LCOV - differential code coverage report
Current view: top level - src/backend/commands - tablecmds.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 91.2 % 6466 5899 271 171 344 12 146 3554 545 1654 390 3643 10 209
Current Date: 2023-04-08 17:13:01 Functions: 98.9 % 189 187 2 173 14 2 178 9
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 92.2 % 472 435 36 1 2 16 410 7 12 13
Legend: Lines: hit not hit (60,120] days: 100.0 % 38 38 6 31 1 1 4
(120,180] days: 98.4 % 64 63 1 29 28 6 1
(180,240] days: 95.8 % 24 23 1 12 9 2 1 4
(240..) days: 91.0 % 5868 5340 3 170 343 12 144 3491 67 1638 376 3621
Function coverage date bins:
[..60] days: 88.9 % 9 8 8 1
(60,120] days: 100.0 % 2 2 2
(120,180] days: 100.0 % 1 1 1
(240..) days: 51.0 % 345 176 2 173 3 2 165

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * tablecmds.c
                                  4                 :  *    Commands for creating and altering table structures and settings
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  *
                                 10                 :  * IDENTIFICATION
                                 11                 :  *    src/backend/commands/tablecmds.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 :  */
                                 15                 : #include "postgres.h"
                                 16                 : 
                                 17                 : #include "access/attmap.h"
                                 18                 : #include "access/genam.h"
                                 19                 : #include "access/heapam.h"
                                 20                 : #include "access/heapam_xlog.h"
                                 21                 : #include "access/multixact.h"
                                 22                 : #include "access/reloptions.h"
                                 23                 : #include "access/relscan.h"
                                 24                 : #include "access/sysattr.h"
                                 25                 : #include "access/tableam.h"
                                 26                 : #include "access/toast_compression.h"
                                 27                 : #include "access/xact.h"
                                 28                 : #include "access/xlog.h"
                                 29                 : #include "access/xloginsert.h"
                                 30                 : #include "catalog/catalog.h"
                                 31                 : #include "catalog/heap.h"
                                 32                 : #include "catalog/index.h"
                                 33                 : #include "catalog/namespace.h"
                                 34                 : #include "catalog/objectaccess.h"
                                 35                 : #include "catalog/partition.h"
                                 36                 : #include "catalog/pg_am.h"
                                 37                 : #include "catalog/pg_attrdef.h"
                                 38                 : #include "catalog/pg_collation.h"
                                 39                 : #include "catalog/pg_constraint.h"
                                 40                 : #include "catalog/pg_depend.h"
                                 41                 : #include "catalog/pg_foreign_table.h"
                                 42                 : #include "catalog/pg_inherits.h"
                                 43                 : #include "catalog/pg_largeobject.h"
                                 44                 : #include "catalog/pg_namespace.h"
                                 45                 : #include "catalog/pg_opclass.h"
                                 46                 : #include "catalog/pg_statistic_ext.h"
                                 47                 : #include "catalog/pg_tablespace.h"
                                 48                 : #include "catalog/pg_trigger.h"
                                 49                 : #include "catalog/pg_type.h"
                                 50                 : #include "catalog/storage.h"
                                 51                 : #include "catalog/storage_xlog.h"
                                 52                 : #include "catalog/toasting.h"
                                 53                 : #include "commands/cluster.h"
                                 54                 : #include "commands/comment.h"
                                 55                 : #include "commands/defrem.h"
                                 56                 : #include "commands/event_trigger.h"
                                 57                 : #include "commands/policy.h"
                                 58                 : #include "commands/sequence.h"
                                 59                 : #include "commands/tablecmds.h"
                                 60                 : #include "commands/tablespace.h"
                                 61                 : #include "commands/trigger.h"
                                 62                 : #include "commands/typecmds.h"
                                 63                 : #include "commands/user.h"
                                 64                 : #include "executor/executor.h"
                                 65                 : #include "foreign/fdwapi.h"
                                 66                 : #include "foreign/foreign.h"
                                 67                 : #include "miscadmin.h"
                                 68                 : #include "nodes/makefuncs.h"
                                 69                 : #include "nodes/nodeFuncs.h"
                                 70                 : #include "nodes/parsenodes.h"
                                 71                 : #include "optimizer/optimizer.h"
                                 72                 : #include "parser/parse_clause.h"
                                 73                 : #include "parser/parse_coerce.h"
                                 74                 : #include "parser/parse_collate.h"
                                 75                 : #include "parser/parse_expr.h"
                                 76                 : #include "parser/parse_oper.h"
                                 77                 : #include "parser/parse_relation.h"
                                 78                 : #include "parser/parse_type.h"
                                 79                 : #include "parser/parse_utilcmd.h"
                                 80                 : #include "parser/parser.h"
                                 81                 : #include "partitioning/partbounds.h"
                                 82                 : #include "partitioning/partdesc.h"
                                 83                 : #include "pgstat.h"
                                 84                 : #include "rewrite/rewriteDefine.h"
                                 85                 : #include "rewrite/rewriteHandler.h"
                                 86                 : #include "rewrite/rewriteManip.h"
                                 87                 : #include "storage/bufmgr.h"
                                 88                 : #include "storage/lmgr.h"
                                 89                 : #include "storage/lock.h"
                                 90                 : #include "storage/predicate.h"
                                 91                 : #include "storage/smgr.h"
                                 92                 : #include "tcop/utility.h"
                                 93                 : #include "utils/acl.h"
                                 94                 : #include "utils/builtins.h"
                                 95                 : #include "utils/fmgroids.h"
                                 96                 : #include "utils/inval.h"
                                 97                 : #include "utils/lsyscache.h"
                                 98                 : #include "utils/memutils.h"
                                 99                 : #include "utils/partcache.h"
                                100                 : #include "utils/relcache.h"
                                101                 : #include "utils/ruleutils.h"
                                102                 : #include "utils/snapmgr.h"
                                103                 : #include "utils/syscache.h"
                                104                 : #include "utils/timestamp.h"
                                105                 : #include "utils/typcache.h"
                                106                 : #include "utils/usercontext.h"
                                107                 : 
                                108                 : /*
                                109                 :  * ON COMMIT action list
                                110                 :  */
                                111                 : typedef struct OnCommitItem
                                112                 : {
                                113                 :     Oid         relid;          /* relid of relation */
                                114                 :     OnCommitAction oncommit;    /* what to do at end of xact */
                                115                 : 
                                116                 :     /*
                                117                 :      * If this entry was created during the current transaction,
                                118                 :      * creating_subid is the ID of the creating subxact; if created in a prior
                                119                 :      * transaction, creating_subid is zero.  If deleted during the current
                                120                 :      * transaction, deleting_subid is the ID of the deleting subxact; if no
                                121                 :      * deletion request is pending, deleting_subid is zero.
                                122                 :      */
                                123                 :     SubTransactionId creating_subid;
                                124                 :     SubTransactionId deleting_subid;
                                125                 : } OnCommitItem;
                                126                 : 
                                127                 : static List *on_commits = NIL;
                                128                 : 
                                129                 : 
                                130                 : /*
                                131                 :  * State information for ALTER TABLE
                                132                 :  *
                                133                 :  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
                                134                 :  * structs, one for each table modified by the operation (the named table
                                135                 :  * plus any child tables that are affected).  We save lists of subcommands
                                136                 :  * to apply to this table (possibly modified by parse transformation steps);
                                137                 :  * these lists will be executed in Phase 2.  If a Phase 3 step is needed,
                                138                 :  * necessary information is stored in the constraints and newvals lists.
                                139                 :  *
                                140                 :  * Phase 2 is divided into multiple passes; subcommands are executed in
                                141                 :  * a pass determined by subcommand type.
                                142                 :  */
                                143                 : 
                                144                 : #define AT_PASS_UNSET           -1  /* UNSET will cause ERROR */
                                145                 : #define AT_PASS_DROP            0   /* DROP (all flavors) */
                                146                 : #define AT_PASS_ALTER_TYPE      1   /* ALTER COLUMN TYPE */
                                147                 : #define AT_PASS_OLD_INDEX       2   /* re-add existing indexes */
                                148                 : #define AT_PASS_OLD_CONSTR      3   /* re-add existing constraints */
                                149                 : /* We could support a RENAME COLUMN pass here, but not currently used */
                                150                 : #define AT_PASS_ADD_COL         4   /* ADD COLUMN */
                                151                 : #define AT_PASS_ADD_CONSTR      5   /* ADD constraints (initial examination) */
                                152                 : #define AT_PASS_COL_ATTRS       6   /* set column attributes, eg NOT NULL */
                                153                 : #define AT_PASS_ADD_INDEXCONSTR 7   /* ADD index-based constraints */
                                154                 : #define AT_PASS_ADD_INDEX       8   /* ADD indexes */
                                155                 : #define AT_PASS_ADD_OTHERCONSTR 9   /* ADD other constraints, defaults */
                                156                 : #define AT_PASS_MISC            10  /* other stuff */
                                157                 : #define AT_NUM_PASSES           11
                                158                 : 
                                159                 : typedef struct AlteredTableInfo
                                160                 : {
                                161                 :     /* Information saved before any work commences: */
                                162                 :     Oid         relid;          /* Relation to work on */
                                163                 :     char        relkind;        /* Its relkind */
                                164                 :     TupleDesc   oldDesc;        /* Pre-modification tuple descriptor */
                                165                 : 
                                166                 :     /*
                                167                 :      * Transiently set during Phase 2, normally set to NULL.
                                168                 :      *
                                169                 :      * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd
                                170                 :      * returns control.  This can be exploited by ATExecCmd subroutines to
                                171                 :      * close/reopen across transaction boundaries.
                                172                 :      */
                                173                 :     Relation    rel;
                                174                 : 
                                175                 :     /* Information saved by Phase 1 for Phase 2: */
                                176                 :     List       *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
                                177                 :     /* Information saved by Phases 1/2 for Phase 3: */
                                178                 :     List       *constraints;    /* List of NewConstraint */
                                179                 :     List       *newvals;        /* List of NewColumnValue */
                                180                 :     List       *afterStmts;     /* List of utility command parsetrees */
                                181                 :     bool        verify_new_notnull; /* T if we should recheck NOT NULL */
                                182                 :     int         rewrite;        /* Reason for forced rewrite, if any */
                                183                 :     Oid         newAccessMethod;    /* new access method; 0 means no change */
                                184                 :     Oid         newTableSpace;  /* new tablespace; 0 means no change */
                                185                 :     bool        chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
                                186                 :     char        newrelpersistence;  /* if above is true */
                                187                 :     Expr       *partition_constraint;   /* for attach partition validation */
                                188                 :     /* true, if validating default due to some other attach/detach */
                                189                 :     bool        validate_default;
                                190                 :     /* Objects to rebuild after completing ALTER TYPE operations */
                                191                 :     List       *changedConstraintOids;  /* OIDs of constraints to rebuild */
                                192                 :     List       *changedConstraintDefs;  /* string definitions of same */
                                193                 :     List       *changedIndexOids;   /* OIDs of indexes to rebuild */
                                194                 :     List       *changedIndexDefs;   /* string definitions of same */
                                195                 :     char       *replicaIdentityIndex;   /* index to reset as REPLICA IDENTITY */
                                196                 :     char       *clusterOnIndex; /* index to use for CLUSTER */
                                197                 :     List       *changedStatisticsOids;  /* OIDs of statistics to rebuild */
                                198                 :     List       *changedStatisticsDefs;  /* string definitions of same */
                                199                 : } AlteredTableInfo;
                                200                 : 
                                201                 : /* Struct describing one new constraint to check in Phase 3 scan */
                                202                 : /* Note: new NOT NULL constraints are handled elsewhere */
                                203                 : typedef struct NewConstraint
                                204                 : {
                                205                 :     char       *name;           /* Constraint name, or NULL if none */
                                206                 :     ConstrType  contype;        /* CHECK, FOREIGN */
                                207                 :     Oid         refrelid;       /* PK rel, if FOREIGN */
                                208                 :     Oid         refindid;       /* OID of PK's index, if FOREIGN */
                                209                 :     Oid         conid;          /* OID of pg_constraint entry, if FOREIGN */
                                210                 :     Node       *qual;           /* Check expr or CONSTR_FOREIGN Constraint */
                                211                 :     ExprState  *qualstate;      /* Execution state for CHECK expr */
                                212                 : } NewConstraint;
                                213                 : 
                                214                 : /*
                                215                 :  * Struct describing one new column value that needs to be computed during
                                216                 :  * Phase 3 copy (this could be either a new column with a non-null default, or
                                217                 :  * a column that we're changing the type of).  Columns without such an entry
                                218                 :  * are just copied from the old table during ATRewriteTable.  Note that the
                                219                 :  * expr is an expression over *old* table values, except when is_generated
                                220                 :  * is true; then it is an expression over columns of the *new* tuple.
                                221                 :  */
                                222                 : typedef struct NewColumnValue
                                223                 : {
                                224                 :     AttrNumber  attnum;         /* which column */
                                225                 :     Expr       *expr;           /* expression to compute */
                                226                 :     ExprState  *exprstate;      /* execution state */
                                227                 :     bool        is_generated;   /* is it a GENERATED expression? */
                                228                 : } NewColumnValue;
                                229                 : 
                                230                 : /*
                                231                 :  * Error-reporting support for RemoveRelations
                                232                 :  */
                                233                 : struct dropmsgstrings
                                234                 : {
                                235                 :     char        kind;
                                236                 :     int         nonexistent_code;
                                237                 :     const char *nonexistent_msg;
                                238                 :     const char *skipping_msg;
                                239                 :     const char *nota_msg;
                                240                 :     const char *drophint_msg;
                                241                 : };
                                242                 : 
                                243                 : static const struct dropmsgstrings dropmsgstringarray[] = {
                                244                 :     {RELKIND_RELATION,
                                245                 :         ERRCODE_UNDEFINED_TABLE,
                                246                 :         gettext_noop("table \"%s\" does not exist"),
                                247                 :         gettext_noop("table \"%s\" does not exist, skipping"),
                                248                 :         gettext_noop("\"%s\" is not a table"),
                                249                 :     gettext_noop("Use DROP TABLE to remove a table.")},
                                250                 :     {RELKIND_SEQUENCE,
                                251                 :         ERRCODE_UNDEFINED_TABLE,
                                252                 :         gettext_noop("sequence \"%s\" does not exist"),
                                253                 :         gettext_noop("sequence \"%s\" does not exist, skipping"),
                                254                 :         gettext_noop("\"%s\" is not a sequence"),
                                255                 :     gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
                                256                 :     {RELKIND_VIEW,
                                257                 :         ERRCODE_UNDEFINED_TABLE,
                                258                 :         gettext_noop("view \"%s\" does not exist"),
                                259                 :         gettext_noop("view \"%s\" does not exist, skipping"),
                                260                 :         gettext_noop("\"%s\" is not a view"),
                                261                 :     gettext_noop("Use DROP VIEW to remove a view.")},
                                262                 :     {RELKIND_MATVIEW,
                                263                 :         ERRCODE_UNDEFINED_TABLE,
                                264                 :         gettext_noop("materialized view \"%s\" does not exist"),
                                265                 :         gettext_noop("materialized view \"%s\" does not exist, skipping"),
                                266                 :         gettext_noop("\"%s\" is not a materialized view"),
                                267                 :     gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
                                268                 :     {RELKIND_INDEX,
                                269                 :         ERRCODE_UNDEFINED_OBJECT,
                                270                 :         gettext_noop("index \"%s\" does not exist"),
                                271                 :         gettext_noop("index \"%s\" does not exist, skipping"),
                                272                 :         gettext_noop("\"%s\" is not an index"),
                                273                 :     gettext_noop("Use DROP INDEX to remove an index.")},
                                274                 :     {RELKIND_COMPOSITE_TYPE,
                                275                 :         ERRCODE_UNDEFINED_OBJECT,
                                276                 :         gettext_noop("type \"%s\" does not exist"),
                                277                 :         gettext_noop("type \"%s\" does not exist, skipping"),
                                278                 :         gettext_noop("\"%s\" is not a type"),
                                279                 :     gettext_noop("Use DROP TYPE to remove a type.")},
                                280                 :     {RELKIND_FOREIGN_TABLE,
                                281                 :         ERRCODE_UNDEFINED_OBJECT,
                                282                 :         gettext_noop("foreign table \"%s\" does not exist"),
                                283                 :         gettext_noop("foreign table \"%s\" does not exist, skipping"),
                                284                 :         gettext_noop("\"%s\" is not a foreign table"),
                                285                 :     gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
                                286                 :     {RELKIND_PARTITIONED_TABLE,
                                287                 :         ERRCODE_UNDEFINED_TABLE,
                                288                 :         gettext_noop("table \"%s\" does not exist"),
                                289                 :         gettext_noop("table \"%s\" does not exist, skipping"),
                                290                 :         gettext_noop("\"%s\" is not a table"),
                                291                 :     gettext_noop("Use DROP TABLE to remove a table.")},
                                292                 :     {RELKIND_PARTITIONED_INDEX,
                                293                 :         ERRCODE_UNDEFINED_OBJECT,
                                294                 :         gettext_noop("index \"%s\" does not exist"),
                                295                 :         gettext_noop("index \"%s\" does not exist, skipping"),
                                296                 :         gettext_noop("\"%s\" is not an index"),
                                297                 :     gettext_noop("Use DROP INDEX to remove an index.")},
                                298                 :     {'\0', 0, NULL, NULL, NULL, NULL}
                                299                 : };
                                300                 : 
                                301                 : /* communication between RemoveRelations and RangeVarCallbackForDropRelation */
                                302                 : struct DropRelationCallbackState
                                303                 : {
                                304                 :     /* These fields are set by RemoveRelations: */
                                305                 :     char        expected_relkind;
                                306                 :     LOCKMODE    heap_lockmode;
                                307                 :     /* These fields are state to track which subsidiary locks are held: */
                                308                 :     Oid         heapOid;
                                309                 :     Oid         partParentOid;
                                310                 :     /* These fields are passed back by RangeVarCallbackForDropRelation: */
                                311                 :     char        actual_relkind;
                                312                 :     char        actual_relpersistence;
                                313                 : };
                                314                 : 
                                315                 : /* Alter table target-type flags for ATSimplePermissions */
                                316                 : #define     ATT_TABLE               0x0001
                                317                 : #define     ATT_VIEW                0x0002
                                318                 : #define     ATT_MATVIEW             0x0004
                                319                 : #define     ATT_INDEX               0x0008
                                320                 : #define     ATT_COMPOSITE_TYPE      0x0010
                                321                 : #define     ATT_FOREIGN_TABLE       0x0020
                                322                 : #define     ATT_PARTITIONED_INDEX   0x0040
                                323                 : #define     ATT_SEQUENCE            0x0080
                                324                 : 
                                325                 : /*
                                326                 :  * ForeignTruncateInfo
                                327                 :  *
                                328                 :  * Information related to truncation of foreign tables.  This is used for
                                329                 :  * the elements in a hash table. It uses the server OID as lookup key,
                                330                 :  * and includes a per-server list of all foreign tables involved in the
                                331                 :  * truncation.
                                332                 :  */
                                333                 : typedef struct ForeignTruncateInfo
                                334                 : {
                                335                 :     Oid         serverid;
                                336                 :     List       *rels;
                                337                 : } ForeignTruncateInfo;
                                338                 : 
                                339                 : /*
                                340                 :  * Partition tables are expected to be dropped when the parent partitioned
                                341                 :  * table gets dropped. Hence for partitioning we use AUTO dependency.
                                342                 :  * Otherwise, for regular inheritance use NORMAL dependency.
                                343                 :  */
                                344                 : #define child_dependency_type(child_is_partition)   \
                                345                 :     ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
                                346                 : 
                                347                 : static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
                                348                 : static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
                                349                 : static void truncate_check_activity(Relation rel);
                                350                 : static void RangeVarCallbackForTruncate(const RangeVar *relation,
                                351                 :                                         Oid relId, Oid oldRelId, void *arg);
                                352                 : static List *MergeAttributes(List *schema, List *supers, char relpersistence,
                                353                 :                              bool is_partition, List **supconstr,
                                354                 :                              List **additional_notnulls);
                                355                 : static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
                                356                 : static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
                                357                 : static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
                                358                 : static void StoreCatalogInheritance(Oid relationId, List *supers,
                                359                 :                                     bool child_is_partition);
                                360                 : static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
                                361                 :                                      int32 seqNumber, Relation inhRelation,
                                362                 :                                      bool child_is_partition);
                                363                 : static int  findAttrByName(const char *attributeName, List *schema);
                                364                 : static void AlterIndexNamespaces(Relation classRel, Relation rel,
                                365                 :                                  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
                                366                 : static void AlterSeqNamespaces(Relation classRel, Relation rel,
                                367                 :                                Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
                                368                 :                                LOCKMODE lockmode);
                                369                 : static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
                                370                 :                                            bool recurse, bool recursing, LOCKMODE lockmode);
                                371                 : static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
                                372                 :                                      Relation rel, HeapTuple contuple, List **otherrelids,
                                373                 :                                      LOCKMODE lockmode);
                                374                 : static ObjectAddress ATExecValidateConstraint(List **wqueue,
                                375                 :                                               Relation rel, char *constrName,
                                376                 :                                               bool recurse, bool recursing, LOCKMODE lockmode);
                                377                 : static int  transformColumnNameList(Oid relId, List *colList,
                                378                 :                                     int16 *attnums, Oid *atttypids);
                                379                 : static int  transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
                                380                 :                                        List **attnamelist,
                                381                 :                                        int16 *attnums, Oid *atttypids,
                                382                 :                                        Oid *opclasses);
                                383                 : static Oid  transformFkeyCheckAttrs(Relation pkrel,
                                384                 :                                     int numattrs, int16 *attnums,
                                385                 :                                     Oid *opclasses);
                                386                 : static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
                                387                 : static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
                                388                 :                                      Oid *funcid);
                                389                 : static void validateForeignKeyConstraint(char *conname,
                                390                 :                                          Relation rel, Relation pkrel,
                                391                 :                                          Oid pkindOid, Oid constraintOid);
                                392                 : static void ATController(AlterTableStmt *parsetree,
                                393                 :                          Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
                                394                 :                          AlterTableUtilityContext *context);
                                395                 : static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
                                396                 :                       bool recurse, bool recursing, LOCKMODE lockmode,
                                397                 :                       AlterTableUtilityContext *context);
                                398                 : static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
                                399                 :                               AlterTableUtilityContext *context);
                                400                 : static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
                                401                 :                       AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass,
                                402                 :                       AlterTableUtilityContext *context);
                                403                 : static AlterTableCmd *ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab,
                                404                 :                                           Relation rel, AlterTableCmd *cmd,
                                405                 :                                           bool recurse, LOCKMODE lockmode,
                                406                 :                                           int cur_pass,
                                407                 :                                           AlterTableUtilityContext *context);
                                408                 : static void ATRewriteTables(AlterTableStmt *parsetree,
                                409                 :                             List **wqueue, LOCKMODE lockmode,
                                410                 :                             AlterTableUtilityContext *context);
                                411                 : static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
                                412                 : static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
                                413                 : static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
                                414                 : static void ATSimpleRecursion(List **wqueue, Relation rel,
                                415                 :                               AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
                                416                 :                               AlterTableUtilityContext *context);
                                417                 : static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
                                418                 : static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
                                419                 :                                   LOCKMODE lockmode,
                                420                 :                                   AlterTableUtilityContext *context);
                                421                 : static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
                                422                 :                                            DropBehavior behavior);
                                423                 : static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                                424                 :                             bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
                                425                 :                             AlterTableUtilityContext *context);
                                426                 : static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
                                427                 :                                      Relation rel, AlterTableCmd **cmd,
                                428                 :                                      bool recurse, bool recursing,
                                429                 :                                      LOCKMODE lockmode, int cur_pass,
                                430                 :                                      AlterTableUtilityContext *context);
                                431                 : static bool check_for_column_name_collision(Relation rel, const char *colname,
                                432                 :                                             bool if_not_exists);
                                433                 : static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
                                434                 : static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
                                435                 : static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
                                436                 :                                        LOCKMODE lockmode);
                                437                 : static void set_attnotnull(List **wqueue, Relation rel,
                                438                 :                            AttrNumber attnum, bool recurse, LOCKMODE lockmode);
                                439                 : static ObjectAddress ATExecSetNotNull(List **wqueue, Relation rel,
                                440                 :                                       char *constrname, char *colName,
                                441                 :                                       bool recurse, bool recursing,
                                442                 :                                       List **readyRels, LOCKMODE lockmode);
                                443                 : static void ATExecSetAttNotNull(List **wqueue, Relation rel,
                                444                 :                                 const char *colName, LOCKMODE lockmode);
                                445                 : static void ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
                                446                 :                                const char *colName, LOCKMODE lockmode);
                                447                 : static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr);
                                448                 : static bool ConstraintImpliedByRelConstraint(Relation scanrel,
                                449                 :                                              List *testConstraint, List *provenConstraint);
                                450                 : static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
                                451                 :                                          Node *newDefault, LOCKMODE lockmode);
                                452                 : static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
                                453                 :                                                Node *newDefault);
                                454                 : static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
                                455                 :                                        Node *def, LOCKMODE lockmode);
                                456                 : static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
                                457                 :                                        Node *def, LOCKMODE lockmode);
                                458                 : static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
                                459                 : static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
                                460                 : static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
                                461                 : static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
                                462                 :                                          Node *newValue, LOCKMODE lockmode);
                                463                 : static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
                                464                 :                                       Node *options, bool isReset, LOCKMODE lockmode);
                                465                 : static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
                                466                 :                                       Node *newValue, LOCKMODE lockmode);
                                467                 : static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                                468                 :                              AlterTableCmd *cmd, LOCKMODE lockmode,
                                469                 :                              AlterTableUtilityContext *context);
                                470                 : static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
                                471                 :                                       DropBehavior behavior,
                                472                 :                                       bool recurse, bool recursing,
                                473                 :                                       bool missing_ok, LOCKMODE lockmode,
                                474                 :                                       ObjectAddresses *addrs);
                                475                 : static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
                                476                 :                                     IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
                                477                 : static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
                                478                 :                                          CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
                                479                 : static ObjectAddress ATExecAddConstraint(List **wqueue,
                                480                 :                                          AlteredTableInfo *tab, Relation rel,
                                481                 :                                          Constraint *newConstraint, bool recurse, bool is_readd,
                                482                 :                                          LOCKMODE lockmode);
                                483                 : static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
                                484                 : static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
                                485                 :                                               IndexStmt *stmt, LOCKMODE lockmode);
                                486                 : static ObjectAddress ATAddCheckConstraint(List **wqueue,
                                487                 :                                           AlteredTableInfo *tab, Relation rel,
                                488                 :                                           Constraint *constr,
                                489                 :                                           bool recurse, bool recursing, bool is_readd,
                                490                 :                                           LOCKMODE lockmode);
                                491                 : static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab,
                                492                 :                                                Relation rel, Constraint *fkconstraint,
                                493                 :                                                bool recurse, bool recursing,
                                494                 :                                                LOCKMODE lockmode);
                                495                 : static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
                                496                 :                                             Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
                                497                 :                                             int numfks, int16 *pkattnum, int16 *fkattnum,
                                498                 :                                             Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
                                499                 :                                             int numfkdelsetcols, int16 *fkdelsetcols,
                                500                 :                                             bool old_check_ok,
                                501                 :                                             Oid parentDelTrigger, Oid parentUpdTrigger);
                                502                 : static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
                                503                 :                                          int numfksetcols, const int16 *fksetcolsattnums,
                                504                 :                                          List *fksetcols);
                                505                 : static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
                                506                 :                                     Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
                                507                 :                                     int numfks, int16 *pkattnum, int16 *fkattnum,
                                508                 :                                     Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
                                509                 :                                     int numfkdelsetcols, int16 *fkdelsetcols,
                                510                 :                                     bool old_check_ok, LOCKMODE lockmode,
                                511                 :                                     Oid parentInsTrigger, Oid parentUpdTrigger);
                                512                 : static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
                                513                 :                                        Relation partitionRel);
                                514                 : static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
                                515                 : static void CloneFkReferencing(List **wqueue, Relation parentRel,
                                516                 :                                Relation partRel);
                                517                 : static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
                                518                 :                                           Constraint *fkconstraint, Oid constraintOid,
                                519                 :                                           Oid indexOid,
                                520                 :                                           Oid parentInsTrigger, Oid parentUpdTrigger,
                                521                 :                                           Oid *insertTrigOid, Oid *updateTrigOid);
                                522                 : static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
                                523                 :                                            Constraint *fkconstraint, Oid constraintOid,
                                524                 :                                            Oid indexOid,
                                525                 :                                            Oid parentDelTrigger, Oid parentUpdTrigger,
                                526                 :                                            Oid *deleteTrigOid, Oid *updateTrigOid);
                                527                 : static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
                                528                 :                                          Oid partRelid,
                                529                 :                                          Oid parentConstrOid, int numfks,
                                530                 :                                          AttrNumber *mapped_conkey, AttrNumber *confkey,
                                531                 :                                          Oid *conpfeqop,
                                532                 :                                          Oid parentInsTrigger,
                                533                 :                                          Oid parentUpdTrigger,
                                534                 :                                          Relation trigrel);
                                535                 : static void GetForeignKeyActionTriggers(Relation trigrel,
                                536                 :                                         Oid conoid, Oid confrelid, Oid conrelid,
                                537                 :                                         Oid *deleteTriggerOid,
                                538                 :                                         Oid *updateTriggerOid);
                                539                 : static void GetForeignKeyCheckTriggers(Relation trigrel,
                                540                 :                                        Oid conoid, Oid confrelid, Oid conrelid,
                                541                 :                                        Oid *insertTriggerOid,
                                542                 :                                        Oid *updateTriggerOid);
                                543                 : static void ATExecDropConstraint(Relation rel, const char *constrName,
                                544                 :                                  DropBehavior behavior,
                                545                 :                                  bool recurse, bool recursing,
                                546                 :                                  bool missing_ok, LOCKMODE lockmode);
                                547                 : static ObjectAddress dropconstraint_internal(Relation rel,
                                548                 :                                              HeapTuple constraintTup, DropBehavior behavior,
                                549                 :                                              bool recurse, bool recursing,
                                550                 :                                              bool missing_ok, List **readyRels,
                                551                 :                                              LOCKMODE lockmode);
                                552                 : static void ATPrepAlterColumnType(List **wqueue,
                                553                 :                                   AlteredTableInfo *tab, Relation rel,
                                554                 :                                   bool recurse, bool recursing,
                                555                 :                                   AlterTableCmd *cmd, LOCKMODE lockmode,
                                556                 :                                   AlterTableUtilityContext *context);
                                557                 : static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
                                558                 : static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                                559                 :                                            AlterTableCmd *cmd, LOCKMODE lockmode);
                                560                 : static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
                                561                 : static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
                                562                 : static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
                                563                 : static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
                                564                 :                                    LOCKMODE lockmode);
                                565                 : static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
                                566                 :                                  char *cmd, List **wqueue, LOCKMODE lockmode,
                                567                 :                                  bool rewrite);
                                568                 : static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
                                569                 :                                      Oid objid, Relation rel, List *domname,
                                570                 :                                      const char *conname);
                                571                 : static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
                                572                 : static void TryReuseForeignKey(Oid oldId, Constraint *con);
                                573                 : static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
                                574                 :                                                      List *options, LOCKMODE lockmode);
                                575                 : static void change_owner_fix_column_acls(Oid relationOid,
                                576                 :                                          Oid oldOwnerId, Oid newOwnerId);
                                577                 : static void change_owner_recurse_to_sequences(Oid relationOid,
                                578                 :                                               Oid newOwnerId, LOCKMODE lockmode);
                                579                 : static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
                                580                 :                                      LOCKMODE lockmode);
                                581                 : static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
                                582                 : static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname);
                                583                 : static bool ATPrepChangePersistence(Relation rel, bool toLogged);
                                584                 : static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
                                585                 :                                 const char *tablespacename, LOCKMODE lockmode);
                                586                 : static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
                                587                 : static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
                                588                 : static void ATExecSetRelOptions(Relation rel, List *defList,
                                589                 :                                 AlterTableType operation,
                                590                 :                                 LOCKMODE lockmode);
                                591                 : static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
                                592                 :                                        char fires_when, bool skip_system, bool recurse,
                                593                 :                                        LOCKMODE lockmode);
                                594                 : static void ATExecEnableDisableRule(Relation rel, const char *rulename,
                                595                 :                                     char fires_when, LOCKMODE lockmode);
                                596                 : static void ATPrepAddInherit(Relation child_rel);
                                597                 : static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
                                598                 : static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
                                599                 : static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
                                600                 :                                    DependencyType deptype);
                                601                 : static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
                                602                 : static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
                                603                 : static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
                                604                 : static void ATExecGenericOptions(Relation rel, List *options);
                                605                 : static void ATExecSetRowSecurity(Relation rel, bool rls);
                                606                 : static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
                                607                 : static ObjectAddress ATExecSetCompression(Relation rel,
                                608                 :                                           const char *column, Node *newValue, LOCKMODE lockmode);
                                609                 : 
                                610                 : static void index_copy_data(Relation rel, RelFileLocator newrlocator);
                                611                 : static const char *storage_name(char c);
                                612                 : 
                                613                 : static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
                                614                 :                                             Oid oldRelOid, void *arg);
                                615                 : static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
                                616                 :                                              Oid oldrelid, void *arg);
                                617                 : static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec);
                                618                 : static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
                                619                 :                                   List **partexprs, Oid *partopclass, Oid *partcollation,
                                620                 :                                   PartitionStrategy strategy);
                                621                 : static void CreateInheritance(Relation child_rel, Relation parent_rel);
                                622                 : static void RemoveInheritance(Relation child_rel, Relation parent_rel,
                                623                 :                               bool expect_detached);
                                624                 : static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
                                625                 :                                            PartitionCmd *cmd,
                                626                 :                                            AlterTableUtilityContext *context);
                                627                 : static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel);
                                628                 : static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
                                629                 :                                                List *partConstraint,
                                630                 :                                                bool validate_default);
                                631                 : static void CloneRowTriggersToPartition(Relation parent, Relation partition);
                                632                 : static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
                                633                 : static void DropClonedTriggersFromPartition(Oid partitionId);
                                634                 : static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab,
                                635                 :                                            Relation rel, RangeVar *name,
                                636                 :                                            bool concurrent);
                                637                 : static void DetachPartitionFinalize(Relation rel, Relation partRel,
                                638                 :                                     bool concurrent, Oid defaultPartOid);
                                639                 : static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name);
                                640                 : static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx,
                                641                 :                                               RangeVar *name);
                                642                 : static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
                                643                 : static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
                                644                 :                                   Relation partitionTbl);
                                645                 : static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partIdx);
                                646                 : static List *GetParentedForeignKeyRefs(Relation partition);
                                647                 : static void ATDetachCheckNoForeignKeyRefs(Relation partition);
                                648                 : static char GetAttributeCompression(Oid atttypid, char *compression);
                                649                 : static char GetAttributeStorage(Oid atttypid, const char *storagemode);
                                650                 : 
                                651                 : 
                                652                 : /* ----------------------------------------------------------------
                                653                 :  *      DefineRelation
                                654                 :  *              Creates a new relation.
                                655                 :  *
                                656                 :  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
                                657                 :  * The other arguments are used to extend the behavior for other cases:
                                658                 :  * relkind: relkind to assign to the new relation
                                659                 :  * ownerId: if not InvalidOid, use this as the new relation's owner.
                                660                 :  * typaddress: if not null, it's set to the pg_type entry's address.
                                661                 :  * queryString: for error reporting
                                662                 :  *
                                663                 :  * Note that permissions checks are done against current user regardless of
                                664                 :  * ownerId.  A nonzero ownerId is used when someone is creating a relation
                                665                 :  * "on behalf of" someone else, so we still want to see that the current user
                                666                 :  * has permissions to do it.
                                667                 :  *
                                668                 :  * If successful, returns the address of the new relation.
                                669                 :  * ----------------------------------------------------------------
                                670                 :  */
                                671                 : ObjectAddress
 2959 alvherre                  672 GIC       62952 : DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
                                673                 :                ObjectAddress *typaddress, const char *queryString)
                                674                 : {
                                675                 :     char        relname[NAMEDATALEN];
                                676                 :     Oid         namespaceId;
                                677                 :     Oid         relationId;
                                678                 :     Oid         tablespaceId;
                                679                 :     Relation    rel;
                                680                 :     TupleDesc   descriptor;
                                681                 :     List       *inheritOids;
                                682                 :     List       *old_constraints;
                                683                 :     List       *old_notnulls;
                                684                 :     List       *rawDefaults;
 5448 tgl                       685 ECB             :     List       *cookedDefaults;
                                686                 :     List       *nncols;
                                687                 :     Datum       reloptions;
                                688                 :     ListCell   *listptr;
                                689                 :     AttrNumber  attnum;
                                690                 :     bool        partitioned;
                                691                 :     static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
                                692                 :     Oid         ofTypeId;
                                693                 :     ObjectAddress address;
                                694                 :     LOCKMODE    parentLockmode;
 1495 andres                    695 GIC       62952 :     const char *accessMethod = NULL;
                                696           62952 :     Oid         accessMethodId = InvalidOid;
                                697                 : 
                                698                 :     /*
                                699                 :      * Truncate relname to appropriate length (probably a waste of time, as
                                700                 :      * parser should have done this already).
                                701                 :      */
  972 peter                     702           62952 :     strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
                                703                 : 
                                704                 :     /*
                                705                 :      * Check consistency of arguments
                                706                 :      */
 4382 bruce                     707           62952 :     if (stmt->oncommit != ONCOMMIT_NOOP
 4500 rhaas                     708              86 :         && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
 7203 tgl                       709 CBC           6 :         ereport(ERROR,
 7203 tgl                       710 ECB             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                                711                 :                  errmsg("ON COMMIT can only be used on temporary tables")));
                                712                 : 
 2314 rhaas                     713 GIC       62946 :     if (stmt->partspec != NULL)
                                714                 :     {
                                715            2178 :         if (relkind != RELKIND_RELATION)
 2314 rhaas                     716 LBC           0 :             elog(ERROR, "unexpected relkind: %d", (int) relkind);
                                717                 : 
 2314 rhaas                     718 GIC        2178 :         relkind = RELKIND_PARTITIONED_TABLE;
 1445 alvherre                  719            2178 :         partitioned = true;
                                720                 :     }
 1445 alvherre                  721 ECB             :     else
 1445 alvherre                  722 CBC       60768 :         partitioned = false;
 2314 rhaas                     723 ECB             : 
                                724                 :     /*
                                725                 :      * Look up the namespace in which we are supposed to create the relation,
                                726                 :      * check we have permission to create there, lock it against concurrent
 4101                           727                 :      * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
                                728                 :      * namespace is selected.
 4298                           729                 :      */
 4101 rhaas                     730 EUB             :     namespaceId =
 4101 rhaas                     731 GIC       62946 :         RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
 4298 rhaas                     732 ECB             : 
 4869 tgl                       733                 :     /*
                                734                 :      * Security check: disallow creating temp tables from security-restricted
                                735                 :      * code.  This is needed because calling code might not expect untrusted
                                736                 :      * tables to appear in pg_temp at the front of its search path.
                                737                 :      */
 4500 rhaas                     738 GIC       62946 :     if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
                                739            1439 :         && InSecurityRestrictedOperation())
 4869 tgl                       740 UIC           0 :         ereport(ERROR,
                                741                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                742                 :                  errmsg("cannot create temporary table within security-restricted operation")));
                                743                 : 
                                744                 :     /*
 1574 alvherre                  745 ECB             :      * Determine the lockmode to use when scanning parents.  A self-exclusive
                                746                 :      * lock is needed here.
                                747                 :      *
                                748                 :      * For regular inheritance, if two backends attempt to add children to the
                                749                 :      * same parent simultaneously, and that parent has no pre-existing
                                750                 :      * children, then both will attempt to update the parent's relhassubclass
                                751                 :      * field, leading to a "tuple concurrently updated" error.  Also, this
                                752                 :      * interlocks against a concurrent ANALYZE on the parent table, which
                                753                 :      * might otherwise be attempting to clear the parent's relhassubclass
 1574 alvherre                  754 EUB             :      * field, if its previous children were recently dropped.
                                755                 :      *
                                756                 :      * If the child table is a partition, then we instead grab an exclusive
                                757                 :      * lock on the parent because its partition descriptor will be changed by
                                758                 :      * addition of the new partition.
                                759                 :      */
 1574 alvherre                  760 GIC       62946 :     parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
                                761                 :                       ShareUpdateExclusiveLock);
                                762                 : 
                                763                 :     /* Determine the list of OIDs of the parents. */
                                764           62946 :     inheritOids = NIL;
                                765           67430 :     foreach(listptr, stmt->inhRelations)
                                766                 :     {
                                767            4484 :         RangeVar   *rv = (RangeVar *) lfirst(listptr);
                                768                 :         Oid         parentOid;
                                769                 : 
                                770            4484 :         parentOid = RangeVarGetRelid(rv, parentLockmode, false);
                                771                 : 
                                772                 :         /*
                                773                 :          * Reject duplications in the list of parents.
 1574 alvherre                  774 ECB             :          */
 1574 alvherre                  775 GIC        4484 :         if (list_member_oid(inheritOids, parentOid))
 1574 alvherre                  776 UIC           0 :             ereport(ERROR,
                                777                 :                     (errcode(ERRCODE_DUPLICATE_TABLE),
 1574 alvherre                  778 ECB             :                      errmsg("relation \"%s\" would be inherited from more than once",
                                779                 :                             get_rel_name(parentOid))));
                                780                 : 
 1574 alvherre                  781 CBC        4484 :         inheritOids = lappend_oid(inheritOids, parentOid);
                                782                 :     }
                                783                 : 
 6869 tgl                       784 ECB             :     /*
                                785                 :      * Select tablespace to use: an explicitly indicated one, or (in the case
                                786                 :      * of a partitioned table) the parent's, if it has one.
                                787                 :      */
 6869 tgl                       788 GIC       62946 :     if (stmt->tablespacename)
 6869 tgl                       789 ECB             :     {
 4630 rhaas                     790 GBC          52 :         tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
                                791                 : 
 1445 alvherre                  792 GIC          49 :         if (partitioned && tablespaceId == MyDatabaseTableSpace)
                                793               3 :             ereport(ERROR,
                                794                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 1445 alvherre                  795 ECB             :                      errmsg("cannot specify default tablespace for partitioned relations")));
                                796                 :     }
 1574 alvherre                  797 GIC       62894 :     else if (stmt->partbound)
                                798                 :     {
                                799                 :         /*
                                800                 :          * For partitions, when no other tablespace is specified, we default
                                801                 :          * the tablespace to the parent partitioned table's.
 1574 alvherre                  802 ECB             :          */
 1574 alvherre                  803 GIC        3608 :         Assert(list_length(inheritOids) == 1);
 1445 alvherre                  804 CBC        3608 :         tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
                                805                 :     }
 6729 tgl                       806 ECB             :     else
 1402 alvherre                  807 CBC       59286 :         tablespaceId = InvalidOid;
                                808                 : 
                                809                 :     /* still nothing? use the default */
 1402 alvherre                  810 GIC       62940 :     if (!OidIsValid(tablespaceId))
 1445 alvherre                  811 CBC       62883 :         tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
                                812                 :                                             partitioned);
                                813                 : 
                                814                 :     /* Check permissions except when using database's default */
 5540 tgl                       815 GIC       62937 :     if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
                                816                 :     {
 6729 tgl                       817 ECB             :         AclResult   aclresult;
                                818                 : 
  147 peter                     819 GNC          66 :         aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
                                820                 :                                            ACL_CREATE);
 6869 tgl                       821 CBC          66 :         if (aclresult != ACLCHECK_OK)
 1954 peter_e                   822 GIC           3 :             aclcheck_error(aclresult, OBJECT_TABLESPACE,
 6729 tgl                       823               3 :                            get_tablespace_name(tablespaceId));
 6869 tgl                       824 ECB             :     }
                                825                 : 
                                826                 :     /* In all cases disallow placing user relations in pg_global */
 4809 tgl                       827 GIC       62934 :     if (tablespaceId == GLOBALTABLESPACE_OID)
                                828               9 :         ereport(ERROR,
 4809 tgl                       829 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                830                 :                  errmsg("only shared relations can be placed in pg_global tablespace")));
                                831                 : 
                                832                 :     /* Identify user ID that will own the table */
 4617 tgl                       833 CBC       62925 :     if (!OidIsValid(ownerId))
 4617 tgl                       834 GIC       62843 :         ownerId = GetUserId();
 4617 tgl                       835 ECB             : 
 5789                           836                 :     /*
                                837                 :      * Parse and validate reloptions, if any.
                                838                 :      */
 5179 alvherre                  839 GIC       62925 :     reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
                                840                 :                                      true, false);
 5789 tgl                       841 ECB             : 
 1242 michael                   842 CBC       62916 :     switch (relkind)
                                843                 :     {
 1242 michael                   844 GIC       43940 :         case RELKIND_VIEW:
                                845           43940 :             (void) view_reloptions(reloptions, true);
                                846           43931 :             break;
 1242 michael                   847 CBC        2169 :         case RELKIND_PARTITIONED_TABLE:
                                848            2169 :             (void) partitioned_table_reloptions(reloptions, true);
 1242 michael                   849 GIC        2166 :             break;
                                850           16807 :         default:
                                851           16807 :             (void) heap_reloptions(relkind, reloptions, true);
                                852                 :     }
 5789 tgl                       853 ECB             : 
 4819 peter_e                   854 GIC       62856 :     if (stmt->ofTypename)
                                855                 :     {
 4128 peter_e                   856 ECB             :         AclResult   aclresult;
                                857                 : 
 4549 peter_e                   858 CBC          43 :         ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
 4128 peter_e                   859 ECB             : 
  147 peter                     860 GNC          43 :         aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
 4128 peter_e                   861 CBC          43 :         if (aclresult != ACLCHECK_OK)
 3950                           862               3 :             aclcheck_error_type(aclresult, ofTypeId);
 4128 peter_e                   863 ECB             :     }
 4819                           864                 :     else
 4819 peter_e                   865 CBC       62813 :         ofTypeId = InvalidOid;
                                866                 : 
                                867                 :     /*
 6385 bruce                     868 ECB             :      * Look up inheritance ancestors and generate relation schema, including
                                869                 :      * inherited attributes.  (Note that stmt->tableElts is destructively
                                870                 :      * modified by MergeAttributes.)
                                871                 :      */
 2151 rhaas                     872 CBC       62769 :     stmt->tableElts =
 1574 alvherre                  873 GIC       62853 :         MergeAttributes(stmt->tableElts, inheritOids,
 2151 rhaas                     874 CBC       62853 :                         stmt->relation->relpersistence,
                                875           62853 :                         stmt->partbound != NULL,
                                876                 :                         &old_constraints, &old_notnulls);
                                877                 : 
                                878                 :     /*
 3260 bruce                     879 ECB             :      * Create a tuple descriptor from the relation schema.  Note that this
                                880                 :      * deals with column names, types, and in-descriptor NOT NULL flags, but
                                881                 :      * not default values, NOT NULL or CHECK constraints; we handle those
                                882                 :      * below.
                                883                 :      */
 2151 rhaas                     884 GIC       62769 :     descriptor = BuildDescForRelation(stmt->tableElts);
                                885                 : 
                                886                 :     /*
 5448 tgl                       887 ECB             :      * Find columns with default values and prepare for insertion of the
                                888                 :      * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
                                889                 :      * CookedConstraint structs that we'll pass to heap_create_with_catalog,
 5050 bruce                     890                 :      * while raw defaults go into a list of RawColumnDefault structs that will
                                891                 :      * be processed by AddRelationNewConstraints.  (We can't deal with raw
                                892                 :      * expressions until we can do transformExpr.)
                                893                 :      *
                                894                 :      * We can set the atthasdef flags now in the tuple descriptor; this just
                                895                 :      * saves StoreAttrDefault from having to do an immediate update of the
                                896                 :      * pg_attribute rows.
                                897                 :      */
 5448 tgl                       898 GIC       62757 :     rawDefaults = NIL;
 5448 tgl                       899 CBC       62757 :     cookedDefaults = NIL;
 5448 tgl                       900 GIC       62757 :     attnum = 0;
                                901                 : 
 2151 rhaas                     902          549553 :     foreach(listptr, stmt->tableElts)
                                903                 :     {
 5448 tgl                       904          486805 :         ColumnDef  *colDef = lfirst(listptr);
                                905                 :         Form_pg_attribute attr;
                                906                 : 
                                907          486805 :         attnum++;
 2058 andres                    908          486805 :         attr = TupleDescAttr(descriptor, attnum - 1);
                                909                 : 
 5448 tgl                       910          486805 :         if (colDef->raw_default != NULL)
                                911                 :         {
                                912                 :             RawColumnDefault *rawEnt;
 6797 bruce                     913 ECB             : 
 5448 tgl                       914 CBC        1126 :             Assert(colDef->cooked_default == NULL);
 5448 tgl                       915 ECB             : 
 5448 tgl                       916 GIC        1126 :             rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
 5448 tgl                       917 CBC        1126 :             rawEnt->attnum = attnum;
 5448 tgl                       918 GIC        1126 :             rawEnt->raw_default = colDef->raw_default;
 1838 andrew                    919 CBC        1126 :             rawEnt->missingMode = false;
 1471 peter                     920 GIC        1126 :             rawEnt->generated = colDef->generated;
 5448 tgl                       921            1126 :             rawDefaults = lappend(rawDefaults, rawEnt);
 2058 andres                    922 CBC        1126 :             attr->atthasdef = true;
 7653 tgl                       923 ECB             :         }
 5448 tgl                       924 GIC      485679 :         else if (colDef->cooked_default != NULL)
 7653 tgl                       925 ECB             :         {
                                926                 :             CookedConstraint *cooked;
                                927                 : 
 5448 tgl                       928 GIC         160 :             cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
 5448 tgl                       929 CBC         160 :             cooked->contype = CONSTR_DEFAULT;
 2118 tgl                       930 GIC         160 :             cooked->conoid = InvalidOid; /* until created */
 5448 tgl                       931 CBC         160 :             cooked->name = NULL;
                                932             160 :             cooked->attnum = attnum;
 4933                           933             160 :             cooked->expr = colDef->cooked_default;
 4330 alvherre                  934             160 :             cooked->skip_validation = false;
 5448 tgl                       935             160 :             cooked->is_local = true; /* not used for defaults */
 2118                           936             160 :             cooked->inhcount = 0;    /* ditto */
 4006 alvherre                  937             160 :             cooked->is_no_inherit = false;
 5448 tgl                       938 GIC         160 :             cookedDefaults = lappend(cookedDefaults, cooked);
 2058 andres                    939 CBC         160 :             attr->atthasdef = true;
                                940                 :         }
                                941                 : 
 2194 peter_e                   942 GIC      486805 :         if (colDef->identity)
 2058 andres                    943 CBC          66 :             attr->attidentity = colDef->identity;
 1471 peter                     944 ECB             : 
 1471 peter                     945 CBC      486805 :         if (colDef->generated)
                                946             445 :             attr->attgenerated = colDef->generated;
  751 rhaas                     947 ECB             : 
  682 tgl                       948 CBC      486805 :         if (colDef->compression)
                                949              41 :             attr->attcompression = GetAttributeCompression(attr->atttypid,
  682 tgl                       950 ECB             :                                                            colDef->compression);
                                951                 : 
  270 peter                     952 GNC      486799 :         if (colDef->storage_name)
                                953               6 :             attr->attstorage = GetAttributeStorage(attr->atttypid, colDef->storage_name);
 9345 bruce                     954 ECB             :     }
                                955                 : 
 1495 andres                    956                 :     /*
                                957                 :      * If the statement hasn't specified an access method, but we're defining
                                958                 :      * a type of relation that needs one, use the default.
                                959                 :      */
 1495 andres                    960 CBC       62748 :     if (stmt->accessMethod != NULL)
 1495 andres                    961 ECB             :     {
 1495 andres                    962 GIC          57 :         accessMethod = stmt->accessMethod;
 1495 andres                    963 ECB             : 
 1445 alvherre                  964 CBC          57 :         if (partitioned)
 1495 andres                    965 GIC           3 :             ereport(ERROR,
 1495 andres                    966 ECB             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                967                 :                      errmsg("specifying a table access method is not supported on a partitioned table")));
                                968                 :     }
  492 peter                     969 GIC       62691 :     else if (RELKIND_HAS_TABLE_AM(relkind))
 1495 andres                    970 CBC       15335 :         accessMethod = default_table_access_method;
 1495 andres                    971 ECB             : 
                                972                 :     /* look up the access method, verify it is for a table */
 1495 andres                    973 GIC       62745 :     if (accessMethod != NULL)
 1466                           974           15389 :         accessMethodId = get_table_am_oid(accessMethod, false);
                                975                 : 
                                976                 :     /*
                                977                 :      * Create the relation.  Inherited defaults and constraints are passed in
 5050 bruce                     978 ECB             :      * for immediate handling --- since they don't need parsing, they can be
                                979                 :      * stored immediately.
 5448 tgl                       980                 :      */
 7653 tgl                       981 GIC       62736 :     relationId = heap_create_with_catalog(relname,
 7653 tgl                       982 ECB             :                                           namespaceId,
 6869                           983                 :                                           tablespaceId,
                                984                 :                                           InvalidOid,
                                985                 :                                           InvalidOid,
                                986                 :                                           ofTypeId,
 4617                           987                 :                                           ownerId,
 1495 andres                    988                 :                                           accessMethodId,
                                989                 :                                           descriptor,
                                990                 :                                           list_concat(cookedDefaults,
 5448 tgl                       991                 :                                                       old_constraints),
 7653                           992                 :                                           relkind,
 4500 rhaas                     993 GIC       62736 :                                           stmt->relation->relpersistence,
                                994                 :                                           false,
                                995                 :                                           false,
                                996                 :                                           stmt->oncommit,
                                997                 :                                           reloptions,
                                998                 :                                           true,
 3820 alvherre                  999 ECB             :                                           allowSystemTableMods,
                               1000                 :                                           false,
                               1001                 :                                           InvalidOid,
                               1002                 :                                           typaddress);
                               1003                 : 
                               1004                 :     /*
                               1005                 :      * We must bump the command counter to make the newly-created relation
                               1006                 :      * tuple visible for opening.
                               1007                 :      */
 7653 tgl                      1008 GIC       62724 :     CommandCounterIncrement();
                               1009                 : 
                               1010                 :     /*
 3260 bruce                    1011 ECB             :      * Open the new relation and acquire exclusive lock on it.  This isn't
                               1012                 :      * really necessary for locking out other backends (since they can't see
                               1013                 :      * the new rel anyway until we commit), but it keeps the lock manager from
                               1014                 :      * complaining about deadlock risks.
                               1015                 :      */
 7528 tgl                      1016 GIC       62724 :     rel = relation_open(relationId, AccessExclusiveLock);
                               1017                 : 
                               1018                 :     /*
                               1019                 :      * Now add any newly specified column default and generation expressions
                               1020                 :      * to the new relation.  These are passed to us in the form of raw
                               1021                 :      * parsetrees; we need to transform them to executable expression trees
                               1022                 :      * before they can be added. The most convenient way to do that is to
                               1023                 :      * apply the parser's transformExpr routine, but transformExpr doesn't
                               1024                 :      * work unless we have a pre-existing relation. So, the transformation has
                               1025                 :      * to be postponed to this final step of CREATE TABLE.
 1471 peter                    1026 ECB             :      *
                               1027                 :      * This needs to be before processing the partitioning clauses because
                               1028                 :      * those could refer to generated columns.
                               1029                 :      */
 1471 peter                    1030 GIC       62724 :     if (rawDefaults)
                               1031             950 :         AddRelationNewConstraints(rel, rawDefaults, NIL,
                               1032                 :                                   true, true, false, queryString);
                               1033                 : 
 1471 peter                    1034 ECB             :     /*
                               1035                 :      * Make column generation expressions visible for use by partitioning.
                               1036                 :      */
 1471 peter                    1037 GIC       62673 :     CommandCounterIncrement();
                               1038                 : 
                               1039                 :     /* Process and store partition bound, if any. */
 2314 rhaas                    1040           62673 :     if (stmt->partbound)
                               1041                 :     {
                               1042                 :         PartitionBoundSpec *bound;
                               1043                 :         ParseState *pstate;
 2039                          1044            3581 :         Oid         parentId = linitial_oid(inheritOids),
                               1045                 :                     defaultPartOid;
                               1046                 :         Relation    parent,
                               1047            3581 :                     defaultRel = NULL;
 1193 tgl                      1048 ECB             :         ParseNamespaceItem *nsitem;
 2314 rhaas                    1049                 : 
                               1050                 :         /* Already have strong enough lock on the parent */
 1539 andres                   1051 GIC        3581 :         parent = table_open(parentId, NoLock);
                               1052                 : 
                               1053                 :         /*
                               1054                 :          * We are going to try to validate the partition bound specification
 2314 rhaas                    1055 ECB             :          * against the partition key of parentRel, so it better have one.
                               1056                 :          */
 2314 rhaas                    1057 GIC        3581 :         if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 2314 rhaas                    1058 CBC           6 :             ereport(ERROR,
                               1059                 :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                               1060                 :                      errmsg("\"%s\" is not partitioned",
                               1061                 :                             RelationGetRelationName(parent))));
 2314 rhaas                    1062 ECB             : 
                               1063                 :         /*
                               1064                 :          * The partition constraint of the default partition depends on the
 2039                          1065                 :          * partition bounds of every other partition. It is possible that
                               1066                 :          * another backend might be about to execute a query on the default
                               1067                 :          * partition table, and that the query relies on previously cached
                               1068                 :          * default partition constraints. We must therefore take a table lock
                               1069                 :          * strong enough to prevent all queries on the default partition from
                               1070                 :          * proceeding until we commit and send out a shared-cache-inval notice
                               1071                 :          * that will make them update their index lists.
                               1072                 :          *
                               1073                 :          * Order of locking: The relation being added won't be visible to
                               1074                 :          * other backends until it is committed, hence here in
                               1075                 :          * DefineRelation() the order of locking the default partition and the
                               1076                 :          * relation being added does not matter. But at all other places we
                               1077                 :          * need to lock the default relation before we lock the relation being
                               1078                 :          * added or removed i.e. we should take the lock in same order at all
                               1079                 :          * the places such that lock parent, lock default partition and then
                               1080                 :          * lock the partition so as to avoid a deadlock.
                               1081                 :          */
                               1082                 :         defaultPartOid =
  745 alvherre                 1083 GIC        3575 :             get_default_oid_from_partdesc(RelationGetPartitionDesc(parent,
                               1084                 :                                                                    true));
 2039 rhaas                    1085            3575 :         if (OidIsValid(defaultPartOid))
 1539 andres                   1086             177 :             defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
                               1087                 : 
                               1088                 :         /* Transform the bound values */
 2314 rhaas                    1089            3575 :         pstate = make_parsestate(NULL);
                               1090            3575 :         pstate->p_sourcetext = queryString;
                               1091                 : 
                               1092                 :         /*
                               1093                 :          * Add an nsitem containing this relation, so that transformExpr
                               1094                 :          * called on partition bound expressions is able to report errors
                               1095                 :          * using a proper context.
                               1096                 :          */
 1193 tgl                      1097            3575 :         nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
                               1098                 :                                                NULL, false, false);
                               1099            3575 :         addNSItemToQuery(pstate, nsitem, false, true, true);
                               1100                 : 
 2314 rhaas                    1101 CBC        3575 :         bound = transformPartitionBound(pstate, parent, stmt->partbound);
                               1102                 : 
 2314 rhaas                    1103 ECB             :         /*
                               1104                 :          * Check first that the new partition's bound is valid and does not
                               1105                 :          * overlap with any of existing partitions of the parent.
                               1106                 :          */
  928 tgl                      1107 CBC        3473 :         check_new_partition_bound(relname, parent, bound, pstate);
 2314 rhaas                    1108 ECB             : 
                               1109                 :         /*
                               1110                 :          * If the default partition exists, its partition constraints will
                               1111                 :          * change after the addition of this new partition such that it won't
                               1112                 :          * allow any row that qualifies for this new partition. So, check that
                               1113                 :          * the existing data in the default partition satisfies the constraint
                               1114                 :          * as it will exist after adding this partition.
 2039                          1115                 :          */
 2039 rhaas                    1116 GIC        3416 :         if (OidIsValid(defaultPartOid))
 2039 rhaas                    1117 ECB             :         {
 1761 tgl                      1118 GIC         162 :             check_default_partition_contents(parent, defaultRel, bound);
 2039 rhaas                    1119 ECB             :             /* Keep the lock until commit. */
 1539 andres                   1120 GIC         153 :             table_close(defaultRel, NoLock);
                               1121                 :         }
                               1122                 : 
                               1123                 :         /* Update the pg_class entry. */
 2302 rhaas                    1124            3407 :         StorePartitionBound(rel, parent, bound);
 2302 rhaas                    1125 ECB             : 
 1539 andres                   1126 GIC        3407 :         table_close(parent, NoLock);
                               1127                 :     }
                               1128                 : 
                               1129                 :     /* Store inheritance information for new rel. */
 1677 alvherre                 1130           62499 :     StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
                               1131                 : 
                               1132                 :     /*
                               1133                 :      * Process the partitioning specification (if any) and store the partition
 2308 rhaas                    1134 ECB             :      * key information into the catalog.
                               1135                 :      */
 1445 alvherre                 1136 CBC       62499 :     if (partitioned)
                               1137                 :     {
 1691 peter_e                  1138 ECB             :         ParseState *pstate;
                               1139                 :         int         partnatts;
                               1140                 :         AttrNumber  partattrs[PARTITION_MAX_KEYS];
 2308 rhaas                    1141                 :         Oid         partopclass[PARTITION_MAX_KEYS];
                               1142                 :         Oid         partcollation[PARTITION_MAX_KEYS];
 2308 rhaas                    1143 CBC        2163 :         List       *partexprs = NIL;
                               1144                 : 
 1691 peter_e                  1145 GIC        2163 :         pstate = make_parsestate(NULL);
                               1146            2163 :         pstate->p_sourcetext = queryString;
 1691 peter_e                  1147 ECB             : 
 2142 tgl                      1148 GIC        2163 :         partnatts = list_length(stmt->partspec->partParams);
                               1149                 : 
                               1150                 :         /* Protect fixed-size arrays here and in executor */
                               1151            2163 :         if (partnatts > PARTITION_MAX_KEYS)
 2142 tgl                      1152 UIC           0 :             ereport(ERROR,
 2142 tgl                      1153 ECB             :                     (errcode(ERRCODE_TOO_MANY_COLUMNS),
                               1154                 :                      errmsg("cannot partition using more than %d columns",
                               1155                 :                             PARTITION_MAX_KEYS)));
                               1156                 : 
                               1157                 :         /*
                               1158                 :          * We need to transform the raw parsetrees corresponding to partition
                               1159                 :          * expressions into executable expression trees.  Like column defaults
 2314 rhaas                    1160                 :          * and CHECK constraints, we could not have done the transformation
                               1161                 :          * earlier.
                               1162                 :          */
  157 alvherre                 1163 GNC        2163 :         stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
 2142 tgl                      1164 ECB             : 
 1691 peter_e                  1165 GIC        2148 :         ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
                               1166                 :                               partattrs, &partexprs, partopclass,
  157 alvherre                 1167 GNC        2148 :                               partcollation, stmt->partspec->strategy);
 2314 rhaas                    1168 EUB             : 
  157 alvherre                 1169 GNC        2106 :         StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
                               1170                 :                           partexprs,
                               1171                 :                           partopclass, partcollation);
                               1172                 : 
                               1173                 :         /* make it all visible */
 1906 alvherre                 1174 GIC        2106 :         CommandCounterIncrement();
                               1175                 :     }
                               1176                 : 
                               1177                 :     /*
                               1178                 :      * If we're creating a partition, create now all the indexes, triggers,
                               1179                 :      * FKs defined in the parent.
 1843 alvherre                 1180 ECB             :      *
                               1181                 :      * We can't do it earlier, because DefineIndex wants to know the partition
                               1182                 :      * key which we just stored.
                               1183                 :      */
 1906 alvherre                 1184 CBC       62442 :     if (stmt->partbound)
                               1185                 :     {
                               1186            3404 :         Oid         parentId = linitial_oid(inheritOids);
                               1187                 :         Relation    parent;
                               1188                 :         List       *idxlist;
                               1189                 :         ListCell   *cell;
                               1190                 : 
 1906 alvherre                 1191 ECB             :         /* Already have strong enough lock on the parent */
 1539 andres                   1192 GIC        3404 :         parent = table_open(parentId, NoLock);
 1906 alvherre                 1193            3404 :         idxlist = RelationGetIndexList(parent);
                               1194                 : 
                               1195                 :         /*
                               1196                 :          * For each index in the parent table, create one in the partition
                               1197                 :          */
                               1198            4006 :         foreach(cell, idxlist)
                               1199                 :         {
                               1200             611 :             Relation    idxRel = index_open(lfirst_oid(cell), AccessShareLock);
 1208 michael                  1201 ECB             :             AttrMap    *attmap;
                               1202                 :             IndexStmt  *idxstmt;
 1875 alvherre                 1203                 :             Oid         constraintOid;
                               1204                 : 
 1383 alvherre                 1205 GIC         611 :             if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
                               1206                 :             {
                               1207              18 :                 if (idxRel->rd_index->indisunique)
                               1208               6 :                     ereport(ERROR,
 1383 alvherre                 1209 ECB             :                             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               1210                 :                              errmsg("cannot create foreign partition of partitioned table \"%s\"",
                               1211                 :                                     RelationGetRelationName(parent)),
                               1212                 :                              errdetail("Table \"%s\" contains indexes that are unique.",
                               1213                 :                                        RelationGetRelationName(parent))));
                               1214                 :                 else
                               1215                 :                 {
 1383 alvherre                 1216 GIC          12 :                     index_close(idxRel, AccessShareLock);
 1383 alvherre                 1217 CBC          12 :                     continue;
                               1218                 :                 }
                               1219                 :             }
                               1220                 : 
 1208 michael                  1221 GIC         593 :             attmap = build_attrmap_by_name(RelationGetDescr(rel),
                               1222                 :                                            RelationGetDescr(parent),
                               1223                 :                                            false);
                               1224                 :             idxstmt =
 1447 tgl                      1225 CBC         593 :                 generateClonedIndexStmt(NULL, idxRel,
 1208 michael                  1226 ECB             :                                         attmap, &constraintOid);
 1906 alvherre                 1227 GIC         593 :             DefineIndex(RelationGetRelid(rel),
                               1228                 :                         idxstmt,
                               1229                 :                         InvalidOid,
                               1230                 :                         RelationGetRelid(idxRel),
                               1231                 :                         constraintOid,
                               1232                 :                         -1,
                               1233                 :                         false, false, false, false, false);
                               1234                 : 
 1906 alvherre                 1235 CBC         590 :             index_close(idxRel, AccessShareLock);
 1906 alvherre                 1236 ECB             :         }
                               1237                 : 
 1906 alvherre                 1238 GIC        3395 :         list_free(idxlist);
                               1239                 : 
 1843 alvherre                 1240 ECB             :         /*
                               1241                 :          * If there are any row-level triggers, clone them to the new
                               1242                 :          * partition.
                               1243                 :          */
 1843 alvherre                 1244 CBC        3395 :         if (parent->trigdesc != NULL)
 1843 alvherre                 1245 GIC         188 :             CloneRowTriggersToPartition(parent, rel);
 1843 alvherre                 1246 ECB             : 
                               1247                 :         /*
                               1248                 :          * And foreign keys too.  Note that because we're freshly creating the
                               1249                 :          * table, there is no need to verify these new constraints.
                               1250                 :          */
 1467 alvherre                 1251 GIC        3395 :         CloneForeignKeyConstraints(NULL, parent, rel);
                               1252                 : 
 1539 andres                   1253            3395 :         table_close(parent, NoLock);
 2314 rhaas                    1254 ECB             :     }
                               1255                 : 
                               1256                 :     /*
 1418 tgl                      1257                 :      * Now add any newly specified CHECK constraints to the new relation. Same
                               1258                 :      * as for defaults above, but these need to come after partitioning is set
                               1259                 :      * up.
                               1260                 :      */
 1471 peter                    1261 GIC       62433 :     if (stmt->constraints)
                               1262             281 :         AddRelationNewConstraints(rel, NIL, stmt->constraints,
 1691 peter_e                  1263 ECB             :                                   true, true, false, queryString);
 8313 JanWieck                 1264                 : 
                               1265                 :     /*
                               1266                 :      * Finally, merge the NOT NULL constraints that are directly declared with
                               1267                 :      * those that come from parent relations (making sure to count inheritance
                               1268                 :      * appropriately for each), create them, and set the attnotnull flag on
                               1269                 :      * columns that don't yet have it.
                               1270                 :      */
    2 alvherre                 1271 GNC       62424 :     nncols = AddRelationNotNullConstraints(rel, stmt->nnconstraints,
                               1272                 :                                            old_notnulls);
                               1273           65677 :     foreach(listptr, nncols)
                               1274            3253 :         set_attnotnull(NULL, rel, lfirst_int(listptr), false, NoLock);
                               1275                 : 
 2959 alvherre                 1276 GIC       62424 :     ObjectAddressSet(address, RelationRelationId, relationId);
                               1277                 : 
                               1278                 :     /*
                               1279                 :      * Clean up.  We keep lock on new relation (although it shouldn't be
                               1280                 :      * visible to anyone else anyway, until commit).
 7849 tgl                      1281 ECB             :      */
 7528 tgl                      1282 GIC       62424 :     relation_close(rel, NoLock);
 7849 tgl                      1283 ECB             : 
 2959 alvherre                 1284 GIC       62424 :     return address;
                               1285                 : }
                               1286                 : 
                               1287                 : /*
                               1288                 :  * Emit the right error or warning message for a "DROP" command issued on a
                               1289                 :  * non-existent relation
                               1290                 :  */
 5412 tgl                      1291 ECB             : static void
 3363 alvherre                 1292 CBC         516 : DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
                               1293                 : {
                               1294                 :     const struct dropmsgstrings *rentry;
                               1295                 : 
 3363 alvherre                 1296 GIC         573 :     if (rel->schemaname != NULL &&
                               1297              57 :         !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
                               1298                 :     {
                               1299              21 :         if (!missing_ok)
                               1300                 :         {
 3363 alvherre                 1301 LBC           0 :             ereport(ERROR,
                               1302                 :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
 2118 tgl                      1303 ECB             :                      errmsg("schema \"%s\" does not exist", rel->schemaname)));
 3363 alvherre                 1304                 :         }
                               1305                 :         else
                               1306                 :         {
 3363 alvherre                 1307 GIC          21 :             ereport(NOTICE,
                               1308                 :                     (errmsg("schema \"%s\" does not exist, skipping",
                               1309                 :                             rel->schemaname)));
                               1310                 :         }
                               1311              21 :         return;
 3363 alvherre                 1312 ECB             :     }
                               1313                 : 
 5412 tgl                      1314 CBC         643 :     for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
                               1315                 :     {
 5412 tgl                      1316 GIC         643 :         if (rentry->kind == rightkind)
                               1317                 :         {
                               1318             495 :             if (!missing_ok)
                               1319                 :             {
                               1320              65 :                 ereport(ERROR,
                               1321                 :                         (errcode(rentry->nonexistent_code),
 3363 alvherre                 1322 ECB             :                          errmsg(rentry->nonexistent_msg, rel->relname)));
                               1323                 :             }
                               1324                 :             else
                               1325                 :             {
 3363 alvherre                 1326 CBC         430 :                 ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
 5412 tgl                      1327             430 :                 break;
                               1328                 :             }
 5412 tgl                      1329 ECB             :         }
                               1330                 :     }
 5412 tgl                      1331 EUB             : 
 2118 tgl                      1332 GIC         430 :     Assert(rentry->kind != '\0');    /* Should be impossible */
                               1333                 : }
                               1334                 : 
                               1335                 : /*
                               1336                 :  * Emit the right error message for a "DROP" command issued on a
 5412 tgl                      1337 ECB             :  * relation of the wrong type
                               1338                 :  */
                               1339                 : static void
 5412 tgl                      1340 UIC           0 : DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
 5412 tgl                      1341 ECB             : {
                               1342                 :     const struct dropmsgstrings *rentry;
                               1343                 :     const struct dropmsgstrings *wentry;
                               1344                 : 
 5412 tgl                      1345 UIC           0 :     for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
 5412 tgl                      1346 LBC           0 :         if (rentry->kind == rightkind)
 5412 tgl                      1347 UIC           0 :             break;
 5412 tgl                      1348 LBC           0 :     Assert(rentry->kind != '\0');
                               1349                 : 
                               1350               0 :     for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
 5412 tgl                      1351 UIC           0 :         if (wentry->kind == wrongkind)
                               1352               0 :             break;
                               1353                 :     /* wrongkind could be something we don't have in our table... */
                               1354                 : 
                               1355               0 :     ereport(ERROR,
 5412 tgl                      1356 ECB             :             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               1357                 :              errmsg(rentry->nota_msg, relname),
                               1358                 :              (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
                               1359                 : }
                               1360                 : 
                               1361                 : /*
                               1362                 :  * RemoveRelations
                               1363                 :  *      Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
                               1364                 :  *      DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
                               1365                 :  */
                               1366                 : void
 5412 tgl                      1367 GIC        7479 : RemoveRelations(DropStmt *drop)
                               1368                 : {
                               1369                 :     ObjectAddresses *objects;
 5412 tgl                      1370 EUB             :     char        relkind;
                               1371                 :     ListCell   *cell;
 4020 simon                    1372 GIC        7479 :     int         flags = 0;
                               1373            7479 :     LOCKMODE    lockmode = AccessExclusiveLock;
                               1374                 : 
 3784 tgl                      1375 EUB             :     /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
 4020 simon                    1376 GBC        7479 :     if (drop->concurrent)
 4020 simon                    1377 EUB             :     {
 1173 michael                  1378                 :         /*
                               1379                 :          * Note that for temporary relations this lock may get upgraded later
 1060 tgl                      1380                 :          * on, but as no other session can access a temporary relation, this
                               1381                 :          * is actually fine.
 1173 michael                  1382                 :          */
 4020 simon                    1383 GIC          70 :         lockmode = ShareUpdateExclusiveLock;
 3784 tgl                      1384              70 :         Assert(drop->removeType == OBJECT_INDEX);
 3784 tgl                      1385 GBC          70 :         if (list_length(drop->objects) != 1)
 4020 simon                    1386 GIC           3 :             ereport(ERROR,
                               1387                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1388                 :                      errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
                               1389              67 :         if (drop->behavior == DROP_CASCADE)
 4020 simon                    1390 UIC           0 :             ereport(ERROR,
                               1391                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1392                 :                      errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
                               1393                 :     }
                               1394                 : 
                               1395                 :     /*
                               1396                 :      * First we identify all the relations, then we delete them in a single
 5050 bruce                    1397 ECB             :      * performMultipleDeletions() call.  This is to avoid unwanted DROP
                               1398                 :      * RESTRICT errors if one of the relations depends on another.
                               1399                 :      */
                               1400                 : 
                               1401                 :     /* Determine required relkind */
 5412 tgl                      1402 CBC        7476 :     switch (drop->removeType)
 5412 tgl                      1403 ECB             :     {
 5412 tgl                      1404 GIC        6494 :         case OBJECT_TABLE:
                               1405            6494 :             relkind = RELKIND_RELATION;
 5412 tgl                      1406 CBC        6494 :             break;
                               1407                 : 
 5412 tgl                      1408 GIC         363 :         case OBJECT_INDEX:
                               1409             363 :             relkind = RELKIND_INDEX;
                               1410             363 :             break;
                               1411                 : 
                               1412              86 :         case OBJECT_SEQUENCE:
 5412 tgl                      1413 CBC          86 :             relkind = RELKIND_SEQUENCE;
                               1414              86 :             break;
 5412 tgl                      1415 ECB             : 
 5412 tgl                      1416 CBC         402 :         case OBJECT_VIEW:
 5412 tgl                      1417 GIC         402 :             relkind = RELKIND_VIEW;
                               1418             402 :             break;
 5412 tgl                      1419 ECB             : 
 3689 kgrittn                  1420 GBC          57 :         case OBJECT_MATVIEW:
 3689 kgrittn                  1421 GIC          57 :             relkind = RELKIND_MATVIEW;
                               1422              57 :             break;
                               1423                 : 
 4481 rhaas                    1424              74 :         case OBJECT_FOREIGN_TABLE:
                               1425              74 :             relkind = RELKIND_FOREIGN_TABLE;
                               1426              74 :             break;
                               1427                 : 
 5412 tgl                      1428 UIC           0 :         default:
                               1429               0 :             elog(ERROR, "unrecognized drop object type: %d",
                               1430                 :                  (int) drop->removeType);
                               1431                 :             relkind = 0;        /* keep compiler quiet */
 5412 tgl                      1432 ECB             :             break;
                               1433                 :     }
                               1434                 : 
                               1435                 :     /* Lock and validate each relation; build a list of object addresses */
 5412 tgl                      1436 CBC        7476 :     objects = new_object_addresses();
                               1437                 : 
                               1438           16602 :     foreach(cell, drop->objects)
 5412 tgl                      1439 ECB             :     {
 5412 tgl                      1440 CBC        9204 :         RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
                               1441                 :         Oid         relOid;
 5412 tgl                      1442 ECB             :         ObjectAddress obj;
 3955 bruce                    1443                 :         struct DropRelationCallbackState state;
 5412 tgl                      1444                 : 
                               1445                 :         /*
                               1446                 :          * These next few steps are a great deal like relation_openrv, but we
                               1447                 :          * don't bother building a relcache entry since we don't need it.
                               1448                 :          *
                               1449                 :          * Check for shared-cache-inval messages before trying to access the
                               1450                 :          * relation.  This is needed to cover the case where the name
                               1451                 :          * identifies a rel that has been dropped and recreated since the
                               1452                 :          * start of our transaction: if we don't flush the old syscache entry,
                               1453                 :          * then we'll latch onto that entry and suffer an error later.
                               1454                 :          */
 5412 tgl                      1455 CBC        9204 :         AcceptInvalidationMessages();
 5412 tgl                      1456 ECB             : 
                               1457                 :         /* Look up the appropriate relation using namespace search. */
  384 tgl                      1458 GBC        9204 :         state.expected_relkind = relkind;
                               1459           18408 :         state.heap_lockmode = drop->concurrent ?
  384 tgl                      1460 GIC        9204 :             ShareUpdateExclusiveLock : AccessExclusiveLock;
                               1461                 :         /* We must initialize these fields to show that no locks are held: */
 4148 rhaas                    1462            9204 :         state.heapOid = InvalidOid;
 2189                          1463            9204 :         state.partParentOid = InvalidOid;
                               1464                 : 
 1836 andres                   1465            9204 :         relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
 4148 rhaas                    1466 ECB             :                                           RangeVarCallbackForDropRelation,
                               1467                 :                                           (void *) &state);
 5412 tgl                      1468                 : 
                               1469                 :         /* Not there? */
 5412 tgl                      1470 CBC        9194 :         if (!OidIsValid(relOid))
                               1471                 :         {
 3363 alvherre                 1472 GIC         516 :             DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
 5412 tgl                      1473             451 :             continue;
                               1474                 :         }
                               1475                 : 
                               1476                 :         /*
                               1477                 :          * Decide if concurrent mode needs to be used here or not.  The
                               1478                 :          * callback retrieved the rel's persistence for us.
                               1479                 :          */
 1173 michael                  1480            8678 :         if (drop->concurrent &&
  384 tgl                      1481              64 :             state.actual_relpersistence != RELPERSISTENCE_TEMP)
                               1482                 :         {
 1173 michael                  1483              55 :             Assert(list_length(drop->objects) == 1 &&
                               1484                 :                    drop->removeType == OBJECT_INDEX);
 1173 michael                  1485 CBC          55 :             flags |= PERFORM_DELETION_CONCURRENTLY;
                               1486                 :         }
                               1487                 : 
  950 alvherre                 1488 ECB             :         /*
                               1489                 :          * Concurrent index drop cannot be used with partitioned indexes,
                               1490                 :          * either.
                               1491                 :          */
  950 alvherre                 1492 CBC        8678 :         if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
  384 tgl                      1493              55 :             state.actual_relkind == RELKIND_PARTITIONED_INDEX)
  950 alvherre                 1494 GIC           3 :             ereport(ERROR,
  950 alvherre                 1495 ECB             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1496                 :                      errmsg("cannot drop partitioned index \"%s\" concurrently",
                               1497                 :                             rel->relname)));
                               1498                 : 
                               1499                 :         /*
  384 tgl                      1500                 :          * If we're told to drop a partitioned index, we must acquire lock on
                               1501                 :          * all the children of its parent partitioned table before proceeding.
                               1502                 :          * Otherwise we'd try to lock the child index partitions before their
                               1503                 :          * tables, leading to potential deadlock against other sessions that
                               1504                 :          * will lock those objects in the other order.
                               1505                 :          */
  384 tgl                      1506 GIC        8675 :         if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
                               1507              26 :             (void) find_all_inheritors(state.heapOid,
                               1508                 :                                        state.heap_lockmode,
                               1509                 :                                        NULL);
  384 tgl                      1510 ECB             : 
 5412                          1511                 :         /* OK, we're ready to delete this one */
 5412 tgl                      1512 GIC        8675 :         obj.classId = RelationRelationId;
 5412 tgl                      1513 CBC        8675 :         obj.objectId = relOid;
 5412 tgl                      1514 GIC        8675 :         obj.objectSubId = 0;
 5412 tgl                      1515 ECB             : 
 5412 tgl                      1516 GIC        8675 :         add_exact_object_address(&obj, objects);
                               1517                 :     }
                               1518                 : 
 4020 simon                    1519            7398 :     performMultipleDeletions(objects, drop->behavior, flags);
                               1520                 : 
 5412 tgl                      1521            7330 :     free_object_addresses(objects);
 8484 peter_e                  1522 CBC        7330 : }
 8484 peter_e                  1523 ECB             : 
 4148 rhaas                    1524                 : /*
                               1525                 :  * Before acquiring a table lock, check whether we have sufficient rights.
                               1526                 :  * In the case of DROP INDEX, also try to lock the table before the index.
                               1527                 :  * Also, if the table to be dropped is a partition, we try to lock the parent
                               1528                 :  * first.
                               1529                 :  */
                               1530                 : static void
 4148 rhaas                    1531 GIC        9317 : RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
                               1532                 :                                 void *arg)
                               1533                 : {
                               1534                 :     HeapTuple   tuple;
                               1535                 :     struct DropRelationCallbackState *state;
 2314 rhaas                    1536 ECB             :     char        expected_relkind;
 2189                          1537                 :     bool        is_partition;
                               1538                 :     Form_pg_class classform;
                               1539                 :     LOCKMODE    heap_lockmode;
 1472 peter                    1540 GIC        9317 :     bool        invalid_system_index = false;
                               1541                 : 
 4148 rhaas                    1542 CBC        9317 :     state = (struct DropRelationCallbackState *) arg;
  384 tgl                      1543            9317 :     heap_lockmode = state->heap_lockmode;
 4148 rhaas                    1544 ECB             : 
                               1545                 :     /*
                               1546                 :      * If we previously locked some other index's heap, and the name we're
                               1547                 :      * looking up no longer refers to that relation, release the now-useless
                               1548                 :      * lock.
                               1549                 :      */
 4148 rhaas                    1550 GIC        9317 :     if (relOid != oldRelOid && OidIsValid(state->heapOid))
 4148 rhaas                    1551 ECB             :     {
 4020 simon                    1552 LBC           0 :         UnlockRelationOid(state->heapOid, heap_lockmode);
 4148 rhaas                    1553 UIC           0 :         state->heapOid = InvalidOid;
                               1554                 :     }
                               1555                 : 
                               1556                 :     /*
                               1557                 :      * Similarly, if we previously locked some other partition's heap, and the
                               1558                 :      * name we're looking up no longer refers to that relation, release the
                               1559                 :      * now-useless lock.
                               1560                 :      */
 2189 rhaas                    1561 CBC        9317 :     if (relOid != oldRelOid && OidIsValid(state->partParentOid))
                               1562                 :     {
 2189 rhaas                    1563 UIC           0 :         UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
                               1564               0 :         state->partParentOid = InvalidOid;
                               1565                 :     }
                               1566                 : 
                               1567                 :     /* Didn't find a relation, so no need for locking or permission checks. */
 4148 rhaas                    1568 GIC        9317 :     if (!OidIsValid(relOid))
                               1569             521 :         return;
 4148 rhaas                    1570 ECB             : 
 4148 rhaas                    1571 GIC        8796 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
 4148 rhaas                    1572 CBC        8796 :     if (!HeapTupleIsValid(tuple))
 4148 rhaas                    1573 LBC           0 :         return;                 /* concurrently dropped, so nothing to do */
 4148 rhaas                    1574 GIC        8796 :     classform = (Form_pg_class) GETSTRUCT(tuple);
 2189                          1575            8796 :     is_partition = classform->relispartition;
                               1576                 : 
                               1577                 :     /* Pass back some data to save lookups in RemoveRelations */
  384 tgl                      1578            8796 :     state->actual_relkind = classform->relkind;
                               1579            8796 :     state->actual_relpersistence = classform->relpersistence;
  384 tgl                      1580 ECB             : 
                               1581                 :     /*
 2314 rhaas                    1582 EUB             :      * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
                               1583                 :      * but RemoveRelations() can only pass one relkind for a given relation.
                               1584                 :      * It chooses RELKIND_RELATION for both regular and partitioned tables.
                               1585                 :      * That means we must be careful before giving the wrong type error when
                               1586                 :      * the relation is RELKIND_PARTITIONED_TABLE.  An equivalent problem
                               1587                 :      * exists with indexes.
                               1588                 :      */
 2314 rhaas                    1589 GIC        8796 :     if (classform->relkind == RELKIND_PARTITIONED_TABLE)
                               1590            1262 :         expected_relkind = RELKIND_RELATION;
 1906 alvherre                 1591 CBC        7534 :     else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
 1906 alvherre                 1592 GIC          31 :         expected_relkind = RELKIND_INDEX;
 2314 rhaas                    1593 EUB             :     else
 2314 rhaas                    1594 GBC        7503 :         expected_relkind = classform->relkind;
                               1595                 : 
  384 tgl                      1596 GIC        8796 :     if (state->expected_relkind != expected_relkind)
  384 tgl                      1597 UIC           0 :         DropErrorMsgWrongType(rel->relname, classform->relkind,
  384 tgl                      1598 LBC           0 :                               state->expected_relkind);
 4148 rhaas                    1599 ECB             : 
                               1600                 :     /* Allow DROP to either table owner or schema owner */
  147 peter                    1601 GNC        8796 :     if (!object_ownercheck(RelationRelationId, relOid, GetUserId()) &&
                               1602               9 :         !object_ownercheck(NamespaceRelationId, classform->relnamespace, GetUserId()))
  384 tgl                      1603 GBC           9 :         aclcheck_error(ACLCHECK_NOT_OWNER,
  384 tgl                      1604 CBC           9 :                        get_relkind_objtype(classform->relkind),
 4148 rhaas                    1605               9 :                        rel->relname);
                               1606                 : 
                               1607                 :     /*
 1472 peter                    1608 ECB             :      * Check the case of a system index that might have been invalidated by a
                               1609                 :      * failed concurrent process and allow its drop. For the time being, this
                               1610                 :      * only concerns indexes of toast relations that became invalid during a
                               1611                 :      * REINDEX CONCURRENTLY process.
                               1612                 :      */
  384 tgl                      1613 GIC        8787 :     if (IsSystemClass(relOid, classform) && classform->relkind == RELKIND_INDEX)
                               1614                 :     {
                               1615                 :         HeapTuple   locTuple;
                               1616                 :         Form_pg_index indexform;
                               1617                 :         bool        indisvalid;
                               1618                 : 
 1472 peter                    1619 LBC           0 :         locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
                               1620               0 :         if (!HeapTupleIsValid(locTuple))
 1472 peter                    1621 ECB             :         {
 1472 peter                    1622 LBC           0 :             ReleaseSysCache(tuple);
 1472 peter                    1623 UIC           0 :             return;
 1472 peter                    1624 ECB             :         }
                               1625                 : 
 1472 peter                    1626 LBC           0 :         indexform = (Form_pg_index) GETSTRUCT(locTuple);
 1472 peter                    1627 UBC           0 :         indisvalid = indexform->indisvalid;
                               1628               0 :         ReleaseSysCache(locTuple);
                               1629                 : 
                               1630                 :         /* Mark object as being an invalid index of system catalogs */
 1472 peter                    1631 LBC           0 :         if (!indisvalid)
                               1632               0 :             invalid_system_index = true;
 1472 peter                    1633 ECB             :     }
                               1634                 : 
                               1635                 :     /* In the case of an invalid index, it is fine to bypass this check */
 1472 peter                    1636 GIC        8787 :     if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
 4148 rhaas                    1637               1 :         ereport(ERROR,
                               1638                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                               1639                 :                  errmsg("permission denied: \"%s\" is a system catalog",
                               1640                 :                         rel->relname)));
                               1641                 : 
                               1642            8786 :     ReleaseSysCache(tuple);
 4148 rhaas                    1643 ECB             : 
                               1644                 :     /*
                               1645                 :      * In DROP INDEX, attempt to acquire lock on the parent table before
                               1646                 :      * locking the index.  index_drop() will need this anyway, and since
                               1647                 :      * regular queries lock tables before their indexes, we risk deadlock if
                               1648                 :      * we do it the other way around.  No error if we don't find a pg_index
  384 tgl                      1649 EUB             :      * entry, though --- the relation may have been dropped.  Note that this
                               1650                 :      * code will execute for either plain or partitioned indexes.
                               1651                 :      */
  384 tgl                      1652 GBC        8786 :     if (expected_relkind == RELKIND_INDEX &&
 1906 alvherre                 1653 EUB             :         relOid != oldRelOid)
                               1654                 :     {
 4148 rhaas                    1655 GIC         354 :         state->heapOid = IndexGetRelation(relOid, true);
 4148 rhaas                    1656 GBC         354 :         if (OidIsValid(state->heapOid))
 4020 simon                    1657             354 :             LockRelationOid(state->heapOid, heap_lockmode);
 4148 rhaas                    1658 EUB             :     }
                               1659                 : 
                               1660                 :     /*
 2189                          1661                 :      * Similarly, if the relation is a partition, we must acquire lock on its
                               1662                 :      * parent before locking the partition.  That's because queries lock the
                               1663                 :      * parent before its partitions, so we risk deadlock if we do it the other
                               1664                 :      * way around.
                               1665                 :      */
 2189 rhaas                    1666 CBC        8786 :     if (is_partition && relOid != oldRelOid)
 2189 rhaas                    1667 ECB             :     {
  745 alvherre                 1668 GIC         293 :         state->partParentOid = get_partition_parent(relOid, true);
 2189 rhaas                    1669             293 :         if (OidIsValid(state->partParentOid))
                               1670             293 :             LockRelationOid(state->partParentOid, AccessExclusiveLock);
                               1671                 :     }
 4148 rhaas                    1672 ECB             : }
                               1673                 : 
                               1674                 : /*
                               1675                 :  * ExecuteTruncate
                               1676                 :  *      Executes a TRUNCATE command.
                               1677                 :  *
                               1678                 :  * This is a multi-relation truncate.  We first open and grab exclusive
                               1679                 :  * lock on all relations involved, checking permissions and otherwise
                               1680                 :  * verifying that the relation is OK for truncation.  Note that if relations
                               1681                 :  * are foreign tables, at this stage, we have not yet checked that their
  731 fujii                    1682                 :  * foreign data in external data sources are OK for truncation.  These are
                               1683                 :  * checked when foreign data are actually truncated later.  In CASCADE mode,
                               1684                 :  * relations having FK references to the targeted relations are automatically
 6246 tgl                      1685                 :  * added to the group; in RESTRICT mode, we check that all FK references are
                               1686                 :  * internal to the group that's being truncated.  Finally all the relations
                               1687                 :  * are truncated and reindexed.
                               1688                 :  */
                               1689                 : void
 6246 tgl                      1690 GIC         641 : ExecuteTruncate(TruncateStmt *stmt)
                               1691                 : {
 6385 bruce                    1692             641 :     List       *rels = NIL;
 6246 tgl                      1693             641 :     List       *relids = NIL;
 1828 peter_e                  1694             641 :     List       *relids_logged = NIL;
                               1695                 :     ListCell   *cell;
 7678 tgl                      1696 ECB             : 
                               1697                 :     /*
 6246                          1698                 :      * Open, exclusive-lock, and check all the explicitly-specified relations
                               1699                 :      */
 6246 tgl                      1700 CBC        1359 :     foreach(cell, stmt->relations)
                               1701                 :     {
 6646 tgl                      1702 GIC         742 :         RangeVar   *rv = lfirst(cell);
                               1703                 :         Relation    rel;
 2298                          1704             742 :         bool        recurse = rv->inh;
                               1705                 :         Oid         myrelid;
 1564 michael                  1706             742 :         LOCKMODE    lockmode = AccessExclusiveLock;
                               1707                 : 
                               1708             742 :         myrelid = RangeVarGetRelidExtended(rv, lockmode,
                               1709                 :                                            0, RangeVarCallbackForTruncate,
                               1710                 :                                            NULL);
                               1711                 : 
                               1712                 :         /* don't throw error for "TRUNCATE foo, foo" */
 5200 peter_e                  1713             724 :         if (list_member_oid(relids, myrelid))
 5380 tgl                      1714               1 :             continue;
                               1715                 : 
                               1716                 :         /* open the relation, we already hold a lock on it */
  727 fujii                    1717             723 :         rel = table_open(myrelid, NoLock);
                               1718                 : 
                               1719                 :         /*
 1703 michael                  1720 ECB             :          * RangeVarGetRelidExtended() has done most checks with its callback,
                               1721                 :          * but other checks with the now-opened Relation remain.
                               1722                 :          */
 1703 michael                  1723 CBC         723 :         truncate_check_activity(rel);
 1703 michael                  1724 ECB             : 
 6246 tgl                      1725 GIC         723 :         rels = lappend(rels, rel);
 5200 peter_e                  1726             723 :         relids = lappend_oid(relids, myrelid);
                               1727                 : 
                               1728                 :         /* Log this relation only if needed for logical decoding */
 1828                          1729             723 :         if (RelationIsLogicallyLogged(rel))
 1828 peter_e                  1730 CBC          37 :             relids_logged = lappend_oid(relids_logged, myrelid);
                               1731                 : 
 5200                          1732             723 :         if (recurse)
                               1733                 :         {
 5200 peter_e                  1734 ECB             :             ListCell   *child;
                               1735                 :             List       *children;
                               1736                 : 
 1564 michael                  1737 GIC         692 :             children = find_all_inheritors(myrelid, lockmode, NULL);
 5200 peter_e                  1738 ECB             : 
 5200 peter_e                  1739 GIC        2202 :             foreach(child, children)
                               1740                 :             {
                               1741            1510 :                 Oid         childrelid = lfirst_oid(child);
                               1742                 : 
 5200 peter_e                  1743 CBC        1510 :                 if (list_member_oid(relids, childrelid))
                               1744             692 :                     continue;
                               1745                 : 
                               1746                 :                 /* find_all_inheritors already got lock */
 1539 andres                   1747             818 :                 rel = table_open(childrelid, NoLock);
                               1748                 : 
                               1749                 :                 /*
                               1750                 :                  * It is possible that the parent table has children that are
                               1751                 :                  * temp tables of other backends.  We cannot safely access
                               1752                 :                  * such tables (because of buffering issues), and the best
 1564 michael                  1753 ECB             :                  * thing to do is to silently ignore them.  Note that this
                               1754                 :                  * check is the same as one of the checks done in
                               1755                 :                  * truncate_check_activity() called below, still it is kept
                               1756                 :                  * here for simplicity.
                               1757                 :                  */
 1564 michael                  1758 GIC         818 :                 if (RELATION_IS_OTHER_TEMP(rel))
 1564 michael                  1759 ECB             :                 {
 1539 andres                   1760 CBC           4 :                     table_close(rel, lockmode);
 1564 michael                  1761 GIC           4 :                     continue;
 1564 michael                  1762 ECB             :                 }
                               1763                 : 
                               1764                 :                 /*
                               1765                 :                  * Inherited TRUNCATE commands perform access permission
                               1766                 :                  * checks on the parent table only. So we skip checking the
 1060 tgl                      1767                 :                  * children's permissions and don't call
                               1768                 :                  * truncate_check_perms() here.
 1164 fujii                    1769                 :                  */
 1703 michael                  1770 GIC         814 :                 truncate_check_rel(RelationGetRelid(rel), rel->rd_rel);
 1703 michael                  1771 CBC         814 :                 truncate_check_activity(rel);
                               1772                 : 
 5200 peter_e                  1773             814 :                 rels = lappend(rels, rel);
                               1774             814 :                 relids = lappend_oid(relids, childrelid);
                               1775                 : 
                               1776                 :                 /* Log this relation only if needed for logical decoding */
 1828                          1777             814 :                 if (RelationIsLogicallyLogged(rel))
 1828 peter_e                  1778 GIC          16 :                     relids_logged = lappend_oid(relids_logged, childrelid);
                               1779                 :             }
                               1780                 :         }
 2314 rhaas                    1781              31 :         else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               1782               6 :             ereport(ERROR,
                               1783                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               1784                 :                      errmsg("cannot truncate only a partitioned table"),
                               1785                 :                      errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
                               1786                 :     }
                               1787                 : 
  712 fujii                    1788 CBC         617 :     ExecuteTruncateGuts(rels, relids, relids_logged,
    5 rhaas                    1789 GNC         617 :                         stmt->behavior, stmt->restart_seqs, false);
 1828 peter_e                  1790 ECB             : 
                               1791                 :     /* And close the rels */
 1828 peter_e                  1792 GIC        2030 :     foreach(cell, rels)
                               1793                 :     {
                               1794            1454 :         Relation    rel = (Relation) lfirst(cell);
                               1795                 : 
 1539 andres                   1796            1454 :         table_close(rel, NoLock);
                               1797                 :     }
 1828 peter_e                  1798             576 : }
                               1799                 : 
 1828 peter_e                  1800 ECB             : /*
                               1801                 :  * ExecuteTruncateGuts
                               1802                 :  *
                               1803                 :  * Internal implementation of TRUNCATE.  This is called by the actual TRUNCATE
                               1804                 :  * command (see above) as well as replication subscribers that execute a
                               1805                 :  * replicated TRUNCATE action.
                               1806                 :  *
                               1807                 :  * explicit_rels is the list of Relations to truncate that the command
                               1808                 :  * specified.  relids is the list of Oids corresponding to explicit_rels.
                               1809                 :  * relids_logged is the list of Oids (a subset of relids) that require
                               1810                 :  * WAL-logging.  This is all a bit redundant, but the existing callers have
  712 fujii                    1811                 :  * this information handy in this form.
 1828 peter_e                  1812                 :  */
                               1813                 : void
  731 fujii                    1814 GIC         634 : ExecuteTruncateGuts(List *explicit_rels,
                               1815                 :                     List *relids,
                               1816                 :                     List *relids_logged,
                               1817                 :                     DropBehavior behavior, bool restart_seqs,
                               1818                 :                     bool run_as_table_owner)
 1828 peter_e                  1819 ECB             : {
                               1820                 :     List       *rels;
 1828 peter_e                  1821 GIC         634 :     List       *seq_relids = NIL;
  731 fujii                    1822             634 :     HTAB       *ft_htab = NULL;
 1828 peter_e                  1823 ECB             :     EState     *estate;
                               1824                 :     ResultRelInfo *resultRelInfos;
                               1825                 :     ResultRelInfo *resultRelInfo;
                               1826                 :     SubTransactionId mySubid;
                               1827                 :     ListCell   *cell;
                               1828                 :     Oid        *logrelids;
                               1829                 : 
                               1830                 :     /*
                               1831                 :      * Check the explicitly-specified relations.
                               1832                 :      *
                               1833                 :      * In CASCADE mode, suck in all referencing relations as well.  This
                               1834                 :      * requires multiple iterations to find indirectly-dependent relations. At
                               1835                 :      * each phase, we need to exclusive-lock new rels before looking for their
                               1836                 :      * dependencies, else we might miss something.  Also, we check each rel as
                               1837                 :      * soon as we open it, to avoid a faux pas such as holding lock for a long
                               1838                 :      * time on a rel we have no permissions for.
                               1839                 :      */
 1828 peter_e                  1840 GIC         634 :     rels = list_copy(explicit_rels);
                               1841             634 :     if (behavior == DROP_CASCADE)
                               1842                 :     {
                               1843                 :         for (;;)
 6246 tgl                      1844              20 :         {
 6031 bruce                    1845 ECB             :             List       *newrelids;
                               1846                 : 
 6246 tgl                      1847 GIC          40 :             newrelids = heap_truncate_find_FKs(relids);
                               1848              40 :             if (newrelids == NIL)
                               1849              20 :                 break;          /* nothing else to add */
                               1850                 : 
                               1851              67 :             foreach(cell, newrelids)
 6246 tgl                      1852 ECB             :             {
 6031 bruce                    1853 CBC          47 :                 Oid         relid = lfirst_oid(cell);
                               1854                 :                 Relation    rel;
                               1855                 : 
 1539 andres                   1856 GIC          47 :                 rel = table_open(relid, AccessExclusiveLock);
 6246 tgl                      1857              47 :                 ereport(NOTICE,
                               1858                 :                         (errmsg("truncate cascades to table \"%s\"",
                               1859                 :                                 RelationGetRelationName(rel))));
 1703 michael                  1860              47 :                 truncate_check_rel(relid, rel->rd_rel);
 1164 fujii                    1861              47 :                 truncate_check_perms(relid, rel->rd_rel);
 1703 michael                  1862              47 :                 truncate_check_activity(rel);
 6246 tgl                      1863              47 :                 rels = lappend(rels, rel);
                               1864              47 :                 relids = lappend_oid(relids, relid);
                               1865                 : 
                               1866                 :                 /* Log this relation only if needed for logical decoding */
 1828 peter_e                  1867              47 :                 if (RelationIsLogicallyLogged(rel))
 1828 peter_e                  1868 UIC           0 :                     relids_logged = lappend_oid(relids_logged, relid);
                               1869                 :             }
                               1870                 :         }
 6246 tgl                      1871 ECB             :     }
                               1872                 : 
                               1873                 :     /*
                               1874                 :      * Check foreign key references.  In CASCADE mode, this should be
 6031 bruce                    1875                 :      * unnecessary since we just pulled in all the references; but as a
                               1876                 :      * cross-check, do it anyway if in an Assert-enabled build.
                               1877                 :      */
 6246 tgl                      1878                 : #ifdef USE_ASSERT_CHECKING
 6646 tgl                      1879 CBC         634 :     heap_truncate_check_FKs(rels, false);
 6246 tgl                      1880 ECB             : #else
                               1881                 :     if (behavior == DROP_RESTRICT)
                               1882                 :         heap_truncate_check_FKs(rels, false);
                               1883                 : #endif
 7405                          1884                 : 
                               1885                 :     /*
                               1886                 :      * If we are asked to restart sequences, find all the sequences, lock them
 4526                          1887                 :      * (we need AccessExclusiveLock for ResetSequence), and check permissions.
                               1888                 :      * We want to do this early since it's pointless to do all the truncation
                               1889                 :      * work only to fail on sequence permissions.
                               1890                 :      */
 1828 peter_e                  1891 CBC         597 :     if (restart_seqs)
 5441 tgl                      1892 ECB             :     {
 5441 tgl                      1893 CBC          26 :         foreach(cell, rels)
 5441 tgl                      1894 ECB             :         {
 5441 tgl                      1895 CBC          13 :             Relation    rel = (Relation) lfirst(cell);
 1357 peter                    1896 GIC          13 :             List       *seqlist = getOwnedSequences(RelationGetRelid(rel));
                               1897                 :             ListCell   *seqcell;
 5441 tgl                      1898 ECB             : 
 5441 tgl                      1899 GBC          31 :             foreach(seqcell, seqlist)
                               1900                 :             {
 5050 bruce                    1901 GIC          18 :                 Oid         seq_relid = lfirst_oid(seqcell);
                               1902                 :                 Relation    seq_rel;
                               1903                 : 
 4526 tgl                      1904              18 :                 seq_rel = relation_open(seq_relid, AccessExclusiveLock);
                               1905                 : 
                               1906                 :                 /* This check must match AlterSequence! */
  147 peter                    1907 GNC          18 :                 if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
 1954 peter_e                  1908 UIC           0 :                     aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SEQUENCE,
 5441 tgl                      1909               0 :                                    RelationGetRelationName(seq_rel));
 5441 tgl                      1910 ECB             : 
 5441 tgl                      1911 GIC          18 :                 seq_relids = lappend_oid(seq_relids, seq_relid);
                               1912                 : 
                               1913              18 :                 relation_close(seq_rel, NoLock);
                               1914                 :             }
                               1915                 :         }
                               1916                 :     }
                               1917                 : 
                               1918                 :     /* Prepare to catch AFTER triggers. */
 5490                          1919             597 :     AfterTriggerBeginQuery();
                               1920                 : 
                               1921                 :     /*
 5050 bruce                    1922 ECB             :      * To fire triggers, we'll need an EState as well as a ResultRelInfo for
                               1923                 :      * each relation.  We don't need to call ExecOpenIndices, though.
  908 heikki.linnakangas       1924                 :      *
                               1925                 :      * We put the ResultRelInfos in the es_opened_result_relations list, even
                               1926                 :      * though we don't have a range table and don't populate the
  888 michael                  1927                 :      * es_result_relations array.  That's a bit bogus, but it's enough to make
                               1928                 :      * ExecGetTriggerResultRel() find them.
                               1929                 :      */
 5490 tgl                      1930 CBC         597 :     estate = CreateExecutorState();
                               1931                 :     resultRelInfos = (ResultRelInfo *)
                               1932             597 :         palloc(list_length(rels) * sizeof(ResultRelInfo));
 5490 tgl                      1933 GIC         597 :     resultRelInfo = resultRelInfos;
                               1934            2135 :     foreach(cell, rels)
 5490 tgl                      1935 ECB             :     {
 5490 tgl                      1936 GIC        1538 :         Relation    rel = (Relation) lfirst(cell);
                               1937                 : 
 5490 tgl                      1938 CBC        1538 :         InitResultRelInfo(resultRelInfo,
 5490 tgl                      1939 EUB             :                           rel,
 5050 bruce                    1940                 :                           0,    /* dummy rangetable index */
                               1941                 :                           NULL,
 4863 rhaas                    1942 ECB             :                           0);
  908 heikki.linnakangas       1943 GIC        1538 :         estate->es_opened_result_relations =
  908 heikki.linnakangas       1944 CBC        1538 :             lappend(estate->es_opened_result_relations, resultRelInfo);
 5490 tgl                      1945 GIC        1538 :         resultRelInfo++;
                               1946                 :     }
                               1947                 : 
                               1948                 :     /*
                               1949                 :      * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
 5050 bruce                    1950 ECB             :      * truncating (this is because one of them might throw an error). Also, if
                               1951                 :      * we were to allow them to prevent statement execution, that would need
                               1952                 :      * to be handled here.
                               1953                 :      */
 5490 tgl                      1954 GIC         597 :     resultRelInfo = resultRelInfos;
                               1955            2135 :     foreach(cell, rels)
                               1956                 :     {
                               1957                 :         UserContext ucxt;
                               1958                 : 
    5 rhaas                    1959 GNC        1538 :         if (run_as_table_owner)
                               1960              33 :             SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
                               1961                 :                                   &ucxt);
 5490 tgl                      1962 GIC        1538 :         ExecBSTruncateTriggers(estate, resultRelInfo);
    5 rhaas                    1963 GNC        1538 :         if (run_as_table_owner)
                               1964              33 :             RestoreUserContext(&ucxt);
 5490 tgl                      1965 GIC        1538 :         resultRelInfo++;
                               1966                 :     }
                               1967                 : 
 7405 tgl                      1968 ECB             :     /*
                               1969                 :      * OK, truncate each table.
                               1970                 :      */
 4977 tgl                      1971 CBC         597 :     mySubid = GetCurrentSubTransactionId();
 4977 tgl                      1972 ECB             : 
  712 fujii                    1973 GIC        2135 :     foreach(cell, rels)
 6910 tgl                      1974 ECB             :     {
  712 fujii                    1975 GIC        1538 :         Relation    rel = (Relation) lfirst(cell);
 6646 tgl                      1976 ECB             : 
                               1977                 :         /* Skip partitioned tables as there is nothing to do */
 2229 rhaas                    1978 GIC        1538 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               1979             322 :             continue;
                               1980                 : 
  731 fujii                    1981 ECB             :         /*
                               1982                 :          * Build the lists of foreign tables belonging to each foreign server
                               1983                 :          * and pass each list to the foreign data wrapper's callback function,
                               1984                 :          * so that each server can truncate its all foreign tables in bulk.
                               1985                 :          * Each list is saved as a single entry in a hash table that uses the
                               1986                 :          * server OID as lookup key.
                               1987                 :          */
  731 fujii                    1988 GIC        1216 :         if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
                               1989              17 :         {
                               1990              17 :             Oid         serverid = GetForeignServerIdByRelId(RelationGetRelid(rel));
                               1991                 :             bool        found;
  731 fujii                    1992 ECB             :             ForeignTruncateInfo *ft_info;
                               1993                 : 
                               1994                 :             /* First time through, initialize hashtable for foreign tables */
  731 fujii                    1995 GIC          17 :             if (!ft_htab)
                               1996                 :             {
  731 fujii                    1997 ECB             :                 HASHCTL     hctl;
                               1998                 : 
  731 fujii                    1999 GIC          15 :                 memset(&hctl, 0, sizeof(HASHCTL));
  731 fujii                    2000 CBC          15 :                 hctl.keysize = sizeof(Oid);
                               2001              15 :                 hctl.entrysize = sizeof(ForeignTruncateInfo);
                               2002              15 :                 hctl.hcxt = CurrentMemoryContext;
  731 fujii                    2003 ECB             : 
  731 fujii                    2004 GIC          15 :                 ft_htab = hash_create("TRUNCATE for Foreign Tables",
                               2005                 :                                       32,   /* start small and extend */
                               2006                 :                                       &hctl,
                               2007                 :                                       HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
                               2008                 :             }
  731 fujii                    2009 ECB             : 
                               2010                 :             /* Find or create cached entry for the foreign table */
  731 fujii                    2011 CBC          17 :             ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
  731 fujii                    2012 GIC          17 :             if (!found)
  731 fujii                    2013 ECB             :             {
  731 fujii                    2014 GIC          15 :                 ft_info->serverid = serverid;
                               2015              15 :                 ft_info->rels = NIL;
  731 fujii                    2016 ECB             :             }
                               2017                 : 
                               2018                 :             /*
                               2019                 :              * Save the foreign table in the entry of the server that the
                               2020                 :              * foreign table belongs to.
                               2021                 :              */
  731 fujii                    2022 GIC          17 :             ft_info->rels = lappend(ft_info->rels, rel);
                               2023              17 :             continue;
                               2024                 :         }
                               2025                 : 
 6646 tgl                      2026 ECB             :         /*
 4790 bruce                    2027                 :          * Normally, we need a transaction-safe truncation here.  However, if
                               2028                 :          * the table was either created in the current (sub)transaction or has
                               2029                 :          * a new relfilenumber in the current (sub)transaction, then we can
                               2030                 :          * just truncate it in-place, because a rollback would cause the whole
                               2031                 :          * table or the current physical file to be thrown away anyway.
                               2032                 :          */
 4977 tgl                      2033 CBC        1199 :         if (rel->rd_createSubid == mySubid ||
  277 rhaas                    2034 GNC        1191 :             rel->rd_newRelfilelocatorSubid == mySubid)
                               2035                 :         {
                               2036                 :             /* Immediate, non-rollbackable truncation is OK */
 4977 tgl                      2037 CBC          24 :             heap_truncate_one_rel(rel);
 6646 tgl                      2038 ECB             :         }
 4977                          2039                 :         else
                               2040                 :         {
                               2041                 :             Oid         heap_relid;
                               2042                 :             Oid         toast_relid;
  811 michael                  2043 GIC        1175 :             ReindexParams reindex_params = {0};
                               2044                 : 
                               2045                 :             /*
                               2046                 :              * This effectively deletes all rows in the table, and may be done
                               2047                 :              * in a serializable transaction.  In that case we must record a
                               2048                 :              * rw-conflict in to this transaction from each transaction
 4323 heikki.linnakangas       2049 ECB             :              * holding a predicate lock on the table.
                               2050                 :              */
 4323 heikki.linnakangas       2051 GIC        1175 :             CheckTableForSerializableConflictIn(rel);
 4323 heikki.linnakangas       2052 ECB             : 
 4977 tgl                      2053                 :             /*
                               2054                 :              * Need the full transaction-safe pushups.
                               2055                 :              *
                               2056                 :              * Create a new empty storage file for the relation, and assign it
                               2057                 :              * as the relfilenumber value. The old storage file is scheduled
                               2058                 :              * for deletion at commit.
                               2059                 :              */
  277 rhaas                    2060 GNC        1175 :             RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
 6646 tgl                      2061 ECB             : 
 4977 tgl                      2062 GIC        1175 :             heap_relid = RelationGetRelid(rel);
                               2063                 : 
                               2064                 :             /*
                               2065                 :              * The same for the toast table, if any.
                               2066                 :              */
 1584                          2067            1175 :             toast_relid = rel->rd_rel->reltoastrelid;
 4977                          2068            1175 :             if (OidIsValid(toast_relid))
                               2069                 :             {
 1584                          2070             700 :                 Relation    toastrel = relation_open(toast_relid,
 1584 tgl                      2071 ECB             :                                                      AccessExclusiveLock);
 1418                          2072                 : 
  277 rhaas                    2073 GNC         700 :                 RelationSetNewRelfilenumber(toastrel,
                               2074             700 :                                             toastrel->rd_rel->relpersistence);
 1539 andres                   2075 CBC         700 :                 table_close(toastrel, NoLock);
                               2076                 :             }
                               2077                 : 
                               2078                 :             /*
                               2079                 :              * Reconstruct the indexes to match, and we're done.
                               2080                 :              */
  811 michael                  2081            1175 :             reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST,
                               2082                 :                              &reindex_params);
                               2083                 :         }
                               2084                 : 
 2970 alvherre                 2085 GIC        1199 :         pgstat_count_truncate(rel);
                               2086                 :     }
                               2087                 : 
                               2088                 :     /* Now go through the hash table, and truncate foreign tables */
  731 fujii                    2089 CBC         597 :     if (ft_htab)
                               2090                 :     {
                               2091                 :         ForeignTruncateInfo *ft_info;
                               2092                 :         HASH_SEQ_STATUS seq;
                               2093                 : 
  731 fujii                    2094 GIC          15 :         hash_seq_init(&seq, ft_htab);
                               2095                 : 
                               2096              15 :         PG_TRY();
                               2097                 :         {
  731 fujii                    2098 CBC          26 :             while ((ft_info = hash_seq_search(&seq)) != NULL)
                               2099                 :             {
                               2100              15 :                 FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
                               2101                 : 
                               2102                 :                 /* truncate_check_rel() has checked that already */
  731 fujii                    2103 GIC          15 :                 Assert(routine->ExecForeignTruncate != NULL);
                               2104                 : 
  731 fujii                    2105 CBC          15 :                 routine->ExecForeignTruncate(ft_info->rels,
  731 fujii                    2106 ECB             :                                              behavior,
                               2107                 :                                              restart_seqs);
                               2108                 :             }
                               2109                 :         }
  731 fujii                    2110 GIC           4 :         PG_FINALLY();
  731 fujii                    2111 ECB             :         {
  731 fujii                    2112 CBC          15 :             hash_destroy(ft_htab);
  731 fujii                    2113 ECB             :         }
  731 fujii                    2114 GIC          15 :         PG_END_TRY();
                               2115                 :     }
                               2116                 : 
                               2117                 :     /*
                               2118                 :      * Restart owned sequences if we were asked to.
 4526 tgl                      2119 ECB             :      */
 4526 tgl                      2120 GIC         611 :     foreach(cell, seq_relids)
                               2121                 :     {
                               2122              18 :         Oid         seq_relid = lfirst_oid(cell);
 4526 tgl                      2123 ECB             : 
 4526 tgl                      2124 GIC          18 :         ResetSequence(seq_relid);
                               2125                 :     }
                               2126                 : 
 1828 peter_e                  2127 ECB             :     /*
                               2128                 :      * Write a WAL record to allow this set of actions to be logically
                               2129                 :      * decoded.
                               2130                 :      *
                               2131                 :      * Assemble an array of relids so we can write a single WAL record for the
                               2132                 :      * whole action.
                               2133                 :      */
  235 tgl                      2134 GNC         593 :     if (relids_logged != NIL)
                               2135                 :     {
 1828 peter_e                  2136 ECB             :         xl_heap_truncate xlrec;
 1828 peter_e                  2137 GIC          47 :         int         i = 0;
 1828 peter_e                  2138 ECB             : 
                               2139                 :         /* should only get here if wal_level >= logical */
 1828 peter_e                  2140 GIC          47 :         Assert(XLogLogicalInfoActive());
 1828 peter_e                  2141 ECB             : 
 1828 peter_e                  2142 GIC          47 :         logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
 1809 tgl                      2143 CBC         133 :         foreach(cell, relids_logged)
 1828 peter_e                  2144 GIC          86 :             logrelids[i++] = lfirst_oid(cell);
                               2145                 : 
                               2146              47 :         xlrec.dbId = MyDatabaseId;
                               2147              47 :         xlrec.nrelids = list_length(relids_logged);
 1828 peter_e                  2148 CBC          47 :         xlrec.flags = 0;
 1828 peter_e                  2149 GIC          47 :         if (behavior == DROP_CASCADE)
 1828 peter_e                  2150 CBC           1 :             xlrec.flags |= XLH_TRUNCATE_CASCADE;
 1828 peter_e                  2151 GIC          47 :         if (restart_seqs)
 1828 peter_e                  2152 CBC           3 :             xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
                               2153                 : 
 1828 peter_e                  2154 GIC          47 :         XLogBeginInsert();
                               2155              47 :         XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
                               2156              47 :         XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
                               2157                 : 
 1828 peter_e                  2158 CBC          47 :         XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
                               2159                 : 
                               2160              47 :         (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
                               2161                 :     }
 1828 peter_e                  2162 ECB             : 
                               2163                 :     /*
                               2164                 :      * Process all AFTER STATEMENT TRUNCATE triggers.
                               2165                 :      */
 5490 tgl                      2166 GIC         593 :     resultRelInfo = resultRelInfos;
                               2167            2127 :     foreach(cell, rels)
                               2168                 :     {
                               2169                 :         UserContext ucxt;
                               2170                 : 
    5 rhaas                    2171 GNC        1534 :         if (run_as_table_owner)
                               2172              33 :             SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
                               2173                 :                                   &ucxt);
 5490 tgl                      2174 GIC        1534 :         ExecASTruncateTriggers(estate, resultRelInfo);
    5 rhaas                    2175 GNC        1534 :         if (run_as_table_owner)
                               2176              33 :             RestoreUserContext(&ucxt);
 5490 tgl                      2177 GIC        1534 :         resultRelInfo++;
                               2178                 :     }
 5490 tgl                      2179 ECB             : 
                               2180                 :     /* Handle queued AFTER triggers */
 5490 tgl                      2181 GIC         593 :     AfterTriggerEndQuery(estate);
 5490 tgl                      2182 ECB             : 
                               2183                 :     /* We can clean up the EState now */
 5490 tgl                      2184 GIC         593 :     FreeExecutorState(estate);
 5487 tgl                      2185 ECB             : 
                               2186                 :     /*
 1828 peter_e                  2187                 :      * Close any rels opened by CASCADE (can't do this while EState still
                               2188                 :      * holds refs)
                               2189                 :      */
 1828 peter_e                  2190 GIC         593 :     rels = list_difference_ptr(rels, explicit_rels);
 5487 tgl                      2191 CBC         640 :     foreach(cell, rels)
 5487 tgl                      2192 ECB             :     {
 5487 tgl                      2193 CBC          47 :         Relation    rel = (Relation) lfirst(cell);
 5487 tgl                      2194 ECB             : 
 1539 andres                   2195 CBC          47 :         table_close(rel, NoLock);
 5487 tgl                      2196 ECB             :     }
 7653 tgl                      2197 CBC         593 : }
                               2198                 : 
 6246 tgl                      2199 ECB             : /*
 1703 michael                  2200                 :  * Check that a given relation is safe to truncate.  Subroutine for
                               2201                 :  * ExecuteTruncate() and RangeVarCallbackForTruncate().
                               2202                 :  */
 6246 tgl                      2203                 : static void
 1703 michael                  2204 GIC        1670 : truncate_check_rel(Oid relid, Form_pg_class reltuple)
 6246 tgl                      2205 ECB             : {
 1703 michael                  2206 GIC        1670 :     char       *relname = NameStr(reltuple->relname);
                               2207                 : 
                               2208                 :     /*
                               2209                 :      * Only allow truncate on regular tables, foreign tables using foreign
                               2210                 :      * data wrappers supporting TRUNCATE and partitioned tables (although, the
  731 fujii                    2211 ECB             :      * latter are only being included here for the following checks; no
                               2212                 :      * physical truncation will occur in their case.).
                               2213                 :      */
  731 fujii                    2214 GIC        1670 :     if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
                               2215                 :     {
  731 fujii                    2216 CBC          18 :         Oid         serverid = GetForeignServerIdByRelId(relid);
                               2217              18 :         FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
                               2218                 : 
                               2219              18 :         if (!fdwroutine->ExecForeignTruncate)
                               2220               1 :             ereport(ERROR,
  731 fujii                    2221 ECB             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2222                 :                      errmsg("cannot truncate foreign table \"%s\"",
                               2223                 :                             relname)));
                               2224                 :     }
  731 fujii                    2225 GIC        1652 :     else if (reltuple->relkind != RELKIND_RELATION &&
  731 fujii                    2226 CBC         330 :              reltuple->relkind != RELKIND_PARTITIONED_TABLE)
 6246 tgl                      2227 UIC           0 :         ereport(ERROR,
                               2228                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 1703 michael                  2229 ECB             :                  errmsg("\"%s\" is not a table", relname)));
                               2230                 : 
                               2231                 :     /*
                               2232                 :      * Most system catalogs can't be truncated at all, or at least not unless
                               2233                 :      * allow_system_table_mods=on. As an exception, however, we allow
                               2234                 :      * pg_largeobject to be truncated as part of pg_upgrade, because we need
  255 rhaas                    2235                 :      * to change its relfilenode to match the old cluster, and allowing a
                               2236                 :      * TRUNCATE command to be executed is the easiest way of doing that.
                               2237                 :      */
  255 rhaas                    2238 CBC        1669 :     if (!allowSystemTableMods && IsSystemClass(relid, reltuple)
  255 rhaas                    2239 GIC           7 :         && (!IsBinaryUpgrade || relid != LargeObjectRelationId))
 6246 tgl                      2240 CBC           1 :         ereport(ERROR,
                               2241                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 6246 tgl                      2242 ECB             :                  errmsg("permission denied: \"%s\" is a system catalog",
                               2243                 :                         relname)));
                               2244                 : 
 1233 mail                     2245 GIC        1668 :     InvokeObjectTruncateHook(relid);
 1703 michael                  2246            1668 : }
                               2247                 : 
                               2248                 : /*
 1164 fujii                    2249 ECB             :  * Check that current user has the permission to truncate given relation.
                               2250                 :  */
                               2251                 : static void
 1164 fujii                    2252 GIC         854 : truncate_check_perms(Oid relid, Form_pg_class reltuple)
                               2253                 : {
                               2254             854 :     char       *relname = NameStr(reltuple->relname);
                               2255                 :     AclResult   aclresult;
                               2256                 : 
                               2257                 :     /* Permissions checks */
                               2258             854 :     aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
 1164 fujii                    2259 CBC         854 :     if (aclresult != ACLCHECK_OK)
 1164 fujii                    2260 GIC          16 :         aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
 1164 fujii                    2261 ECB             :                        relname);
 1164 fujii                    2262 CBC         838 : }
                               2263                 : 
 1703 michael                  2264 ECB             : /*
                               2265                 :  * Set of extra sanity checks to check if a given relation is safe to
                               2266                 :  * truncate.  This is split with truncate_check_rel() as
                               2267                 :  * RangeVarCallbackForTruncate() cannot open a Relation yet.
                               2268                 :  */
                               2269                 : static void
 1703 michael                  2270 CBC        1584 : truncate_check_activity(Relation rel)
 1703 michael                  2271 ECB             : {
 6246 tgl                      2272 EUB             :     /*
                               2273                 :      * Don't allow truncate on temp tables of other backends ... their local
                               2274                 :      * buffer manager is not going to cope.
                               2275                 :      */
 5122 tgl                      2276 GIC        1584 :     if (RELATION_IS_OTHER_TEMP(rel))
 6246 tgl                      2277 UIC           0 :         ereport(ERROR,
                               2278                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2279                 :                  errmsg("cannot truncate temporary tables of other sessions")));
                               2280                 : 
                               2281                 :     /*
                               2282                 :      * Also check for active uses of the relation in the current transaction,
 5548 tgl                      2283 ECB             :      * including open scans and pending AFTER trigger events.
 5576                          2284                 :      */
 5548 tgl                      2285 CBC        1584 :     CheckTableNotInUse(rel, "TRUNCATE");
 6246 tgl                      2286 GIC        1584 : }
                               2287                 : 
                               2288                 : /*
                               2289                 :  * storage_name
 4790 bruce                    2290 ECB             :  *    returns the name corresponding to a typstorage/attstorage enum value
 4927 andrew                   2291                 :  */
                               2292                 : static const char *
 4927 andrew                   2293 GIC          12 : storage_name(char c)
                               2294                 : {
                               2295              12 :     switch (c)
                               2296                 :     {
 1131 tgl                      2297 LBC           0 :         case TYPSTORAGE_PLAIN:
 4926 tgl                      2298 UIC           0 :             return "PLAIN";
 1131 tgl                      2299 LBC           0 :         case TYPSTORAGE_EXTERNAL:
 4926 tgl                      2300 UIC           0 :             return "EXTERNAL";
 1131 tgl                      2301 GIC           6 :         case TYPSTORAGE_EXTENDED:
                               2302               6 :             return "EXTENDED";
 1131 tgl                      2303 CBC           6 :         case TYPSTORAGE_MAIN:
                               2304               6 :             return "MAIN";
 4926 tgl                      2305 LBC           0 :         default:
 4926 tgl                      2306 UIC           0 :             return "???";
 4927 andrew                   2307 ECB             :     }
                               2308                 : }
                               2309                 : 
                               2310                 : /*----------
                               2311                 :  * MergeAttributes
                               2312                 :  *      Returns new schema given initial schema and superclasses.
                               2313                 :  *
                               2314                 :  * Input arguments:
 7653 tgl                      2315                 :  * 'schema' is the column/attribute definition for the table. (It's a list
                               2316                 :  *      of ColumnDef's.) It is destructively changed.
                               2317                 :  * 'supers' is a list of OIDs of parent relations, already locked by caller.
                               2318                 :  * 'relpersistence' is the persistence type of the table.
                               2319                 :  * 'is_partition' tells if the table is a partition.
                               2320                 :  *
                               2321                 :  * Output arguments:
 7653 tgl                      2322 EUB             :  * 'supconstr' receives a list of constraints belonging to the parents,
                               2323                 :  *      updated as necessary to be valid for the child.
                               2324                 :  * 'nnconstraints' receives a list of CookedConstraints that corresponds to
                               2325                 :  *      constraints coming from inheritance parents.
                               2326                 :  *
                               2327                 :  * Return value:
                               2328                 :  * Completed schema list.
                               2329                 :  *
                               2330                 :  * Notes:
                               2331                 :  *    The order in which the attributes are inherited is very important.
 7653 tgl                      2332 ECB             :  *    Intuitively, the inherited attributes should come first. If a table
                               2333                 :  *    inherits from multiple parents, the order of those attributes are
                               2334                 :  *    according to the order of the parents specified in CREATE TABLE.
                               2335                 :  *
                               2336                 :  *    Here's an example:
                               2337                 :  *
                               2338                 :  *      create table person (name text, age int4, location point);
                               2339                 :  *      create table emp (salary int4, manager text) inherits(person);
                               2340                 :  *      create table student (gpa float8) inherits (person);
                               2341                 :  *      create table stud_emp (percent int4) inherits (emp, student);
                               2342                 :  *
                               2343                 :  *    The order of the attributes of stud_emp is:
 7653 tgl                      2344 EUB             :  *
                               2345                 :  *                          person {1:name, 2:age, 3:location}
                               2346                 :  *                          /    \
                               2347                 :  *             {6:gpa}  student   emp {4:salary, 5:manager}
 7653 tgl                      2348 ECB             :  *                          \    /
                               2349                 :  *                         stud_emp {7:percent}
                               2350                 :  *
                               2351                 :  *     If the same attribute name appears multiple times, then it appears
 7653 tgl                      2352 EUB             :  *     in the result table in the proper location for its first appearance.
                               2353                 :  *
                               2354                 :  *     Constraints (including NOT NULL constraints) for the child table
                               2355                 :  *     are the union of all relevant constraints, from both the child schema
                               2356                 :  *     and parent tables.  In addition, in legacy inheritance, each column that
                               2357                 :  *     appears in a primary key in any of the parents also gets a NOT NULL
                               2358                 :  *     constraint (partitioning doesn't need this, because the PK itself gets
                               2359                 :  *     inherited.)
                               2360                 :  *
                               2361                 :  *     The default value for a child column is defined as:
                               2362                 :  *      (1) If the child schema specifies a default, that value is used.
                               2363                 :  *      (2) If neither the child nor any parent specifies a default, then
                               2364                 :  *          the column will not have a default.
                               2365                 :  *      (3) If conflicting defaults are inherited from different parents
                               2366                 :  *          (and not overridden by the child), an error is raised.
                               2367                 :  *      (4) Otherwise the inherited default is used.
                               2368                 :  *
                               2369                 :  *      Note that the default-value infrastructure is used for generated
                               2370                 :  *      columns' expressions too, so most of the preceding paragraph applies
                               2371                 :  *      to generation expressions too.  We insist that a child column be
                               2372                 :  *      generated if and only if its parent(s) are, but it need not have
                               2373                 :  *      the same generation expression.
                               2374                 :  *----------
                               2375                 :  */
                               2376                 : static List *
 4500 rhaas                    2377 GIC       62853 : MergeAttributes(List *schema, List *supers, char relpersistence,
                               2378                 :                 bool is_partition, List **supconstr, List **supnotnulls)
                               2379                 : {
 7653 tgl                      2380           62853 :     List       *inhSchema = NIL;
                               2381           62853 :     List       *constraints = NIL;
    2 alvherre                 2382 GNC       62853 :     List       *nnconstraints = NIL;
 7653 tgl                      2383 GIC       62853 :     bool        have_bogus_defaults = false;
                               2384                 :     int         child_attno;
                               2385                 :     static Node bogus_marker = {0}; /* marks conflicting defaults */
 2314 rhaas                    2386           62853 :     List       *saved_schema = NIL;
                               2387                 :     ListCell   *entry;
                               2388                 : 
                               2389                 :     /*
                               2390                 :      * Check for and reject tables with too many columns. We perform this
                               2391                 :      * check relatively early for two reasons: (a) we don't run the risk of
                               2392                 :      * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
                               2393                 :      * okay if we're processing <= 1600 columns, but could take minutes to
                               2394                 :      * execute if the user attempts to create a table with hundreds of
                               2395                 :      * thousands of columns.
                               2396                 :      *
                               2397                 :      * Note that we also need to check that we do not exceed this figure after
                               2398                 :      * including columns from inherited relations.
                               2399                 :      */
 6718 neilc                    2400           62853 :     if (list_length(schema) > MaxHeapAttributeNumber)
 6718 neilc                    2401 UIC           0 :         ereport(ERROR,
                               2402                 :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
                               2403                 :                  errmsg("tables can have at most %d columns",
                               2404                 :                         MaxHeapAttributeNumber)));
                               2405                 : 
                               2406                 :     /*
                               2407                 :      * Check for duplicate names in the explicit list of attributes.
                               2408                 :      *
                               2409                 :      * Although we might consider merging such entries in the same way that we
                               2410                 :      * handle name conflicts for inherited attributes, it seems to make more
                               2411                 :      * sense to assume such conflicts are errors.
                               2412                 :      *
                               2413                 :      * We don't use foreach() here because we have two nested loops over the
                               2414                 :      * schema list, with possible element deletions in the inner one.  If we
                               2415                 :      * used foreach_delete_current() it could only fix up the state of one of
                               2416                 :      * the loops, so it seems cleaner to use looping over list indexes for
                               2417                 :      * both loops.  Note that any deletion will happen beyond where the outer
                               2418                 :      * loop is, so its index never needs adjustment.
                               2419                 :      */
 1364 tgl                      2420 GIC      541245 :     for (int coldefpos = 0; coldefpos < list_length(schema); coldefpos++)
                               2421                 :     {
                               2422          478404 :         ColumnDef  *coldef = list_nth_node(ColumnDef, schema, coldefpos);
                               2423                 : 
 1613 alvherre                 2424          478404 :         if (!is_partition && coldef->typeName == NULL)
                               2425                 :         {
                               2426                 :             /*
                               2427                 :              * Typed table column option that does not belong to a column from
                               2428                 :              * the type.  This works because the columns from the type come
                               2429                 :              * first in the list.  (We omit this check for partition column
                               2430                 :              * lists; those are processed separately below.)
                               2431                 :              */
 4819 peter_e                  2432 CBC           3 :             ereport(ERROR,
                               2433                 :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               2434                 :                      errmsg("column \"%s\" does not exist",
 4819 peter_e                  2435 ECB             :                             coldef->colname)));
 1613 alvherre                 2436                 :         }
 7678 tgl                      2437                 : 
 1364                          2438                 :         /* restpos scans all entries beyond coldef; incr is in loop body */
 1364 tgl                      2439 GIC     6750509 :         for (int restpos = coldefpos + 1; restpos < list_length(schema);)
                               2440                 :         {
 1364 tgl                      2441 CBC     6272117 :             ColumnDef  *restdef = list_nth_node(ColumnDef, schema, restpos);
                               2442                 : 
 7653 tgl                      2443 GIC     6272117 :             if (strcmp(coldef->colname, restdef->colname) == 0)
                               2444                 :             {
 4819 peter_e                  2445              25 :                 if (coldef->is_from_type)
                               2446                 :                 {
                               2447                 :                     /*
                               2448                 :                      * merge the column options into the column from the type
                               2449                 :                      */
                               2450              16 :                     coldef->is_not_null = restdef->is_not_null;
                               2451              16 :                     coldef->raw_default = restdef->raw_default;
                               2452              16 :                     coldef->cooked_default = restdef->cooked_default;
                               2453              16 :                     coldef->constraints = restdef->constraints;
                               2454              16 :                     coldef->is_from_type = false;
 1364 tgl                      2455 CBC          16 :                     schema = list_delete_nth_cell(schema, restpos);
 4819 peter_e                  2456 EUB             :                 }
                               2457                 :                 else
 4819 peter_e                  2458 GIC           9 :                     ereport(ERROR,
                               2459                 :                             (errcode(ERRCODE_DUPLICATE_COLUMN),
                               2460                 :                              errmsg("column \"%s\" specified more than once",
                               2461                 :                                     coldef->colname)));
                               2462                 :             }
                               2463                 :             else
 1364 tgl                      2464         6272092 :                 restpos++;
                               2465                 :         }
                               2466                 :     }
                               2467                 : 
                               2468                 :     /*
                               2469                 :      * In case of a partition, there are no new column definitions, only dummy
                               2470                 :      * ColumnDefs created for column constraints.  Set them aside for now and
                               2471                 :      * process them at the end.
                               2472                 :      */
 1613 alvherre                 2473           62841 :     if (is_partition)
                               2474                 :     {
 1613 alvherre                 2475 CBC        3602 :         saved_schema = schema;
 1613 alvherre                 2476 GIC        3602 :         schema = NIL;
 1613 alvherre                 2477 ECB             :     }
                               2478                 : 
 7678 tgl                      2479                 :     /*
                               2480                 :      * Scan the parents left-to-right, and merge their attributes to form a
                               2481                 :      * list of inherited attributes (inhSchema).  Also check to see if we need
                               2482                 :      * to inherit an OID column.
                               2483                 :      */
 7653 tgl                      2484 GIC       62841 :     child_attno = 0;
                               2485           67277 :     foreach(entry, supers)
                               2486                 :     {
 1574 alvherre                 2487 CBC        4472 :         Oid         parent = lfirst_oid(entry);
                               2488                 :         Relation    relation;
                               2489                 :         TupleDesc   tupleDesc;
                               2490                 :         TupleConstr *constr;
                               2491                 :         AttrMap    *newattmap;
                               2492                 :         List       *inherited_defaults;
                               2493                 :         List       *cols_with_defaults;
                               2494                 :         List       *nnconstrs;
 7653 tgl                      2495 ECB             :         AttrNumber  parent_attno;
                               2496                 :         ListCell   *lc1;
  961                          2497                 :         ListCell   *lc2;
                               2498                 :         Bitmapset  *pkattrs;
    2 alvherre                 2499 GNC        4472 :         Bitmapset  *nncols = NULL;
                               2500                 : 
                               2501                 : 
 1574 alvherre                 2502 ECB             :         /* caller already got lock */
 1539 andres                   2503 GIC        4472 :         relation = table_open(parent, NoLock);
 2314 rhaas                    2504 ECB             : 
                               2505                 :         /*
                               2506                 :          * Check for active uses of the parent partitioned table in the
                               2507                 :          * current transaction, such as being used in some manner by an
                               2508                 :          * enclosing command.
 1616 michael                  2509                 :          */
 1616 michael                  2510 CBC        4472 :         if (is_partition)
                               2511            3602 :             CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
 1616 michael                  2512 ECB             : 
 2314 rhaas                    2513                 :         /*
 2308                          2514                 :          * We do not allow partitioned tables and partitions to participate in
                               2515                 :          * regular inheritance.
                               2516                 :          */
 2314 rhaas                    2517 CBC        4469 :         if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
 2314 rhaas                    2518 GIC        3596 :             !is_partition)
                               2519               3 :             ereport(ERROR,
                               2520                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2521                 :                      errmsg("cannot inherit from partitioned table \"%s\"",
                               2522                 :                             RelationGetRelationName(relation))));
 2314 rhaas                    2523 CBC        4466 :         if (relation->rd_rel->relispartition && !is_partition)
 2314 rhaas                    2524 GIC           3 :             ereport(ERROR,
                               2525                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2526                 :                      errmsg("cannot inherit from partition \"%s\"",
                               2527                 :                             RelationGetRelationName(relation))));
                               2528                 : 
 2940 tgl                      2529            4463 :         if (relation->rd_rel->relkind != RELKIND_RELATION &&
 2314 rhaas                    2530            3603 :             relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
                               2531            3593 :             relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 7203 tgl                      2532 LBC           0 :             ereport(ERROR,
                               2533                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 2940 tgl                      2534 ECB             :                      errmsg("inherited relation \"%s\" is not a table or foreign table",
 1574 alvherre                 2535                 :                             RelationGetRelationName(relation))));
                               2536                 : 
                               2537                 :         /*
                               2538                 :          * If the parent is permanent, so must be all of its partitions.  Note
                               2539                 :          * that inheritance allows that case.
                               2540                 :          */
 1754 michael                  2541 GIC        4463 :         if (is_partition &&
                               2542            3599 :             relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
 1754 michael                  2543 ECB             :             relpersistence == RELPERSISTENCE_TEMP)
 1754 michael                  2544 CBC           3 :             ereport(ERROR,
                               2545                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 1754 michael                  2546 ECB             :                      errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
                               2547                 :                             RelationGetRelationName(relation))));
                               2548                 : 
                               2549                 :         /* Permanent rels cannot inherit from temporary ones */
 3765 tgl                      2550 GIC        4460 :         if (relpersistence != RELPERSISTENCE_TEMP &&
                               2551            4289 :             relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
 7203                          2552              12 :             ereport(ERROR,
                               2553                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2554                 :                      errmsg(!is_partition
                               2555                 :                             ? "cannot inherit from temporary relation \"%s\""
                               2556                 :                             : "cannot create a permanent relation as partition of temporary relation \"%s\"",
                               2557                 :                             RelationGetRelationName(relation))));
 7678 tgl                      2558 ECB             : 
                               2559                 :         /* If existing rel is temp, it must belong to this session */
 3765 tgl                      2560 GIC        4448 :         if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                               2561             147 :             !relation->rd_islocaltemp)
 3765 tgl                      2562 LBC           0 :             ereport(ERROR,
                               2563                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2564                 :                      errmsg(!is_partition
                               2565                 :                             ? "cannot inherit from temporary relation of another session"
                               2566                 :                             : "cannot create as partition of temporary relation of another session")));
                               2567                 : 
                               2568                 :         /*
 7653 tgl                      2569 ECB             :          * We should have an UNDER permission flag for this, but for now,
                               2570                 :          * demand that creator of a child table own the parent.
                               2571                 :          */
  147 peter                    2572 GNC        4448 :         if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), GetUserId()))
 1954 peter_e                  2573 UIC           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(relation->rd_rel->relkind),
 7652 tgl                      2574               0 :                            RelationGetRelationName(relation));
                               2575                 : 
 7653 tgl                      2576 CBC        4448 :         tupleDesc = RelationGetDescr(relation);
                               2577            4448 :         constr = tupleDesc->constr;
 7678 tgl                      2578 ECB             : 
                               2579                 :         /*
                               2580                 :          * newattmap->attnums[] will contain the child-table attribute numbers
                               2581                 :          * for the attributes of this parent table.  (They are not the same
 1208 michael                  2582                 :          * for parents after the first one, nor if we have dropped columns.)
 7653 tgl                      2583                 :          */
 1208 michael                  2584 GIC        4448 :         newattmap = make_attrmap(tupleDesc->natts);
                               2585                 : 
                               2586                 :         /* We can't process inherited defaults until newattmap is complete. */
  961 tgl                      2587            4448 :         inherited_defaults = cols_with_defaults = NIL;
  961 tgl                      2588 ECB             : 
                               2589                 :         /*
                               2590                 :          * All columns that are part of the parent's primary key need to be
                               2591                 :          * NOT NULL; if partition just the attnotnull bit, otherwise a full
                               2592                 :          * constraint (if they don't have one already).  Also, we request
                               2593                 :          * attnotnull on columns that have a NOT NULL constraint that's not
                               2594                 :          * marked NO INHERIT.
                               2595                 :          */
    2 alvherre                 2596 GNC        4448 :         pkattrs = RelationGetIndexAttrBitmap(relation,
                               2597                 :                                              INDEX_ATTR_BITMAP_PRIMARY_KEY);
                               2598            4448 :         nnconstrs = RelationGetNotNullConstraints(relation, true);
                               2599            4749 :         foreach(lc1, nnconstrs)
                               2600             301 :             nncols = bms_add_member(nncols,
                               2601             301 :                                     ((CookedConstraint *) lfirst(lc1))->attnum);
                               2602                 : 
 7653 tgl                      2603 CBC       13432 :         for (parent_attno = 1; parent_attno <= tupleDesc->natts;
                               2604            8984 :              parent_attno++)
 7653 tgl                      2605 EUB             :         {
 2058 andres                   2606 GIC        8996 :             Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
                               2607                 :                                                         parent_attno - 1);
 7653 tgl                      2608            8996 :             char       *attributeName = NameStr(attribute->attname);
                               2609                 :             int         exist_attno;
                               2610                 :             ColumnDef  *def;
                               2611                 : 
                               2612                 :             /*
                               2613                 :              * Ignore dropped columns in the parent.
 7555 tgl                      2614 ECB             :              */
 7555 tgl                      2615 CBC        8996 :             if (attribute->attisdropped)
 1208 michael                  2616 GIC          96 :                 continue;       /* leave newattmap->attnums entry as zero */
 7555 tgl                      2617 ECB             : 
                               2618                 :             /*
                               2619                 :              * Does it conflict with some previously inherited column?
                               2620                 :              */
 7653 tgl                      2621 GIC        8900 :             exist_attno = findAttrByName(attributeName, inhSchema);
                               2622            8900 :             if (exist_attno > 0)
 7653 tgl                      2623 ECB             :             {
 5624 bruce                    2624                 :                 Oid         defTypeId;
                               2625                 :                 int32       deftypmod;
                               2626                 :                 Oid         defCollId;
                               2627                 : 
                               2628                 :                 /*
                               2629                 :                  * Yes, try to merge the two column definitions.
                               2630                 :                  */
 7203 tgl                      2631 GIC         112 :                 ereport(NOTICE,
 7136 peter_e                  2632 ECB             :                         (errmsg("merging multiple inherited definitions of column \"%s\"",
 7203 tgl                      2633                 :                                 attributeName)));
 6892 neilc                    2634 GBC         112 :                 def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
                               2635                 : 
                               2636                 :                 /*
                               2637                 :                  * Must have the same type and typmod
                               2638                 :                  */
 4414 tgl                      2639 GIC         112 :                 typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
 5944                          2640             112 :                 if (defTypeId != attribute->atttypid ||
                               2641             112 :                     deftypmod != attribute->atttypmod)
 7203 tgl                      2642 UIC           0 :                     ereport(ERROR,
                               2643                 :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
                               2644                 :                              errmsg("inherited column \"%s\" has a type conflict",
                               2645                 :                                     attributeName),
                               2646                 :                              errdetail("%s versus %s",
                               2647                 :                                        format_type_with_typemod(defTypeId,
 2661 tgl                      2648 ECB             :                                                                 deftypmod),
 2118 tgl                      2649 EUB             :                                        format_type_with_typemod(attribute->atttypid,
                               2650                 :                                                                 attribute->atttypmod))));
                               2651                 : 
                               2652                 :                 /*
                               2653                 :                  * Must have the same collation
                               2654                 :                  */
 4414 tgl                      2655 GIC         112 :                 defCollId = GetColumnDefCollation(NULL, def, defTypeId);
 4443 peter_e                  2656 CBC         112 :                 if (defCollId != attribute->attcollation)
 4443 peter_e                  2657 LBC           0 :                     ereport(ERROR,
                               2658                 :                             (errcode(ERRCODE_COLLATION_MISMATCH),
                               2659                 :                              errmsg("inherited column \"%s\" has a collation conflict",
                               2660                 :                                     attributeName),
                               2661                 :                              errdetail("\"%s\" versus \"%s\"",
                               2662                 :                                        get_collation_name(defCollId),
                               2663                 :                                        get_collation_name(attribute->attcollation))));
 4927 andrew                   2664 ECB             : 
                               2665                 :                 /*
                               2666                 :                  * Copy/check storage parameter
                               2667                 :                  */
 4927 andrew                   2668 GIC         112 :                 if (def->storage == 0)
 4927 andrew                   2669 LBC           0 :                     def->storage = attribute->attstorage;
 4927 andrew                   2670 GIC         112 :                 else if (def->storage != attribute->attstorage)
                               2671               3 :                     ereport(ERROR,
                               2672                 :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
                               2673                 :                              errmsg("inherited column \"%s\" has a storage parameter conflict",
                               2674                 :                                     attributeName),
                               2675                 :                              errdetail("%s versus %s",
                               2676                 :                                        storage_name(def->storage),
                               2677                 :                                        storage_name(attribute->attstorage))));
 4927 andrew                   2678 ECB             : 
                               2679                 :                 /*
                               2680                 :                  * Copy/check compression parameter
                               2681                 :                  */
  751 rhaas                    2682 CBC         109 :                 if (CompressionMethodIsValid(attribute->attcompression))
  751 rhaas                    2683 ECB             :                 {
                               2684                 :                     const char *compression =
  697 tgl                      2685 CBC           3 :                     GetCompressionMethodName(attribute->attcompression);
                               2686                 : 
  751 rhaas                    2687               3 :                     if (def->compression == NULL)
  751 rhaas                    2688 LBC           0 :                         def->compression = pstrdup(compression);
  751 rhaas                    2689 GIC           3 :                     else if (strcmp(def->compression, compression) != 0)
  751 rhaas                    2690 CBC           3 :                         ereport(ERROR,
                               2691                 :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
  751 rhaas                    2692 ECB             :                                  errmsg("column \"%s\" has a compression method conflict",
                               2693                 :                                         attributeName),
                               2694                 :                                  errdetail("%s versus %s", def->compression, compression)));
                               2695                 :                 }
                               2696                 : 
                               2697                 :                 /*
                               2698                 :                  * In regular inheritance, columns in the parent's primary key
                               2699                 :                  * get an extra CHECK (NOT NULL) constraint.  Partitioning
                               2700                 :                  * doesn't need this, because the PK itself is going to be
                               2701                 :                  * cloned to the partition.
                               2702                 :                  */
    2 alvherre                 2703 GNC         212 :                 if (!is_partition &&
                               2704             106 :                     bms_is_member(parent_attno - FirstLowInvalidHeapAttributeNumber,
                               2705                 :                                   pkattrs))
                               2706                 :                 {
                               2707                 :                     CookedConstraint *nn;
                               2708                 : 
    2 alvherre                 2709 UNC           0 :                     nn = palloc(sizeof(CookedConstraint));
                               2710               0 :                     nn->contype = CONSTR_NOTNULL;
                               2711               0 :                     nn->conoid = InvalidOid;
                               2712               0 :                     nn->name = NULL;
                               2713               0 :                     nn->attnum = exist_attno;
                               2714               0 :                     nn->expr = NULL;
                               2715               0 :                     nn->skip_validation = false;
                               2716               0 :                     nn->is_local = false;
                               2717               0 :                     nn->inhcount = 1;
                               2718               0 :                     nn->is_no_inherit = false;
                               2719                 : 
                               2720               0 :                     nnconstraints = lappend(nnconstraints, nn);
                               2721                 :                 }
                               2722                 : 
                               2723                 :                 /*
                               2724                 :                  * mark attnotnull if parent has it and it's not NO INHERIT
                               2725                 :                  */
    2 alvherre                 2726 GNC         202 :                 if (bms_is_member(parent_attno, nncols) ||
                               2727              96 :                     bms_is_member(parent_attno - FirstLowInvalidHeapAttributeNumber,
                               2728                 :                                   pkattrs))
                               2729              10 :                     def->is_not_null = true;
                               2730                 : 
                               2731                 :                 /*
                               2732                 :                  * Check for GENERATED conflicts
                               2733                 :                  */
 1471 peter                    2734 GIC         106 :                 if (def->generated != attribute->attgenerated)
 1471 peter                    2735 CBC           6 :                     ereport(ERROR,
 1471 peter                    2736 ECB             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
                               2737                 :                              errmsg("inherited column \"%s\" has a generation conflict",
                               2738                 :                                     attributeName)));
                               2739                 : 
                               2740                 :                 /*
                               2741                 :                  * Default and other constraints are handled below
                               2742                 :                  */
                               2743                 : 
   32 peter                    2744 GNC         100 :                 def->inhcount++;
   12                          2745             100 :                 if (def->inhcount < 0)
   12 peter                    2746 UNC           0 :                     ereport(ERROR,
                               2747                 :                             errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               2748                 :                             errmsg("too many inheritance parents"));
                               2749                 : 
   32 peter                    2750 GNC         100 :                 newattmap->attnums[parent_attno - 1] = exist_attno;
                               2751                 :             }
                               2752                 :             else
                               2753                 :             {
                               2754                 :                 /*
                               2755                 :                  * No, create a new inherited column
                               2756                 :                  */
 7653 tgl                      2757 CBC        8788 :                 def = makeNode(ColumnDef);
 7653 tgl                      2758 GIC        8788 :                 def->colname = pstrdup(attributeName);
 5015 peter_e                  2759            8788 :                 def->typeName = makeTypeNameFromOid(attribute->atttypid,
 4414 tgl                      2760 ECB             :                                                     attribute->atttypmod);
 7504 tgl                      2761 GIC        8788 :                 def->inhcount = 1;
                               2762            8788 :                 def->is_local = false;
                               2763                 :                 /* mark attnotnull if parent has it and it's not NO INHERIT */
    2 alvherre                 2764 GNC       17285 :                 if (bms_is_member(parent_attno, nncols) ||
                               2765            8497 :                     bms_is_member(parent_attno - FirstLowInvalidHeapAttributeNumber,
                               2766                 :                                   pkattrs))
                               2767             831 :                     def->is_not_null = true;
 4414 tgl                      2768 GIC        8788 :                 def->is_from_type = false;
 4926 tgl                      2769 CBC        8788 :                 def->storage = attribute->attstorage;
 7653                          2770            8788 :                 def->raw_default = NULL;
                               2771            8788 :                 def->cooked_default = NULL;
 1471 peter                    2772 GBC        8788 :                 def->generated = attribute->attgenerated;
 4414 tgl                      2773 GIC        8788 :                 def->collClause = NULL;
                               2774            8788 :                 def->collOid = attribute->attcollation;
 7653                          2775            8788 :                 def->constraints = NIL;
 3426                          2776            8788 :                 def->location = -1;
  751 rhaas                    2777            8788 :                 if (CompressionMethodIsValid(attribute->attcompression))
  686 tgl                      2778               9 :                     def->compression =
                               2779               9 :                         pstrdup(GetCompressionMethodName(attribute->attcompression));
                               2780                 :                 else
  751 rhaas                    2781            8779 :                     def->compression = NULL;
 7653 tgl                      2782            8788 :                 inhSchema = lappend(inhSchema, def);
 1208 michael                  2783            8788 :                 newattmap->attnums[parent_attno - 1] = ++child_attno;
                               2784                 : 
                               2785                 :                 /*
                               2786                 :                  * In regular inheritance, columns in the parent's primary key
                               2787                 :                  * get an extra NOT NULL constraint.  Partitioning doesn't
                               2788                 :                  * need this, because the PK itself is going to be cloned to
                               2789                 :                  * the partition.
                               2790                 :                  */
    2 alvherre                 2791 GNC       10386 :                 if (!is_partition &&
                               2792            1598 :                     bms_is_member(parent_attno -
                               2793                 :                                   FirstLowInvalidHeapAttributeNumber,
                               2794                 :                                   pkattrs))
                               2795                 :                 {
                               2796                 :                     CookedConstraint *nn;
                               2797                 : 
                               2798              95 :                     nn = palloc(sizeof(CookedConstraint));
                               2799              95 :                     nn->contype = CONSTR_NOTNULL;
                               2800              95 :                     nn->conoid = InvalidOid;
                               2801              95 :                     nn->name = NULL;
                               2802              95 :                     nn->attnum = newattmap->attnums[parent_attno - 1];
                               2803              95 :                     nn->expr = NULL;
                               2804              95 :                     nn->skip_validation = false;
                               2805              95 :                     nn->is_local = false;
                               2806              95 :                     nn->inhcount = 1;
                               2807              95 :                     nn->is_no_inherit = false;
                               2808                 : 
                               2809              95 :                     nnconstraints = lappend(nnconstraints, nn);
                               2810                 :                 }
                               2811                 :             }
 7678 tgl                      2812 ECB             : 
 7653                          2813                 :             /*
                               2814                 :              * Locate default/generation expression if any
                               2815                 :              */
 7653 tgl                      2816 GIC        8888 :             if (attribute->atthasdef)
                               2817                 :             {
 4933                          2818             260 :                 Node       *this_default = NULL;
                               2819                 : 
                               2820                 :                 /* Find default in constraint structure */
  733                          2821             260 :                 if (constr != NULL)
                               2822                 :                 {
                               2823             260 :                     AttrDefault *attrdef = constr->defval;
                               2824                 : 
  733 tgl                      2825 CBC         284 :                     for (int i = 0; i < constr->num_defval; i++)
 7653 tgl                      2826 EUB             :                     {
  733 tgl                      2827 CBC         284 :                         if (attrdef[i].adnum == parent_attno)
  733 tgl                      2828 ECB             :                         {
  733 tgl                      2829 GIC         260 :                             this_default = stringToNode(attrdef[i].adbin);
                               2830             260 :                             break;
                               2831                 :                         }
                               2832                 :                     }
                               2833                 :                 }
                               2834             260 :                 if (this_default == NULL)
  733 tgl                      2835 UIC           0 :                     elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
                               2836                 :                          parent_attno, RelationGetRelationName(relation));
                               2837                 : 
                               2838                 :                 /*
  961 tgl                      2839 ECB             :                  * If it's a GENERATED default, it might contain Vars that
                               2840                 :                  * need to be mapped to the inherited column(s)' new numbers.
                               2841                 :                  * We can't do that till newattmap is ready, so just remember
                               2842                 :                  * all the inherited default expressions for the moment.
                               2843                 :                  */
  961 tgl                      2844 CBC         260 :                 inherited_defaults = lappend(inherited_defaults, this_default);
  961 tgl                      2845 GBC         260 :                 cols_with_defaults = lappend(cols_with_defaults, def);
  961 tgl                      2846 ECB             :             }
                               2847                 :         }
                               2848                 : 
                               2849                 :         /*
                               2850                 :          * Now process any inherited default expressions, adjusting attnos
                               2851                 :          * using the completed newattmap map.
                               2852                 :          */
  961 tgl                      2853 GIC        4696 :         forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
                               2854                 :         {
                               2855             260 :             Node       *this_default = (Node *) lfirst(lc1);
                               2856             260 :             ColumnDef  *def = (ColumnDef *) lfirst(lc2);
                               2857                 :             bool        found_whole_row;
                               2858                 : 
                               2859                 :             /* Adjust Vars to match new table's column numbering */
  961 tgl                      2860 CBC         260 :             this_default = map_variable_attnos(this_default,
  961 tgl                      2861 ECB             :                                                1, 0,
                               2862                 :                                                newattmap,
                               2863                 :                                                InvalidOid, &found_whole_row);
                               2864                 : 
                               2865                 :             /*
  961 tgl                      2866 EUB             :              * For the moment we have to reject whole-row variables.  We could
                               2867                 :              * convert them, if we knew the new table's rowtype OID, but that
                               2868                 :              * hasn't been assigned yet.  (A variable could only appear in a
                               2869                 :              * generation expression, so the error message is correct.)
                               2870                 :              */
  961 tgl                      2871 GBC         260 :             if (found_whole_row)
  961 tgl                      2872 UBC           0 :                 ereport(ERROR,
  961 tgl                      2873 EUB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2874                 :                          errmsg("cannot convert whole-row table reference"),
                               2875                 :                          errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
                               2876                 :                                    def->colname,
                               2877                 :                                    RelationGetRelationName(relation))));
                               2878                 : 
                               2879                 :             /*
                               2880                 :              * If we already had a default from some prior parent, check to
                               2881                 :              * see if they are the same.  If so, no problem; if not, mark the
                               2882                 :              * column as having a bogus default.  Below, we will complain if
  961 tgl                      2883 ECB             :              * the bogus default isn't overridden by the child schema.
                               2884                 :              */
  961 tgl                      2885 GIC         260 :             Assert(def->raw_default == NULL);
  961 tgl                      2886 CBC         260 :             if (def->cooked_default == NULL)
  961 tgl                      2887 GIC         245 :                 def->cooked_default = this_default;
                               2888              15 :             else if (!equal(def->cooked_default, this_default))
                               2889                 :             {
                               2890              12 :                 def->cooked_default = &bogus_marker;
  961 tgl                      2891 CBC          12 :                 have_bogus_defaults = true;
 7653 tgl                      2892 ECB             :             }
                               2893                 :         }
                               2894                 : 
                               2895                 :         /*
                               2896                 :          * Now copy the CHECK constraints of this parent, adjusting attnos
                               2897                 :          * using the completed newattmap map.  Identically named constraints
                               2898                 :          * are merged if possible, else we throw error.
                               2899                 :          */
 7653 tgl                      2900 GIC        4436 :         if (constr && constr->num_check > 0)
 7653 tgl                      2901 ECB             :         {
 7653 tgl                      2902 CBC          98 :             ConstrCheck *check = constr->check;
 7653 tgl                      2903 EUB             :             int         i;
                               2904                 : 
 7653 tgl                      2905 GIC         211 :             for (i = 0; i < constr->num_check; i++)
                               2906                 :             {
 5448 tgl                      2907 CBC         113 :                 char       *name = check[i].ccname;
                               2908                 :                 Node       *expr;
                               2909                 :                 bool        found_whole_row;
                               2910                 : 
                               2911                 :                 /* ignore if the constraint is non-inheritable */
 4006 alvherre                 2912 GIC         113 :                 if (check[i].ccnoinherit)
 4143                          2913              21 :                     continue;
 4143 alvherre                 2914 ECB             : 
 3935 tgl                      2915                 :                 /* Adjust Vars to match new table's column numbering */
 3935 tgl                      2916 CBC          92 :                 expr = map_variable_attnos(stringToNode(check[i].ccbin),
                               2917                 :                                            1, 0,
 1208 michael                  2918 ECB             :                                            newattmap,
 2075 rhaas                    2919                 :                                            InvalidOid, &found_whole_row);
                               2920                 : 
 3935 tgl                      2921                 :                 /*
 3602 bruce                    2922                 :                  * For the moment we have to reject whole-row variables. We
                               2923                 :                  * could convert them, if we knew the new table's rowtype OID,
                               2924                 :                  * but that hasn't been assigned yet.
 3935 tgl                      2925                 :                  */
 3935 tgl                      2926 CBC          92 :                 if (found_whole_row)
 3935 tgl                      2927 LBC           0 :                     ereport(ERROR,
 3935 tgl                      2928 ECB             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 2118                          2929                 :                              errmsg("cannot convert whole-row table reference"),
 3935                          2930                 :                              errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
                               2931                 :                                        name,
                               2932                 :                                        RelationGetRelationName(relation))));
 5448                          2933                 : 
                               2934                 :                 /* check for duplicate */
 5448 tgl                      2935 CBC          92 :                 if (!MergeCheckConstraint(constraints, name, expr))
 5448 tgl                      2936 ECB             :                 {
                               2937                 :                     /* nope, this is a new one */
                               2938                 :                     CookedConstraint *cooked;
                               2939                 : 
 5448 tgl                      2940 CBC          86 :                     cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
 5448 tgl                      2941 GIC          86 :                     cooked->contype = CONSTR_CHECK;
 2118                          2942              86 :                     cooked->conoid = InvalidOid; /* until created */
 5448                          2943              86 :                     cooked->name = pstrdup(name);
 5050 bruce                    2944              86 :                     cooked->attnum = 0; /* not used for constraints */
 5448 tgl                      2945              86 :                     cooked->expr = expr;
 4330 alvherre                 2946              86 :                     cooked->skip_validation = false;
 5448 tgl                      2947              86 :                     cooked->is_local = false;
 5448 tgl                      2948 CBC          86 :                     cooked->inhcount = 1;
 4006 alvherre                 2949              86 :                     cooked->is_no_inherit = false;
 5448 tgl                      2950 GIC          86 :                     constraints = lappend(constraints, cooked);
                               2951                 :                 }
                               2952                 :             }
                               2953                 :         }
                               2954                 : 
                               2955                 :         /*
                               2956                 :          * Also copy the NOT NULL constraints from this parent.  The
                               2957                 :          * attnotnull markings were already installed above.
                               2958                 :          */
    2 alvherre                 2959 GNC        4737 :         foreach(lc1, nnconstrs)
                               2960                 :         {
                               2961             301 :             CookedConstraint *nn = lfirst(lc1);
                               2962                 : 
                               2963             301 :             nn->attnum = newattmap->attnums[nn->attnum - 1];
                               2964                 : 
                               2965             301 :             nnconstraints = lappend(nnconstraints, nn);
                               2966                 :         }
                               2967                 : 
 1208 michael                  2968 CBC        4436 :         free_attrmap(newattmap);
 8484 peter_e                  2969 ECB             : 
 7653 tgl                      2970                 :         /*
 2314 rhaas                    2971                 :          * Close the parent rel, but keep our lock on it until xact commit.
                               2972                 :          * That will prevent someone else from deleting or ALTERing the parent
                               2973                 :          * before the child is committed.
 7653 tgl                      2974                 :          */
 1539 andres                   2975 CBC        4436 :         table_close(relation, NoLock);
 7653 tgl                      2976 ECB             :     }
 7828                          2977                 : 
                               2978                 :     /*
 7653                          2979                 :      * If we had no inherited attributes, the result schema is just the
                               2980                 :      * explicitly declared columns.  Otherwise, we need to merge the declared
                               2981                 :      * columns into the inherited schema list.  Although, we never have any
                               2982                 :      * explicitly declared columns if the table is a partition.
                               2983                 :      */
 7653 tgl                      2984 GIC       62805 :     if (inhSchema != NIL)
                               2985                 :     {
 2878 bruce                    2986 CBC        4318 :         int         schema_attno = 0;
                               2987                 : 
 7653 tgl                      2988            4698 :         foreach(entry, schema)
                               2989                 :         {
 7653 tgl                      2990 GIC         404 :             ColumnDef  *newdef = lfirst(entry);
 7653 tgl                      2991 CBC         404 :             char       *attributeName = newdef->colname;
                               2992                 :             int         exist_attno;
 7828 tgl                      2993 ECB             : 
 3140 bruce                    2994 GIC         404 :             schema_attno++;
 3140 bruce                    2995 ECB             : 
                               2996                 :             /*
 7653 tgl                      2997                 :              * Does it conflict with some previously inherited column?
                               2998                 :              */
 7653 tgl                      2999 CBC         404 :             exist_attno = findAttrByName(attributeName, inhSchema);
                               3000             404 :             if (exist_attno > 0)
                               3001                 :             {
                               3002                 :                 ColumnDef  *def;
                               3003                 :                 Oid         defTypeId,
 5624 bruce                    3004 ECB             :                             newTypeId;
 5624 bruce                    3005 EUB             :                 int32       deftypmod,
                               3006                 :                             newtypmod;
                               3007                 :                 Oid         defcollid,
                               3008                 :                             newcollid;
                               3009                 : 
                               3010                 :                 /*
                               3011                 :                  * Partitions have only one parent and have no column
                               3012                 :                  * definitions of their own, so conflict should never occur.
                               3013                 :                  */
 2314 rhaas                    3014 CBC         125 :                 Assert(!is_partition);
 2314 rhaas                    3015 ECB             : 
                               3016                 :                 /*
                               3017                 :                  * Yes, try to merge the two column definitions.
                               3018                 :                  */
 2878 bruce                    3019 GIC         125 :                 if (exist_attno == schema_attno)
 3140                          3020             114 :                     ereport(NOTICE,
                               3021                 :                             (errmsg("merging column \"%s\" with inherited definition",
 2118 tgl                      3022 ECB             :                                     attributeName)));
                               3023                 :                 else
 3140 bruce                    3024 CBC          11 :                     ereport(NOTICE,
 2878 bruce                    3025 ECB             :                             (errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
                               3026                 :                              errdetail("User-specified column moved to the position of the inherited column.")));
 6892 neilc                    3027 GIC         125 :                 def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
                               3028                 : 
                               3029                 :                 /*
                               3030                 :                  * Must have the same type and typmod
                               3031                 :                  */
 4414 tgl                      3032             125 :                 typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
 4414 tgl                      3033 CBC         125 :                 typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
 5944 tgl                      3034 GIC         125 :                 if (defTypeId != newTypeId || deftypmod != newtypmod)
 7203                          3035               6 :                     ereport(ERROR,
                               3036                 :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3037                 :                              errmsg("column \"%s\" has a type conflict",
                               3038                 :                                     attributeName),
                               3039                 :                              errdetail("%s versus %s",
                               3040                 :                                        format_type_with_typemod(defTypeId,
                               3041                 :                                                                 deftypmod),
                               3042                 :                                        format_type_with_typemod(newTypeId,
                               3043                 :                                                                 newtypmod))));
                               3044                 : 
                               3045                 :                 /*
                               3046                 :                  * Must have the same collation
                               3047                 :                  */
 4414 tgl                      3048 CBC         119 :                 defcollid = GetColumnDefCollation(NULL, def, defTypeId);
 4414 tgl                      3049 GBC         119 :                 newcollid = GetColumnDefCollation(NULL, newdef, newTypeId);
 4443 peter_e                  3050 GIC         119 :                 if (defcollid != newcollid)
                               3051               3 :                     ereport(ERROR,
                               3052                 :                             (errcode(ERRCODE_COLLATION_MISMATCH),
                               3053                 :                              errmsg("column \"%s\" has a collation conflict",
                               3054                 :                                     attributeName),
                               3055                 :                              errdetail("\"%s\" versus \"%s\"",
                               3056                 :                                        get_collation_name(defcollid),
                               3057                 :                                        get_collation_name(newcollid))));
                               3058                 : 
                               3059                 :                 /*
                               3060                 :                  * Identity is never inherited.  The new column can have an
                               3061                 :                  * identity definition, so we always just take that one.
 2194 peter_e                  3062 ECB             :                  */
 2194 peter_e                  3063 CBC         116 :                 def->identity = newdef->identity;
 2194 peter_e                  3064 ECB             : 
                               3065                 :                 /*
                               3066                 :                  * Copy storage parameter
                               3067                 :                  */
 4927 andrew                   3068 GIC         116 :                 if (def->storage == 0)
 4927 andrew                   3069 LBC           0 :                     def->storage = newdef->storage;
 4927 andrew                   3070 CBC         116 :                 else if (newdef->storage != 0 && def->storage != newdef->storage)
 4927 andrew                   3071 GIC           3 :                     ereport(ERROR,
                               3072                 :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3073                 :                              errmsg("column \"%s\" has a storage parameter conflict",
                               3074                 :                                     attributeName),
                               3075                 :                              errdetail("%s versus %s",
                               3076                 :                                        storage_name(def->storage),
                               3077                 :                                        storage_name(newdef->storage))));
                               3078                 : 
                               3079                 :                 /*
                               3080                 :                  * Copy compression parameter
                               3081                 :                  */
  751 rhaas                    3082             113 :                 if (def->compression == NULL)
  751 rhaas                    3083 CBC         110 :                     def->compression = newdef->compression;
  751 rhaas                    3084 GIC           3 :                 else if (newdef->compression != NULL)
                               3085                 :                 {
  751 rhaas                    3086 CBC           3 :                     if (strcmp(def->compression, newdef->compression) != 0)
  751 rhaas                    3087 GIC           3 :                         ereport(ERROR,
  751 rhaas                    3088 ECB             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3089                 :                                  errmsg("column \"%s\" has a compression method conflict",
                               3090                 :                                         attributeName),
                               3091                 :                                  errdetail("%s versus %s", def->compression, newdef->compression)));
                               3092                 :                 }
                               3093                 : 
                               3094                 :                 /*
                               3095                 :                  * Merge of NOT NULL constraints = OR 'em together
                               3096                 :                  */
 7653 tgl                      3097 CBC         110 :                 def->is_not_null |= newdef->is_not_null;
                               3098                 : 
                               3099                 :                 /*
                               3100                 :                  * Check for conflicts related to generated columns.
                               3101                 :                  *
                               3102                 :                  * If the parent column is generated, the child column will be
                               3103                 :                  * made a generated column if it isn't already.  If it is a
                               3104                 :                  * generated column, we'll take its generation expression in
                               3105                 :                  * preference to the parent's.  We must check that the child
                               3106                 :                  * column doesn't specify a default value or identity, which
                               3107                 :                  * matches the rules for a single column in parse_util.c.
                               3108                 :                  *
                               3109                 :                  * Conversely, if the parent column is not generated, the
                               3110                 :                  * child column can't be either.  (We used to allow that, but
                               3111                 :                  * it results in being able to override the generation
                               3112                 :                  * expression via UPDATEs through the parent.)
                               3113                 :                  */
 1068 peter                    3114 GIC         110 :                 if (def->generated)
                               3115                 :                 {
                               3116              13 :                     if (newdef->raw_default && !newdef->generated)
                               3117               3 :                         ereport(ERROR,
 1068 peter                    3118 ECB             :                                 (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3119                 :                                  errmsg("column \"%s\" inherits from generated column but specifies default",
                               3120                 :                                         def->colname)));
 1068 peter                    3121 CBC          10 :                     if (newdef->identity)
                               3122               3 :                         ereport(ERROR,
 1068 peter                    3123 ECB             :                                 (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3124                 :                                  errmsg("column \"%s\" inherits from generated column but specifies identity",
                               3125                 :                                         def->colname)));
                               3126                 :                 }
                               3127                 :                 else
                               3128                 :                 {
 1068 peter                    3129 GIC          97 :                     if (newdef->generated)
   88 tgl                      3130 GNC           3 :                         ereport(ERROR,
                               3131                 :                                 (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3132                 :                                  errmsg("child column \"%s\" specifies generation expression",
                               3133                 :                                         def->colname),
                               3134                 :                                  errhint("A child table column cannot be generated unless its parent column is.")));
                               3135                 :                 }
 1068 peter                    3136 ECB             : 
                               3137                 :                 /*
                               3138                 :                  * If new def has a default, override previous default
                               3139                 :                  */
 7653 tgl                      3140 CBC         101 :                 if (newdef->raw_default != NULL)
                               3141                 :                 {
                               3142               9 :                     def->raw_default = newdef->raw_default;
 7653 tgl                      3143 GIC           9 :                     def->cooked_default = newdef->cooked_default;
 7653 tgl                      3144 ECB             :                 }
                               3145                 : 
                               3146                 :                 /* Mark the column as locally defined */
   32 peter                    3147 GNC         101 :                 def->is_local = true;
                               3148                 :             }
                               3149                 :             else
 7653 tgl                      3150 ECB             :             {
                               3151                 :                 /*
                               3152                 :                  * No, attach new column to result schema
                               3153                 :                  */
 7653 tgl                      3154 GIC         279 :                 inhSchema = lappend(inhSchema, newdef);
                               3155                 :             }
                               3156                 :         }
 7653 tgl                      3157 ECB             : 
 7653 tgl                      3158 GIC        4294 :         schema = inhSchema;
                               3159                 : 
                               3160                 :         /*
                               3161                 :          * Check that we haven't exceeded the legal # of columns after merging
                               3162                 :          * in inherited columns.
                               3163                 :          */
 6718 neilc                    3164            4294 :         if (list_length(schema) > MaxHeapAttributeNumber)
 6718 neilc                    3165 UIC           0 :             ereport(ERROR,
 6718 neilc                    3166 ECB             :                     (errcode(ERRCODE_TOO_MANY_COLUMNS),
                               3167                 :                      errmsg("tables can have at most %d columns",
                               3168                 :                             MaxHeapAttributeNumber)));
                               3169                 :     }
 8484 peter_e                  3170                 : 
                               3171                 :     /*
 2314 rhaas                    3172                 :      * Now that we have the column definition list for a partition, we can
 2308                          3173                 :      * check whether the columns referenced in the column constraint specs
                               3174                 :      * actually exist.
 2314                          3175                 :      */
 1613 alvherre                 3176 GIC       62781 :     if (is_partition)
                               3177                 :     {
                               3178            3681 :         foreach(entry, saved_schema)
                               3179                 :         {
 1613 alvherre                 3180 CBC         100 :             ColumnDef  *restdef = lfirst(entry);
                               3181             100 :             bool        found = false;
                               3182                 :             ListCell   *l;
                               3183                 : 
 1613 alvherre                 3184 GIC         372 :             foreach(l, schema)
                               3185                 :             {
                               3186             278 :                 ColumnDef  *coldef = lfirst(l);
                               3187                 : 
 2314 rhaas                    3188             278 :                 if (strcmp(coldef->colname, restdef->colname) == 0)
                               3189                 :                 {
 1613 alvherre                 3190             100 :                     found = true;
                               3191             100 :                     coldef->is_not_null |= restdef->is_not_null;
                               3192                 : 
                               3193                 :                     /*
                               3194                 :                      * Check for conflicts related to generated columns.
                               3195                 :                      *
                               3196                 :                      * Same rules as above: generated-ness has to match the
                               3197                 :                      * parent, but the contents of the generation expression
                               3198                 :                      * can be different.
                               3199                 :                      */
   52 tgl                      3200 GNC         100 :                     if (coldef->generated)
                               3201                 :                     {
                               3202              49 :                         if (restdef->raw_default && !restdef->generated)
                               3203               3 :                             ereport(ERROR,
                               3204                 :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3205                 :                                      errmsg("column \"%s\" inherits from generated column but specifies default",
                               3206                 :                                             restdef->colname)));
                               3207              46 :                         if (restdef->identity)
   52 tgl                      3208 UNC           0 :                             ereport(ERROR,
                               3209                 :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3210                 :                                      errmsg("column \"%s\" inherits from generated column but specifies identity",
                               3211                 :                                             restdef->colname)));
                               3212                 :                     }
                               3213                 :                     else
                               3214                 :                     {
   52 tgl                      3215 GNC          51 :                         if (restdef->generated)
                               3216               3 :                             ereport(ERROR,
                               3217                 :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3218                 :                                      errmsg("child column \"%s\" specifies generation expression",
                               3219                 :                                             restdef->colname),
                               3220                 :                                      errhint("A child table column cannot be generated unless its parent column is.")));
                               3221                 :                     }
                               3222                 : 
                               3223                 :                     /*
                               3224                 :                      * Override the parent's default value for this column
 1613 alvherre                 3225 ECB             :                      * (coldef->cooked_default) with the partition's local
                               3226                 :                      * definition (restdef->raw_default), if there's one. It
                               3227                 :                      * should be physically impossible to get a cooked default
                               3228                 :                      * in the local definition or a raw default in the
                               3229                 :                      * inherited definition, but make sure they're nulls, for
                               3230                 :                      * future-proofing.
 2314 rhaas                    3231                 :                      */
 1613 alvherre                 3232 GIC          94 :                     Assert(restdef->cooked_default == NULL);
                               3233              94 :                     Assert(coldef->raw_default == NULL);
                               3234              94 :                     if (restdef->raw_default)
 2172 rhaas                    3235 ECB             :                     {
 2172 rhaas                    3236 GIC          58 :                         coldef->raw_default = restdef->raw_default;
 1613 alvherre                 3237              58 :                         coldef->cooked_default = NULL;
 2172 rhaas                    3238 ECB             :                     }
                               3239                 :                 }
                               3240                 :             }
                               3241                 : 
                               3242                 :             /* complain for constraints on columns not in parent */
 1613 alvherre                 3243 CBC          94 :             if (!found)
 1613 alvherre                 3244 LBC           0 :                 ereport(ERROR,
 1613 alvherre                 3245 ECB             :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
                               3246                 :                          errmsg("column \"%s\" does not exist",
                               3247                 :                                 restdef->colname)));
                               3248                 :         }
                               3249                 :     }
                               3250                 : 
                               3251                 :     /*
                               3252                 :      * If we found any conflicting parent default values, check to make sure
                               3253                 :      * they were overridden by the child.
                               3254                 :      */
 7653 tgl                      3255 GIC       62775 :     if (have_bogus_defaults)
                               3256                 :     {
                               3257              27 :         foreach(entry, schema)
                               3258                 :         {
 7653 tgl                      3259 CBC          21 :             ColumnDef  *def = lfirst(entry);
 8397 bruce                    3260 ECB             : 
 4933 tgl                      3261 CBC          21 :             if (def->cooked_default == &bogus_marker)
 1068 peter                    3262 ECB             :             {
 1068 peter                    3263 GIC           6 :                 if (def->generated)
                               3264               3 :                     ereport(ERROR,
                               3265                 :                             (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3266                 :                              errmsg("column \"%s\" inherits conflicting generation expressions",
                               3267                 :                                     def->colname),
                               3268                 :                              errhint("To resolve the conflict, specify a generation expression explicitly.")));
                               3269                 :                 else
                               3270               3 :                     ereport(ERROR,
                               3271                 :                             (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3272                 :                              errmsg("column \"%s\" inherits conflicting default values",
                               3273                 :                                     def->colname),
                               3274                 :                              errhint("To resolve the conflict, specify a default explicitly.")));
 1068 peter                    3275 ECB             :             }
                               3276                 :         }
                               3277                 :     }
                               3278                 : 
 7653 tgl                      3279 GIC       62769 :     *supconstr = constraints;
    2 alvherre                 3280 GNC       62769 :     *supnotnulls = nnconstraints;
                               3281                 : 
 7653 tgl                      3282 CBC       62769 :     return schema;
 7653 tgl                      3283 EUB             : }
 8397 bruce                    3284 ECB             : 
 6024 tgl                      3285                 : 
                               3286                 : /*
                               3287                 :  * MergeCheckConstraint
                               3288                 :  *      Try to merge an inherited CHECK constraint with previous ones
                               3289                 :  *
                               3290                 :  * If we inherit identically-named constraints from multiple parents, we must
                               3291                 :  * merge them, or throw an error if they don't have identical definitions.
                               3292                 :  *
                               3293                 :  * constraints is a list of CookedConstraint structs for previous constraints.
                               3294                 :  *
                               3295                 :  * Returns true if merged (constraint is a duplicate), or false if it's
 5448                          3296                 :  * got a so-far-unique name, or throws error if conflict.
 7653                          3297                 :  */
 5448                          3298                 : static bool
 5448 tgl                      3299 GIC          92 : MergeCheckConstraint(List *constraints, char *name, Node *expr)
 6130 bruce                    3300 ECB             : {
 5448 tgl                      3301                 :     ListCell   *lc;
                               3302                 : 
 5448 tgl                      3303 GIC         107 :     foreach(lc, constraints)
                               3304                 :     {
                               3305              21 :         CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
                               3306                 : 
                               3307              21 :         Assert(ccon->contype == CONSTR_CHECK);
                               3308                 : 
                               3309                 :         /* Non-matching names never conflict */
                               3310              21 :         if (strcmp(ccon->name, name) != 0)
 6130 bruce                    3311 CBC          15 :             continue;
                               3312                 : 
 5448 tgl                      3313 GIC           6 :         if (equal(expr, ccon->expr))
                               3314                 :         {
                               3315                 :             /* OK to merge */
                               3316               6 :             ccon->inhcount++;
   12 peter                    3317 GNC           6 :             if (ccon->inhcount < 0)
   12 peter                    3318 UNC           0 :                 ereport(ERROR,
                               3319                 :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               3320                 :                         errmsg("too many inheritance parents"));
 5448 tgl                      3321 GIC           6 :             return true;
                               3322                 :         }
                               3323                 : 
 6024 tgl                      3324 UIC           0 :         ereport(ERROR,
                               3325                 :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
                               3326                 :                  errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
                               3327                 :                         name)));
                               3328                 :     }
                               3329                 : 
 5448 tgl                      3330 GIC          86 :     return false;
                               3331                 : }
 6130 bruce                    3332 ECB             : 
                               3333                 : /*
                               3334                 :  * RelationGetNotNullConstraints -- get list of NOT NULL constraints
                               3335                 :  *
                               3336                 :  * Caller can request cooked constraints, or raw.
                               3337                 :  *
                               3338                 :  * This is seldom needed, so we just scan pg_constraint each time.
                               3339                 :  *
                               3340                 :  * XXX This is only used to create derived tables, so NO INHERIT constraints
                               3341                 :  * are always skipped.
                               3342                 :  */
                               3343                 : List *
    2 alvherre                 3344 GNC        4761 : RelationGetNotNullConstraints(Relation relation, bool cooked)
                               3345                 : {
                               3346            4761 :     List       *notnulls = NIL;
                               3347                 :     Relation    constrRel;
                               3348                 :     HeapTuple   htup;
                               3349                 :     SysScanDesc conscan;
                               3350                 :     ScanKeyData skey;
                               3351                 : 
                               3352            4761 :     constrRel = table_open(ConstraintRelationId, AccessShareLock);
                               3353            4761 :     ScanKeyInit(&skey,
                               3354                 :                 Anum_pg_constraint_conrelid,
                               3355                 :                 BTEqualStrategyNumber, F_OIDEQ,
                               3356                 :                 ObjectIdGetDatum(RelationGetRelid(relation)));
                               3357            4761 :     conscan = systable_beginscan(constrRel, ConstraintRelidTypidNameIndexId, true,
                               3358                 :                                  NULL, 1, &skey);
                               3359                 : 
                               3360            6297 :     while (HeapTupleIsValid(htup = systable_getnext(conscan)))
                               3361                 :     {
                               3362            1536 :         Form_pg_constraint conForm = (Form_pg_constraint) GETSTRUCT(htup);
                               3363                 :         AttrNumber  colnum;
                               3364                 : 
                               3365            1536 :         if (conForm->contype != CONSTRAINT_NOTNULL)
                               3366            1149 :             continue;
                               3367             387 :         if (conForm->connoinherit)
                               3368               9 :             continue;
                               3369                 : 
                               3370             378 :         colnum = extractNotNullColumn(htup);
                               3371                 : 
                               3372             378 :         if (cooked)
                               3373                 :         {
                               3374                 :             CookedConstraint *cooked;
                               3375                 : 
                               3376             301 :             cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
                               3377                 : 
                               3378             301 :             cooked->contype = CONSTR_NOTNULL;
                               3379             301 :             cooked->name = pstrdup(NameStr(conForm->conname));
                               3380             301 :             cooked->attnum = colnum;
                               3381             301 :             cooked->expr = NULL;
                               3382             301 :             cooked->skip_validation = false;
                               3383             301 :             cooked->is_local = true;
                               3384             301 :             cooked->inhcount = 0;
                               3385             301 :             cooked->is_no_inherit = conForm->connoinherit;
                               3386                 : 
                               3387             301 :             notnulls = lappend(notnulls, cooked);
                               3388                 :         }
                               3389                 :         else
                               3390                 :         {
                               3391                 :             Constraint *constr;
                               3392                 : 
                               3393              77 :             constr = makeNode(Constraint);
                               3394              77 :             constr->contype = CONSTR_NOTNULL;
                               3395              77 :             constr->conname = pstrdup(NameStr(conForm->conname));
                               3396              77 :             constr->deferrable = false;
                               3397              77 :             constr->initdeferred = false;
                               3398              77 :             constr->location = -1;
                               3399              77 :             constr->colname = get_attname(RelationGetRelid(relation),
                               3400                 :                                           colnum, false);
                               3401              77 :             constr->skip_validation = false;
                               3402              77 :             constr->initially_valid = true;
                               3403              77 :             notnulls = lappend(notnulls, constr);
                               3404                 :         }
                               3405                 :     }
                               3406                 : 
                               3407            4761 :     systable_endscan(conscan);
                               3408            4761 :     table_close(constrRel, AccessShareLock);
                               3409                 : 
                               3410            4761 :     return notnulls;
                               3411                 : }
                               3412                 : 
 8007 tgl                      3413 ECB             : /*
 7653                          3414                 :  * StoreCatalogInheritance
                               3415                 :  *      Updates the system catalogs with proper inheritance information.
                               3416                 :  *
                               3417                 :  * supers is a list of the OIDs of the new relation's direct ancestors.
 8007                          3418                 :  */
 7653                          3419                 : static void
 2225 simon                    3420 GIC       62499 : StoreCatalogInheritance(Oid relationId, List *supers,
                               3421                 :                         bool child_is_partition)
                               3422                 : {
                               3423                 :     Relation    relation;
                               3424                 :     int32       seqNumber;
                               3425                 :     ListCell   *entry;
 7681 tgl                      3426 ECB             : 
 7668 bruce                    3427                 :     /*
                               3428                 :      * sanity checks
                               3429                 :      */
  163 peter                    3430 GNC       62499 :     Assert(OidIsValid(relationId));
                               3431                 : 
 7653 tgl                      3432 GIC       62499 :     if (supers == NIL)
                               3433           58385 :         return;
                               3434                 : 
                               3435                 :     /*
                               3436                 :      * Store INHERITS information in pg_inherits using direct ancestors only.
 6385 bruce                    3437 ECB             :      * Also enter dependencies on the direct ancestors, and make sure they are
                               3438                 :      * marked with relhassubclass = true.
 7118 tgl                      3439                 :      *
 6347 bruce                    3440                 :      * (Once upon a time, both direct and indirect ancestors were found here
                               3441                 :      * and then entered into pg_ipl.  Since that catalog doesn't exist
                               3442                 :      * anymore, there's no need to look for indirect ancestors.)
                               3443                 :      */
 1539 andres                   3444 CBC        4114 :     relation = table_open(InheritsRelationId, RowExclusiveLock);
                               3445                 : 
 7653 tgl                      3446 GIC        4114 :     seqNumber = 1;
                               3447            8322 :     foreach(entry, supers)
                               3448                 :     {
 6022                          3449            4208 :         Oid         parentOid = lfirst_oid(entry);
                               3450                 : 
 2225 simon                    3451 CBC        4208 :         StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
                               3452                 :                                  child_is_partition);
 6125 neilc                    3453 GIC        4208 :         seqNumber++;
                               3454                 :     }
 6125 bruce                    3455 ECB             : 
 1539 andres                   3456 GIC        4114 :     table_close(relation, RowExclusiveLock);
                               3457                 : }
                               3458                 : 
                               3459                 : /*
                               3460                 :  * Make catalog entries showing relationId as being an inheritance child
 6022 tgl                      3461 ECB             :  * of parentOid.  inhRelation is the already-opened pg_inherits catalog.
 6022 tgl                      3462 EUB             :  */
                               3463                 : static void
 6125 neilc                    3464 GIC        5238 : StoreCatalogInheritance1(Oid relationId, Oid parentOid,
                               3465                 :                          int32 seqNumber, Relation inhRelation,
                               3466                 :                          bool child_is_partition)
                               3467                 : {
                               3468                 :     ObjectAddress childobject,
                               3469                 :                 parentobject;
                               3470                 : 
                               3471                 :     /* store the pg_inherits row */
 1906 alvherre                 3472            5238 :     StoreSingleInheritance(relationId, parentOid, seqNumber);
 8007 tgl                      3473 ECB             : 
                               3474                 :     /*
 6125 neilc                    3475                 :      * Store a dependency too
                               3476                 :      */
 6125 neilc                    3477 CBC        5238 :     parentobject.classId = RelationRelationId;
                               3478            5238 :     parentobject.objectId = parentOid;
 6125 neilc                    3479 GIC        5238 :     parentobject.objectSubId = 0;
                               3480            5238 :     childobject.classId = RelationRelationId;
 6125 neilc                    3481 CBC        5238 :     childobject.objectId = relationId;
 6125 neilc                    3482 GIC        5238 :     childobject.objectSubId = 0;
 7576 tgl                      3483 ECB             : 
 2126 rhaas                    3484 GIC        5238 :     recordDependencyOn(&childobject, &parentobject,
 2126 rhaas                    3485 ECB             :                        child_dependency_type(child_is_partition));
                               3486                 : 
 3675                          3487                 :     /*
                               3488                 :      * Post creation hook of this inheritance. Since object_access_hook
                               3489                 :      * doesn't take multiple object identifiers, we relay oid of parent
                               3490                 :      * relation using auxiliary_id argument.
                               3491                 :      */
 3675 rhaas                    3492 GIC        5238 :     InvokeObjectPostAlterHookArg(InheritsRelationId,
                               3493                 :                                  relationId, 0,
                               3494                 :                                  parentOid, false);
                               3495                 : 
                               3496                 :     /*
 6125 neilc                    3497 ECB             :      * Mark the parent as having subclasses.
                               3498                 :      */
 4237 tgl                      3499 CBC        5238 :     SetRelationHasSubclass(parentOid, true);
 7653                          3500            5238 : }
                               3501                 : 
                               3502                 : /*
                               3503                 :  * Look for an existing schema entry with the given name.
 7653 tgl                      3504 ECB             :  *
 7653 tgl                      3505 EUB             :  * Returns the index (starting with 1) if attribute already exists in schema,
                               3506                 :  * 0 if it doesn't.
                               3507                 :  */
                               3508                 : static int
 7653 tgl                      3509 GIC        9304 : findAttrByName(const char *attributeName, List *schema)
                               3510                 : {
                               3511                 :     ListCell   *s;
 6892 neilc                    3512 CBC        9304 :     int         i = 1;
 7653 tgl                      3513 ECB             : 
 7653 tgl                      3514 GIC       16605 :     foreach(s, schema)
                               3515                 :     {
                               3516            7538 :         ColumnDef  *def = lfirst(s);
                               3517                 : 
                               3518            7538 :         if (strcmp(attributeName, def->colname) == 0)
                               3519             237 :             return i;
                               3520                 : 
 6892 neilc                    3521            7301 :         i++;
                               3522                 :     }
 7653 tgl                      3523            9067 :     return 0;
                               3524                 : }
                               3525                 : 
                               3526                 : 
                               3527                 : /*
                               3528                 :  * SetRelationHasSubclass
 4237 tgl                      3529 ECB             :  *      Set the value of the relation's relhassubclass field in pg_class.
                               3530                 :  *
                               3531                 :  * NOTE: caller must be holding an appropriate lock on the relation.
                               3532                 :  * ShareUpdateExclusiveLock is sufficient.
                               3533                 :  *
                               3534                 :  * NOTE: an important side-effect of this operation is that an SI invalidation
                               3535                 :  * message is sent out to all backends --- including me --- causing plans
                               3536                 :  * referencing the relation to be rebuilt with the new list of children.
                               3537                 :  * This must happen even if we find that no change is needed in the pg_class
                               3538                 :  * row.
                               3539                 :  */
                               3540                 : void
 4237 tgl                      3541 GBC        6544 : SetRelationHasSubclass(Oid relationId, bool relhassubclass)
                               3542                 : {
                               3543                 :     Relation    relationRelation;
                               3544                 :     HeapTuple   tuple;
                               3545                 :     Form_pg_class classtuple;
                               3546                 : 
                               3547                 :     /*
                               3548                 :      * Fetch a modifiable copy of the tuple, modify it, update pg_class.
                               3549                 :      */
 1539 andres                   3550 GIC        6544 :     relationRelation = table_open(RelationRelationId, RowExclusiveLock);
 4802 rhaas                    3551            6544 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
 7653 tgl                      3552 CBC        6544 :     if (!HeapTupleIsValid(tuple))
 7203 tgl                      3553 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relationId);
 7118 tgl                      3554 CBC        6544 :     classtuple = (Form_pg_class) GETSTRUCT(tuple);
                               3555                 : 
                               3556            6544 :     if (classtuple->relhassubclass != relhassubclass)
                               3557                 :     {
                               3558            3248 :         classtuple->relhassubclass = relhassubclass;
 2259 alvherre                 3559 GIC        3248 :         CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
 7118 tgl                      3560 ECB             :     }
                               3561                 :     else
                               3562                 :     {
                               3563                 :         /* no need to change tuple, but force relcache rebuild anyway */
 6998 tgl                      3564 GIC        3296 :         CacheInvalidateRelcacheByTuple(tuple);
                               3565                 :     }
                               3566                 : 
 7653 tgl                      3567 CBC        6544 :     heap_freetuple(tuple);
 1539 andres                   3568 GIC        6544 :     table_close(relationRelation, RowExclusiveLock);
 7653 tgl                      3569            6544 : }
                               3570                 : 
                               3571                 : /*
                               3572                 :  * CheckRelationTableSpaceMove
                               3573                 :  *      Check if relation can be moved to new tablespace.
                               3574                 :  *
                               3575                 :  * NOTE: The caller must hold AccessExclusiveLock on the relation.
  802 michael                  3576 ECB             :  *
  800                          3577                 :  * Returns true if the relation can be moved to the new tablespace; raises
                               3578                 :  * an error if it is not possible to do the move; returns false if the move
                               3579                 :  * would have no effect.
                               3580                 :  */
                               3581                 : bool
  802 michael                  3582 GIC         215 : CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
                               3583                 : {
                               3584                 :     Oid         oldTableSpaceId;
                               3585                 : 
                               3586                 :     /*
                               3587                 :      * No work if no change in tablespace.  Note that MyDatabaseTableSpace is
                               3588                 :      * stored as 0.
                               3589                 :      */
                               3590             215 :     oldTableSpaceId = rel->rd_rel->reltablespace;
                               3591             215 :     if (newTableSpaceId == oldTableSpaceId ||
                               3592             211 :         (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
                               3593               5 :         return false;
                               3594                 : 
                               3595                 :     /*
  802 michael                  3596 ECB             :      * We cannot support moving mapped relations into different tablespaces.
                               3597                 :      * (In particular this eliminates all shared catalogs.)
                               3598                 :      */
  802 michael                  3599 GIC         210 :     if (RelationIsMapped(rel))
  802 michael                  3600 LBC           0 :         ereport(ERROR,
                               3601                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  802 michael                  3602 ECB             :                  errmsg("cannot move system relation \"%s\"",
                               3603                 :                         RelationGetRelationName(rel))));
                               3604                 : 
                               3605                 :     /* Cannot move a non-shared relation into pg_global */
  802 michael                  3606 GIC         210 :     if (newTableSpaceId == GLOBALTABLESPACE_OID)
  802 michael                  3607 CBC           6 :         ereport(ERROR,
  802 michael                  3608 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               3609                 :                  errmsg("only shared relations can be placed in pg_global tablespace")));
                               3610                 : 
                               3611                 :     /*
                               3612                 :      * Do not allow moving temp tables of other backends ... their local
                               3613                 :      * buffer manager is not going to cope.
                               3614                 :      */
  802 michael                  3615 GBC         204 :     if (RELATION_IS_OTHER_TEMP(rel))
  802 michael                  3616 UIC           0 :         ereport(ERROR,
                               3617                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  802 michael                  3618 ECB             :                  errmsg("cannot move temporary tables of other sessions")));
                               3619                 : 
  802 michael                  3620 GIC         204 :     return true;
  802 michael                  3621 EUB             : }
                               3622                 : 
                               3623                 : /*
                               3624                 :  * SetRelationTableSpace
                               3625                 :  *      Set new reltablespace and relfilenumber in pg_class entry.
                               3626                 :  *
  802 michael                  3627 ECB             :  * newTableSpaceId is the new tablespace for the relation, and
                               3628                 :  * newRelFilenumber its new filenumber.  If newRelFilenumber is
                               3629                 :  * InvalidRelFileNumber, this field is not updated.
                               3630                 :  *
                               3631                 :  * NOTE: The caller must hold AccessExclusiveLock on the relation.
                               3632                 :  *
                               3633                 :  * The caller of this routine had better check if a relation can be
                               3634                 :  * moved to this new tablespace by calling CheckRelationTableSpaceMove()
                               3635                 :  * first, and is responsible for making the change visible with
                               3636                 :  * CommandCounterIncrement().
                               3637                 :  */
                               3638                 : void
  802 michael                  3639 GIC         102 : SetRelationTableSpace(Relation rel,
                               3640                 :                       Oid newTableSpaceId,
                               3641                 :                       RelFileNumber newRelFilenumber)
                               3642                 : {
  802 michael                  3643 ECB             :     Relation    pg_class;
                               3644                 :     HeapTuple   tuple;
                               3645                 :     Form_pg_class rd_rel;
  802 michael                  3646 GIC         102 :     Oid         reloid = RelationGetRelid(rel);
                               3647                 : 
                               3648             102 :     Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
  802 michael                  3649 ECB             : 
                               3650                 :     /* Get a modifiable copy of the relation's pg_class row. */
  802 michael                  3651 GIC         102 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
                               3652                 : 
                               3653             102 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
  802 michael                  3654 CBC         102 :     if (!HeapTupleIsValid(tuple))
  802 michael                  3655 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", reloid);
  802 michael                  3656 GIC         102 :     rd_rel = (Form_pg_class) GETSTRUCT(tuple);
  802 michael                  3657 ECB             : 
                               3658                 :     /* Update the pg_class row. */
  802 michael                  3659 CBC         204 :     rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
  802 michael                  3660 GIC         102 :         InvalidOid : newTableSpaceId;
  277 rhaas                    3661 GNC         102 :     if (RelFileNumberIsValid(newRelFilenumber))
                               3662              80 :         rd_rel->relfilenode = newRelFilenumber;
  802 michael                  3663 CBC         102 :     CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
  802 michael                  3664 ECB             : 
                               3665                 :     /*
                               3666                 :      * Record dependency on tablespace.  This is only required for relations
                               3667                 :      * that have no physical storage.
                               3668                 :      */
  802 michael                  3669 CBC         102 :     if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
  802 michael                  3670 GIC          15 :         changeDependencyOnTablespace(RelationRelationId, reloid,
                               3671                 :                                      rd_rel->reltablespace);
                               3672                 : 
  802 michael                  3673 CBC         102 :     heap_freetuple(tuple);
  802 michael                  3674 GIC         102 :     table_close(pg_class, RowExclusiveLock);
  802 michael                  3675 CBC         102 : }
  802 michael                  3676 ECB             : 
 8478 peter_e                  3677                 : /*
 4133 rhaas                    3678                 :  *      renameatt_check         - basic sanity checks before attribute rename
 8478 peter_e                  3679                 :  */
 4520                          3680                 : static void
 4133 rhaas                    3681 CBC         479 : renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 8484 peter_e                  3682 ECB             : {
 4133 rhaas                    3683 GIC         479 :     char        relkind = classform->relkind;
 7681 tgl                      3684 ECB             : 
 4133 rhaas                    3685 GIC         479 :     if (classform->reloftype && !recursing)
 4819 peter_e                  3686               3 :         ereport(ERROR,
                               3687                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               3688                 :                  errmsg("cannot rename column of typed table")));
                               3689                 : 
 4768 rhaas                    3690 ECB             :     /*
                               3691                 :      * Renaming the columns of sequences or toast tables doesn't actually
                               3692                 :      * break anything from the system's point of view, since internal
 4660 bruce                    3693                 :      * references are by attnum.  But it doesn't seem right to allow users to
                               3694                 :      * change names that are hardcoded into the system, hence the following
 4768 rhaas                    3695                 :      * restriction.
                               3696                 :      */
 4768 rhaas                    3697 GIC         476 :     if (relkind != RELKIND_RELATION &&
 4768 rhaas                    3698 CBC          42 :         relkind != RELKIND_VIEW &&
 3689 kgrittn                  3699              42 :         relkind != RELKIND_MATVIEW &&
 4768 rhaas                    3700              18 :         relkind != RELKIND_COMPOSITE_TYPE &&
 4481 rhaas                    3701 GIC          18 :         relkind != RELKIND_INDEX &&
 1906 alvherre                 3702              18 :         relkind != RELKIND_PARTITIONED_INDEX &&
 2314 rhaas                    3703 UIC           0 :         relkind != RELKIND_FOREIGN_TABLE &&
 2314 rhaas                    3704 ECB             :         relkind != RELKIND_PARTITIONED_TABLE)
 4768 rhaas                    3705 LBC           0 :         ereport(ERROR,
                               3706                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  640 peter                    3707 ECB             :                  errmsg("cannot rename columns of relation \"%s\"",
                               3708                 :                         NameStr(classform->relname)),
                               3709                 :                  errdetail_relkind_not_supported(relkind)));
                               3710                 : 
                               3711                 :     /*
                               3712                 :      * permissions checking.  only the owner of a class can change its schema.
                               3713                 :      */
  147 peter                    3714 GNC         476 :     if (!object_ownercheck(RelationRelationId, myrelid, GetUserId()))
 1954 peter_e                  3715 UIC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(myrelid)),
 4133 rhaas                    3716               0 :                        NameStr(classform->relname));
 3419 rhaas                    3717 CBC         476 :     if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
 7203 tgl                      3718 GIC           1 :         ereport(ERROR,
                               3719                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                               3720                 :                  errmsg("permission denied: \"%s\" is a system catalog",
                               3721                 :                         NameStr(classform->relname))));
 4133 rhaas                    3722             475 : }
                               3723                 : 
                               3724                 : /*
                               3725                 :  *      renameatt_internal      - workhorse for renameatt
                               3726                 :  *
 2959 alvherre                 3727 ECB             :  * Return value is the attribute number in the 'myrelid' relation.
                               3728                 :  */
                               3729                 : static AttrNumber
 4133 rhaas                    3730 CBC         267 : renameatt_internal(Oid myrelid,
                               3731                 :                    const char *oldattname,
                               3732                 :                    const char *newattname,
                               3733                 :                    bool recurse,
                               3734                 :                    bool recursing,
                               3735                 :                    int expected_parents,
                               3736                 :                    DropBehavior behavior)
                               3737                 : {
                               3738                 :     Relation    targetrelation;
                               3739                 :     Relation    attrelation;
                               3740                 :     HeapTuple   atttup;
 3602 bruce                    3741 ECB             :     Form_pg_attribute attform;
                               3742                 :     AttrNumber  attnum;
 4133 rhaas                    3743                 : 
                               3744                 :     /*
                               3745                 :      * Grab an exclusive lock on the target table, which we will NOT release
                               3746                 :      * until end of transaction.
                               3747                 :      */
 4133 rhaas                    3748 CBC         267 :     targetrelation = relation_open(myrelid, AccessExclusiveLock);
 4133 rhaas                    3749 GIC         267 :     renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
 7849 tgl                      3750 ECB             : 
                               3751                 :     /*
                               3752                 :      * if the 'recurse' flag is set then we are supposed to rename this
 7653                          3753                 :      * attribute in all classes that inherit from 'relname' (as well as in
                               3754                 :      * 'relname').
                               3755                 :      *
                               3756                 :      * any permissions or problems with duplicate attributes will cause the
                               3757                 :      * whole transaction to abort, which is what we want -- all or nothing.
                               3758                 :      */
 7653 tgl                      3759 GIC         267 :     if (recurse)
                               3760                 :     {
 4790 bruce                    3761 ECB             :         List       *child_oids,
                               3762                 :                    *child_numparents;
                               3763                 :         ListCell   *lo,
                               3764                 :                    *li;
                               3765                 : 
                               3766                 :         /*
                               3767                 :          * we need the number of parents for each child so that the recursive
                               3768                 :          * calls to renameatt() can determine whether there are any parents
 4815 rhaas                    3769                 :          * outside the inheritance hierarchy being processed.
                               3770                 :          */
 4815 rhaas                    3771 GIC         115 :         child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
                               3772                 :                                          &child_numparents);
                               3773                 : 
 7849 tgl                      3774 ECB             :         /*
 6385 bruce                    3775                 :          * find_all_inheritors does the recursive search of the inheritance
                               3776                 :          * hierarchy, so all we have to do is process all of the relids in the
                               3777                 :          * list that it returns.
 7849 tgl                      3778                 :          */
 4815 rhaas                    3779 CBC         349 :         forboth(lo, child_oids, li, child_numparents)
                               3780                 :         {
                               3781             249 :             Oid         childrelid = lfirst_oid(lo);
 4815 rhaas                    3782 GIC         249 :             int         numparents = lfirst_int(li);
                               3783                 : 
 7527 tgl                      3784             249 :             if (childrelid == myrelid)
 7849                          3785             115 :                 continue;
                               3786                 :             /* note we need not recurse again */
 4520 peter_e                  3787             134 :             renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
                               3788                 :         }
 7849 tgl                      3789 ECB             :     }
                               3790                 :     else
                               3791                 :     {
                               3792                 :         /*
                               3793                 :          * If we are told not to recurse, there had better not be any child
                               3794                 :          * tables; else the rename would put them out of step.
                               3795                 :          *
 4815 rhaas                    3796                 :          * expected_parents will only be 0 if we are not already recursing.
 7527 tgl                      3797                 :          */
 4815 rhaas                    3798 GIC         170 :         if (expected_parents == 0 &&
  711 alvherre                 3799              18 :             find_inheritance_children(myrelid, NoLock) != NIL)
 7203 tgl                      3800               6 :             ereport(ERROR,
                               3801                 :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               3802                 :                      errmsg("inherited column \"%s\" must be renamed in child tables too",
                               3803                 :                             oldattname)));
                               3804                 :     }
                               3805                 : 
 4520 peter_e                  3806 ECB             :     /* rename attributes in typed tables of composite type */
 4520 peter_e                  3807 GIC         246 :     if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
                               3808                 :     {
 4520 peter_e                  3809 ECB             :         List       *child_oids;
                               3810                 :         ListCell   *lo;
                               3811                 : 
 4520 peter_e                  3812 GIC          12 :         child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
 2118 tgl                      3813 CBC          12 :                                                    RelationGetRelationName(targetrelation),
                               3814                 :                                                    behavior);
 4520 peter_e                  3815 ECB             : 
 4520 peter_e                  3816 CBC          12 :         foreach(lo, child_oids)
 4520 peter_e                  3817 GIC           3 :             renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
 4520 peter_e                  3818 ECB             :     }
                               3819                 : 
 1539 andres                   3820 CBC         243 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               3821                 : 
 7527 tgl                      3822 GIC         243 :     atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
 7653                          3823             243 :     if (!HeapTupleIsValid(atttup))
 7203                          3824              12 :         ereport(ERROR,
                               3825                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               3826                 :                  errmsg("column \"%s\" does not exist",
                               3827                 :                         oldattname)));
 7527                          3828             231 :     attform = (Form_pg_attribute) GETSTRUCT(atttup);
                               3829                 : 
 7256                          3830             231 :     attnum = attform->attnum;
 6913                          3831             231 :     if (attnum <= 0)
 7203 tgl                      3832 UIC           0 :         ereport(ERROR,
                               3833                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               3834                 :                  errmsg("cannot rename system column \"%s\"",
                               3835                 :                         oldattname)));
                               3836                 : 
                               3837                 :     /*
 3260 bruce                    3838 ECB             :      * if the attribute is inherited, forbid the renaming.  if this is a
                               3839                 :      * top-level call to renameatt(), then expected_parents will be 0, so the
                               3840                 :      * effect of this code will be to prohibit the renaming if the attribute
                               3841                 :      * is inherited at all.  if this is a recursive call to renameatt(),
                               3842                 :      * expected_parents will be the number of parents the current relation has
                               3843                 :      * within the inheritance hierarchy being processed, so we'll prohibit the
                               3844                 :      * renaming only if there are additional parents from elsewhere.
                               3845                 :      */
 4815 rhaas                    3846 GIC         231 :     if (attform->attinhcount > expected_parents)
 7203 tgl                      3847 CBC          15 :         ereport(ERROR,
 7203 tgl                      3848 ECB             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 7136 peter_e                  3849                 :                  errmsg("cannot rename inherited column \"%s\"",
 7203 tgl                      3850 EUB             :                         oldattname)));
 7527 tgl                      3851 ECB             : 
                               3852                 :     /* new name should not already exist */
 2811 andrew                   3853 CBC         216 :     (void) check_for_column_name_collision(targetrelation, newattname, false);
                               3854                 : 
 4855 tgl                      3855 ECB             :     /* apply the update */
 7527 tgl                      3856 CBC         210 :     namestrcpy(&(attform->attname), newattname);
                               3857                 : 
 2259 alvherre                 3858 GIC         210 :     CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
                               3859                 : 
 3675 rhaas                    3860             210 :     InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
 3675 rhaas                    3861 ECB             : 
 7653 tgl                      3862 GIC         210 :     heap_freetuple(atttup);
                               3863                 : 
 1539 andres                   3864 CBC         210 :     table_close(attrelation, RowExclusiveLock);
 7678 tgl                      3865 ECB             : 
 2118 tgl                      3866 CBC         210 :     relation_close(targetrelation, NoLock); /* close rel but keep lock */
                               3867                 : 
 2959 alvherre                 3868 GIC         210 :     return attnum;
                               3869                 : }
                               3870                 : 
                               3871                 : /*
                               3872                 :  * Perform permissions and integrity checks before acquiring a relation lock.
                               3873                 :  */
                               3874                 : static void
 4133 rhaas                    3875             191 : RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
                               3876                 :                                    void *arg)
                               3877                 : {
                               3878                 :     HeapTuple   tuple;
 3955 bruce                    3879 ECB             :     Form_pg_class form;
                               3880                 : 
 4133 rhaas                    3881 GIC         191 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
                               3882             191 :     if (!HeapTupleIsValid(tuple))
 3955 bruce                    3883              18 :         return;                 /* concurrently dropped */
 4133 rhaas                    3884             173 :     form = (Form_pg_class) GETSTRUCT(tuple);
                               3885             173 :     renameatt_check(relid, form, false);
                               3886             169 :     ReleaseSysCache(tuple);
 4133 rhaas                    3887 ECB             : }
 5499 tgl                      3888                 : 
 4520 peter_e                  3889                 : /*
 2881 heikki.linnakangas       3890                 :  *      renameatt       - changes the name of an attribute in a relation
                               3891                 :  *
                               3892                 :  * The returned ObjectAddress is that of the renamed column.
                               3893                 :  */
                               3894                 : ObjectAddress
 4133 rhaas                    3895 GIC         149 : renameatt(RenameStmt *stmt)
 4520 peter_e                  3896 ECB             : {
 4133 rhaas                    3897 EUB             :     Oid         relid;
                               3898                 :     AttrNumber  attnum;
                               3899                 :     ObjectAddress address;
                               3900                 : 
                               3901                 :     /* lock level taken here should match renameatt_internal */
 4133 rhaas                    3902 GIC         149 :     relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
 1836 andres                   3903 CBC         149 :                                      stmt->missing_ok ? RVR_MISSING_OK : 0,
 4133 rhaas                    3904 ECB             :                                      RangeVarCallbackForRenameAttribute,
                               3905                 :                                      NULL);
                               3906                 : 
 4094 simon                    3907 GIC         142 :     if (!OidIsValid(relid))
                               3908                 :     {
                               3909              12 :         ereport(NOTICE,
                               3910                 :                 (errmsg("relation \"%s\" does not exist, skipping",
                               3911                 :                         stmt->relation->relname)));
 2959 alvherre                 3912 CBC          12 :         return InvalidObjectAddress;
 4094 simon                    3913 EUB             :     }
                               3914                 : 
                               3915                 :     attnum =
 2959 alvherre                 3916 GIC         130 :         renameatt_internal(relid,
 2118 tgl                      3917 CBC         130 :                            stmt->subname,    /* old att name */
 2118 tgl                      3918 GIC         130 :                            stmt->newname,    /* new att name */
 2298                          3919             130 :                            stmt->relation->inh, /* recursive? */
                               3920                 :                            false,   /* recursing? */
                               3921                 :                            0,   /* expected inhcount */
                               3922                 :                            stmt->behavior);
                               3923                 : 
 2959 alvherre                 3924              88 :     ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
                               3925                 : 
                               3926              88 :     return address;
                               3927                 : }
                               3928                 : 
                               3929                 : /*
                               3930                 :  * same logic as renameatt_internal
                               3931                 :  */
                               3932                 : static ObjectAddress
 4047 peter_e                  3933              42 : rename_constraint_internal(Oid myrelid,
                               3934                 :                            Oid mytypid,
                               3935                 :                            const char *oldconname,
 4047 peter_e                  3936 ECB             :                            const char *newconname,
                               3937                 :                            bool recurse,
                               3938                 :                            bool recursing,
                               3939                 :                            int expected_parents)
                               3940                 : {
 4023 peter_e                  3941 GIC          42 :     Relation    targetrelation = NULL;
                               3942                 :     Oid         constraintOid;
 3955 bruce                    3943 ECB             :     HeapTuple   tuple;
                               3944                 :     Form_pg_constraint con;
 2959 alvherre                 3945                 :     ObjectAddress address;
                               3946                 : 
  163 peter                    3947 GNC          42 :     Assert(!myrelid || !mytypid);
 4023 peter_e                  3948 ECB             : 
 4023 peter_e                  3949 GIC          42 :     if (mytypid)
 4023 peter_e                  3950 ECB             :     {
 4023 peter_e                  3951 CBC           3 :         constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
 4023 peter_e                  3952 EUB             :     }
 4023 peter_e                  3953 ECB             :     else
                               3954                 :     {
 4023 peter_e                  3955 GIC          39 :         targetrelation = relation_open(myrelid, AccessExclusiveLock);
 3955 bruce                    3956 ECB             : 
                               3957                 :         /*
                               3958                 :          * don't tell it whether we're recursing; we allow changing typed
                               3959                 :          * tables here
                               3960                 :          */
 4023 peter_e                  3961 GIC          39 :         renameatt_check(myrelid, RelationGetForm(targetrelation), false);
                               3962                 : 
                               3963              39 :         constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
                               3964                 :     }
                               3965                 : 
 4047 peter_e                  3966 CBC          42 :     tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
                               3967              42 :     if (!HeapTupleIsValid(tuple))
 4047 peter_e                  3968 UIC           0 :         elog(ERROR, "cache lookup failed for constraint %u",
                               3969                 :              constraintOid);
 4047 peter_e                  3970 CBC          42 :     con = (Form_pg_constraint) GETSTRUCT(tuple);
 4047 peter_e                  3971 ECB             : 
    2 alvherre                 3972 GNC          42 :     if (myrelid &&
                               3973              39 :         (con->contype == CONSTRAINT_CHECK ||
                               3974               9 :          con->contype == CONSTRAINT_NOTNULL) &&
                               3975              30 :         !con->connoinherit)
                               3976                 :     {
 4047 peter_e                  3977 GIC          24 :         if (recurse)
                               3978                 :         {
                               3979                 :             List       *child_oids,
                               3980                 :                        *child_numparents;
 4047 peter_e                  3981 ECB             :             ListCell   *lo,
                               3982                 :                        *li;
                               3983                 : 
 4047 peter_e                  3984 GIC          15 :             child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
 4047 peter_e                  3985 ECB             :                                              &child_numparents);
                               3986                 : 
 4047 peter_e                  3987 GIC          36 :             forboth(lo, child_oids, li, child_numparents)
                               3988                 :             {
                               3989              21 :                 Oid         childrelid = lfirst_oid(lo);
                               3990              21 :                 int         numparents = lfirst_int(li);
                               3991                 : 
                               3992              21 :                 if (childrelid == myrelid)
                               3993              15 :                     continue;
                               3994                 : 
 4023                          3995               6 :                 rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
                               3996                 :             }
 4047 peter_e                  3997 ECB             :         }
                               3998                 :         else
                               3999                 :         {
 4047 peter_e                  4000 CBC          12 :             if (expected_parents == 0 &&
  711 alvherre                 4001               3 :                 find_inheritance_children(myrelid, NoLock) != NIL)
 4047 peter_e                  4002               3 :                 ereport(ERROR,
 4047 peter_e                  4003 EUB             :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               4004                 :                          errmsg("inherited constraint \"%s\" must be renamed in child tables too",
                               4005                 :                                 oldconname)));
                               4006                 :         }
                               4007                 : 
 4047 peter_e                  4008 GIC          21 :         if (con->coninhcount > expected_parents)
                               4009               3 :             ereport(ERROR,
                               4010                 :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               4011                 :                      errmsg("cannot rename inherited constraint \"%s\"",
                               4012                 :                             oldconname)));
                               4013                 :     }
 4047 peter_e                  4014 ECB             : 
 4047 peter_e                  4015 GBC          36 :     if (con->conindid
                               4016               9 :         && (con->contype == CONSTRAINT_PRIMARY
 4047 peter_e                  4017 CBC           3 :             || con->contype == CONSTRAINT_UNIQUE
 4047 peter_e                  4018 LBC           0 :             || con->contype == CONSTRAINT_EXCLUSION))
                               4019                 :         /* rename the index; this renames the constraint as well */
 1627 peter_e                  4020 GIC           9 :         RenameRelationInternal(con->conindid, newconname, false, true);
                               4021                 :     else
 4047 peter_e                  4022 CBC          27 :         RenameConstraintById(constraintOid, newconname);
                               4023                 : 
 2959 alvherre                 4024 GIC          36 :     ObjectAddressSet(address, ConstraintRelationId, constraintOid);
                               4025                 : 
 4047 peter_e                  4026              36 :     ReleaseSysCache(tuple);
                               4027                 : 
 4023                          4028              36 :     if (targetrelation)
                               4029                 :     {
 1574 michael                  4030 ECB             :         /*
                               4031                 :          * Invalidate relcache so as others can see the new constraint name.
                               4032                 :          */
 1574 michael                  4033 GIC          33 :         CacheInvalidateRelcache(targetrelation);
                               4034                 : 
                               4035              33 :         relation_close(targetrelation, NoLock); /* close rel but keep lock */
                               4036                 :     }
                               4037                 : 
 2959 alvherre                 4038              36 :     return address;
                               4039                 : }
                               4040                 : 
                               4041                 : ObjectAddress
 4047 peter_e                  4042              39 : RenameConstraint(RenameStmt *stmt)
                               4043                 : {
 4023                          4044              39 :     Oid         relid = InvalidOid;
                               4045              39 :     Oid         typid = InvalidOid;
                               4046                 : 
 3029 alvherre                 4047              39 :     if (stmt->renameType == OBJECT_DOMCONSTRAINT)
 4023 peter_e                  4048 ECB             :     {
                               4049                 :         Relation    rel;
                               4050                 :         HeapTuple   tup;
                               4051                 : 
 2339 peter_e                  4052 GIC           3 :         typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
 1539 andres                   4053               3 :         rel = table_open(TypeRelationId, RowExclusiveLock);
 4023 peter_e                  4054               3 :         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
                               4055               3 :         if (!HeapTupleIsValid(tup))
 4023 peter_e                  4056 UIC           0 :             elog(ERROR, "cache lookup failed for type %u", typid);
 4023 peter_e                  4057 GIC           3 :         checkDomainOwner(tup);
                               4058               3 :         ReleaseSysCache(tup);
 1539 andres                   4059 CBC           3 :         table_close(rel, NoLock);
                               4060                 :     }
                               4061                 :     else
                               4062                 :     {
                               4063                 :         /* lock level taken here should match rename_constraint_internal */
 4023 peter_e                  4064 GIC          36 :         relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
 1836 andres                   4065              36 :                                          stmt->missing_ok ? RVR_MISSING_OK : 0,
                               4066                 :                                          RangeVarCallbackForRenameAttribute,
                               4067                 :                                          NULL);
 2938 bruce                    4068              36 :         if (!OidIsValid(relid))
                               4069                 :         {
                               4070               3 :             ereport(NOTICE,
 2938 bruce                    4071 ECB             :                     (errmsg("relation \"%s\" does not exist, skipping",
                               4072                 :                             stmt->relation->relname)));
 2938 bruce                    4073 GIC           3 :             return InvalidObjectAddress;
                               4074                 :         }
                               4075                 :     }
                               4076                 : 
                               4077                 :     return
 3759 rhaas                    4078              36 :         rename_constraint_internal(relid, typid,
 3759 rhaas                    4079 CBC          36 :                                    stmt->subname,
 3759 rhaas                    4080 GIC          36 :                                    stmt->newname,
 2298 tgl                      4081 CBC          69 :                                    (stmt->relation &&
 2118                          4082              33 :                                     stmt->relation->inh), /* recursive? */
                               4083                 :                                    false,   /* recursing? */
 3759 rhaas                    4084 ECB             :                                    0 /* expected inhcount */ );
 4047 peter_e                  4085                 : }
                               4086                 : 
 4133 rhaas                    4087                 : /*
                               4088                 :  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
                               4089                 :  * RENAME
                               4090                 :  */
                               4091                 : ObjectAddress
 4133 rhaas                    4092 GIC         255 : RenameRelation(RenameStmt *stmt)
                               4093                 : {
  537 alvherre                 4094             255 :     bool        is_index_stmt = stmt->renameType == OBJECT_INDEX;
                               4095                 :     Oid         relid;
                               4096                 :     ObjectAddress address;
                               4097                 : 
 5499 tgl                      4098 ECB             :     /*
 3330 rhaas                    4099                 :      * Grab an exclusive lock on the target table, index, sequence, view,
                               4100                 :      * materialized view, or foreign table, which we will NOT release until
                               4101                 :      * end of transaction.
                               4102                 :      *
                               4103                 :      * Lock level used here should match RenameRelationInternal, to avoid lock
                               4104                 :      * escalation.  However, because ALTER INDEX can be used with any relation
                               4105                 :      * type, we mustn't believe without verification.
                               4106                 :      */
  537 alvherre                 4107                 :     for (;;)
 4094 simon                    4108 GIC           6 :     {
                               4109                 :         LOCKMODE    lockmode;
                               4110                 :         char        relkind;
                               4111                 :         bool        obj_is_index;
  537 alvherre                 4112 ECB             : 
  537 alvherre                 4113 CBC         261 :         lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
                               4114                 : 
  537 alvherre                 4115 GIC         261 :         relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
  537 alvherre                 4116 CBC         261 :                                          stmt->missing_ok ? RVR_MISSING_OK : 0,
  537 alvherre                 4117 ECB             :                                          RangeVarCallbackForAlterRelation,
                               4118                 :                                          (void *) stmt);
                               4119                 : 
  537 alvherre                 4120 CBC         236 :         if (!OidIsValid(relid))
                               4121                 :         {
                               4122               9 :             ereport(NOTICE,
  537 alvherre                 4123 ECB             :                     (errmsg("relation \"%s\" does not exist, skipping",
                               4124                 :                             stmt->relation->relname)));
  537 alvherre                 4125 GIC           9 :             return InvalidObjectAddress;
                               4126                 :         }
                               4127                 : 
  537 alvherre                 4128 ECB             :         /*
                               4129                 :          * We allow mismatched statement and object types (e.g., ALTER INDEX
                               4130                 :          * to rename a table), but we might've used the wrong lock level.  If
                               4131                 :          * that happens, retry with the correct lock level.  We don't bother
  537 alvherre                 4132 EUB             :          * if we already acquired AccessExclusiveLock with an index, however.
                               4133                 :          */
  537 alvherre                 4134 GIC         227 :         relkind = get_rel_relkind(relid);
                               4135             227 :         obj_is_index = (relkind == RELKIND_INDEX ||
                               4136                 :                         relkind == RELKIND_PARTITIONED_INDEX);
                               4137             227 :         if (obj_is_index || is_index_stmt == obj_is_index)
                               4138                 :             break;
                               4139                 : 
                               4140               6 :         UnlockRelationOid(relid, lockmode);
                               4141               6 :         is_index_stmt = obj_is_index;
                               4142                 :     }
                               4143                 : 
                               4144                 :     /* Do the work */
                               4145             221 :     RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
 3759 rhaas                    4146 ECB             : 
 2959 alvherre                 4147 CBC         215 :     ObjectAddressSet(address, RelationRelationId, relid);
                               4148                 : 
 2959 alvherre                 4149 GIC         215 :     return address;
                               4150                 : }
                               4151                 : 
                               4152                 : /*
 5499 tgl                      4153 ECB             :  *      RenameRelationInternal - change the name of a relation
                               4154                 :  */
                               4155                 : void
 1627 peter_e                  4156 CBC         575 : RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
                               4157                 : {
 5499 tgl                      4158 ECB             :     Relation    targetrelation;
                               4159                 :     Relation    relrelation;    /* for RELATION relation */
                               4160                 :     HeapTuple   reltup;
                               4161                 :     Form_pg_class relform;
 4133 rhaas                    4162                 :     Oid         namespaceId;
                               4163                 : 
 5499 tgl                      4164                 :     /*
                               4165                 :      * Grab a lock on the target relation, which we will NOT release until end
 1627 peter_e                  4166                 :      * of transaction.  We need at least a self-exclusive lock so that
                               4167                 :      * concurrent DDL doesn't overwrite the rename if they start updating
                               4168                 :      * while still seeing the old version.  The lock also guards against
                               4169                 :      * triggering relcache reloads in concurrent sessions, which might not
                               4170                 :      * handle this information changing under them.  For indexes, we can use a
                               4171                 :      * reduced lock level because RelationReloadIndexInfo() handles indexes
                               4172                 :      * specially.
                               4173                 :      */
 1627 peter_e                  4174 GIC         575 :     targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
 4133 rhaas                    4175 CBC         575 :     namespaceId = RelationGetNamespace(targetrelation);
                               4176                 : 
                               4177                 :     /*
                               4178                 :      * Find relation's pg_class tuple, and make sure newrelname isn't in use.
                               4179                 :      */
 1539 andres                   4180 GIC         575 :     relrelation = table_open(RelationRelationId, RowExclusiveLock);
 7984 bruce                    4181 ECB             : 
 4802 rhaas                    4182 CBC         575 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
 2118 tgl                      4183             575 :     if (!HeapTupleIsValid(reltup))  /* shouldn't happen */
 7203 tgl                      4184 LBC           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
 5811 tgl                      4185 CBC         575 :     relform = (Form_pg_class) GETSTRUCT(reltup);
 7681 tgl                      4186 ECB             : 
 7653 tgl                      4187 GIC         575 :     if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
 7203                          4188               6 :         ereport(ERROR,
                               4189                 :                 (errcode(ERRCODE_DUPLICATE_TABLE),
                               4190                 :                  errmsg("relation \"%s\" already exists",
                               4191                 :                         newrelname)));
                               4192                 : 
                               4193                 :     /*
                               4194                 :      * RenameRelation is careful not to believe the caller's idea of the
  537 alvherre                 4195 ECB             :      * relation kind being handled.  We don't have to worry about this, but
                               4196                 :      * let's not be totally oblivious to it.  We can process an index as
                               4197                 :      * not-an-index, but not the other way around.
                               4198                 :      */
  537 alvherre                 4199 GIC         569 :     Assert(!is_index ||
                               4200                 :            is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
                               4201                 :                         targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
  537 alvherre                 4202 ECB             : 
 7984 bruce                    4203                 :     /*
                               4204                 :      * Update pg_class tuple with new relname.  (Scribbling on reltup is OK
                               4205                 :      * because it's a copy...)
                               4206                 :      */
 5811 tgl                      4207 CBC         569 :     namestrcpy(&(relform->relname), newrelname);
                               4208                 : 
 2259 alvherre                 4209             569 :     CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
                               4210                 : 
 3675 rhaas                    4211 GIC         569 :     InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
 3675 rhaas                    4212 ECB             :                                  InvalidOid, is_internal);
                               4213                 : 
 7653 tgl                      4214 GIC         569 :     heap_freetuple(reltup);
 1539 andres                   4215             569 :     table_close(relrelation, RowExclusiveLock);
 7984 bruce                    4216 ECB             : 
                               4217                 :     /*
 7653 tgl                      4218                 :      * Also rename the associated type, if any.
 7984 bruce                    4219                 :      */
 5811 tgl                      4220 GIC         569 :     if (OidIsValid(targetrelation->rd_rel->reltype))
 5499                          4221              62 :         RenameTypeInternal(targetrelation->rd_rel->reltype,
                               4222                 :                            newrelname, namespaceId);
                               4223                 : 
 5561 tgl                      4224 ECB             :     /*
                               4225                 :      * Also rename the associated constraint, if any.
                               4226                 :      */
 1906 alvherre                 4227 GIC         569 :     if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
                               4228             308 :         targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
                               4229                 :     {
 5561 tgl                      4230             270 :         Oid         constraintId = get_index_constraint(myrelid);
                               4231                 : 
                               4232             270 :         if (OidIsValid(constraintId))
 5561 tgl                      4233 CBC          18 :             RenameConstraintById(constraintId, newrelname);
                               4234                 :     }
                               4235                 : 
                               4236                 :     /*
                               4237                 :      * Close rel, but keep lock!
                               4238                 :      */
 7653 tgl                      4239 GIC         569 :     relation_close(targetrelation, NoLock);
  592 akapila                  4240             569 : }
  592 akapila                  4241 ECB             : 
                               4242                 : /*
                               4243                 :  *      ResetRelRewrite - reset relrewrite
                               4244                 :  */
                               4245                 : void
  592 akapila                  4246 GIC         170 : ResetRelRewrite(Oid myrelid)
  592 akapila                  4247 ECB             : {
                               4248                 :     Relation    relrelation;    /* for RELATION relation */
                               4249                 :     HeapTuple   reltup;
                               4250                 :     Form_pg_class relform;
                               4251                 : 
                               4252                 :     /*
                               4253                 :      * Find relation's pg_class tuple.
                               4254                 :      */
  592 akapila                  4255 CBC         170 :     relrelation = table_open(RelationRelationId, RowExclusiveLock);
                               4256                 : 
  592 akapila                  4257 GIC         170 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
                               4258             170 :     if (!HeapTupleIsValid(reltup))  /* shouldn't happen */
  592 akapila                  4259 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
  592 akapila                  4260 GIC         170 :     relform = (Form_pg_class) GETSTRUCT(reltup);
  592 akapila                  4261 ECB             : 
                               4262                 :     /*
                               4263                 :      * Update pg_class tuple.
                               4264                 :      */
  592 akapila                  4265 GIC         170 :     relform->relrewrite = InvalidOid;
  592 akapila                  4266 ECB             : 
  592 akapila                  4267 CBC         170 :     CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
  592 akapila                  4268 EUB             : 
  592 akapila                  4269 GIC         170 :     heap_freetuple(reltup);
  592 akapila                  4270 CBC         170 :     table_close(relrelation, RowExclusiveLock);
 7653 tgl                      4271 GIC         170 : }
 7984 bruce                    4272 ECB             : 
 5548 tgl                      4273                 : /*
                               4274                 :  * Disallow ALTER TABLE (and similar commands) when the current backend has
                               4275                 :  * any open reference to the target table besides the one just acquired by
                               4276                 :  * the calling command; this implies there's an open cursor or active plan.
 4638 simon                    4277                 :  * We need this check because our lock doesn't protect us against stomping
                               4278                 :  * on our own foot, only other people's feet!
                               4279                 :  *
                               4280                 :  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
                               4281                 :  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
                               4282                 :  * possibly be relaxed to only error out for certain types of alterations.
                               4283                 :  * But the use-case for allowing any of these things is not obvious, so we
 5548 tgl                      4284                 :  * won't work hard at it for now.
                               4285                 :  *
                               4286                 :  * We also reject these commands if there are any pending AFTER trigger events
                               4287                 :  * for the rel.  This is certainly necessary for the rewriting variants of
                               4288                 :  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
 3260 bruce                    4289                 :  * events would try to fetch the wrong tuples.  It might be overly cautious
 5548 tgl                      4290                 :  * in other cases, but again it seems better to err on the side of paranoia.
                               4291                 :  *
                               4292                 :  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
                               4293                 :  * we are worried about active indexscans on the index.  The trigger-event
                               4294                 :  * check can be skipped, since we are doing no damage to the parent table.
                               4295                 :  *
                               4296                 :  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
                               4297                 :  */
                               4298                 : void
 5548 tgl                      4299 GIC       90091 : CheckTableNotInUse(Relation rel, const char *stmt)
 5548 tgl                      4300 ECB             : {
                               4301                 :     int         expected_refcnt;
                               4302                 : 
 5548 tgl                      4303 GIC       90091 :     expected_refcnt = rel->rd_isnailed ? 2 : 1;
                               4304           90091 :     if (rel->rd_refcnt != expected_refcnt)
                               4305              12 :         ereport(ERROR,
                               4306                 :                 (errcode(ERRCODE_OBJECT_IN_USE),
                               4307                 :         /* translator: first %s is a SQL command, eg ALTER TABLE */
 1356 alvherre                 4308 ECB             :                  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
 5548 tgl                      4309                 :                         stmt, RelationGetRelationName(rel))));
                               4310                 : 
 5548 tgl                      4311 GIC       90079 :     if (rel->rd_rel->relkind != RELKIND_INDEX &&
 1906 alvherre                 4312          154916 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
 5548 tgl                      4313           77014 :         AfterTriggerPendingOnRel(RelationGetRelid(rel)))
                               4314               9 :         ereport(ERROR,
 5548 tgl                      4315 ECB             :                 (errcode(ERRCODE_OBJECT_IN_USE),
 5050 bruce                    4316                 :         /* translator: first %s is a SQL command, eg ALTER TABLE */
 1356 alvherre                 4317                 :                  errmsg("cannot %s \"%s\" because it has pending trigger events",
 5548 tgl                      4318 EUB             :                         stmt, RelationGetRelationName(rel))));
 5548 tgl                      4319 GIC       90070 : }
 5548 tgl                      4320 ECB             : 
                               4321                 : /*
 4111 rhaas                    4322                 :  * AlterTableLookupRelation
                               4323                 :  *      Look up, and lock, the OID for the relation named by an alter table
                               4324                 :  *      statement.
                               4325                 :  */
                               4326                 : Oid
 4111 rhaas                    4327 GIC       44953 : AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
 4111 rhaas                    4328 ECB             : {
 1836 andres                   4329 GIC       89864 :     return RangeVarGetRelidExtended(stmt->relation, lockmode,
                               4330           44953 :                                     stmt->missing_ok ? RVR_MISSING_OK : 0,
                               4331                 :                                     RangeVarCallbackForAlterRelation,
                               4332                 :                                     (void *) stmt);
 4111 rhaas                    4333 ECB             : }
                               4334                 : 
 6913 tgl                      4335                 : /*
                               4336                 :  * AlterTable
                               4337                 :  *      Execute ALTER TABLE, which can be a list of subcommands
                               4338                 :  *
                               4339                 :  * ALTER TABLE is performed in three phases:
                               4340                 :  *      1. Examine subcommands and perform pre-transformation checking.
                               4341                 :  *      2. Validate and transform subcommands, and update system catalogs.
                               4342                 :  *      3. Scan table(s) to check new constraints, and optionally recopy
                               4343                 :  *         the data into new table(s).
                               4344                 :  * Phase 3 is not performed unless one or more of the subcommands requires
 3260 bruce                    4345                 :  * it.  The intention of this design is to allow multiple independent
                               4346                 :  * updates of the table schema to be performed with only one pass over the
 6913 tgl                      4347                 :  * data.
                               4348                 :  *
                               4349                 :  * ATPrepCmd performs phase 1.  A "work queue" entry is created for
                               4350                 :  * each table to be affected (there may be multiple affected tables if the
                               4351                 :  * commands traverse a table inheritance hierarchy).  Also we do preliminary
 1180                          4352                 :  * validation of the subcommands.  Because earlier subcommands may change
                               4353                 :  * the catalog state seen by later commands, there are limits to what can
                               4354                 :  * be done in this phase.  Generally, this phase acquires table locks,
                               4355                 :  * checks permissions and relkind, and recurses to find child tables.
 6913 tgl                      4356 EUB             :  *
  248 alvherre                 4357 ECB             :  * ATRewriteCatalogs performs phase 2 for each affected table.
 6913 tgl                      4358                 :  * Certain subcommands need to be performed before others to avoid
                               4359                 :  * unnecessary conflicts; for example, DROP COLUMN should come before
                               4360                 :  * ADD COLUMN.  Therefore phase 1 divides the subcommands into multiple
                               4361                 :  * lists, one for each logical "pass" of phase 2.
                               4362                 :  *
                               4363                 :  * ATRewriteTables performs phase 3 for those tables that need it.
                               4364                 :  *
  248 alvherre                 4365                 :  * For most subcommand types, phases 2 and 3 do no explicit recursion,
                               4366                 :  * since phase 1 already does it.  However, for certain subcommand types
                               4367                 :  * it is only possible to determine how to recurse at phase 2 time; for
                               4368                 :  * those cases, phase 1 sets the cmd->recurse flag.
                               4369                 :  *
                               4370                 :  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
                               4371                 :  * the whole operation; we don't have to do anything special to clean up.
 4638 simon                    4372                 :  *
                               4373                 :  * The caller must lock the relation, with an appropriate lock level
                               4374                 :  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
                               4375                 :  * or higher. We pass the lock level down
                               4376                 :  * so that we can apply it recursively to inherited tables. Note that the
 4111 rhaas                    4377                 :  * lock level we want as we recurse might well be higher than required for
 4638 simon                    4378                 :  * that specific subcommand. So we pass down the overall lock requirement,
                               4379                 :  * rather than reassess it at lower levels.
 1180 tgl                      4380                 :  *
                               4381                 :  * The caller also provides a "context" which is to be passed back to
                               4382                 :  * utility.c when we need to execute a subcommand such as CREATE INDEX.
                               4383                 :  * Some of the fields therein, such as the relid, are used here as well.
                               4384                 :  */
                               4385                 : void
 1180 tgl                      4386 GIC       44842 : AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
                               4387                 :            AlterTableUtilityContext *context)
                               4388                 : {
                               4389                 :     Relation    rel;
                               4390                 : 
 4111 rhaas                    4391 ECB             :     /* Caller is required to provide an adequate lock. */
 1180 tgl                      4392 GIC       44842 :     rel = relation_open(context->relid, NoLock);
 5576 tgl                      4393 ECB             : 
 5548 tgl                      4394 GIC       44842 :     CheckTableNotInUse(rel, "ALTER TABLE");
                               4395                 : 
 1180                          4396           44833 :     ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
 5576                          4397           43514 : }
                               4398                 : 
                               4399                 : /*
                               4400                 :  * AlterTableInternal
                               4401                 :  *
                               4402                 :  * ALTER TABLE with target specified by OID
                               4403                 :  *
                               4404                 :  * We do not reject if the relation is already open, because it's quite
                               4405                 :  * likely that one or more layers of caller have it open.  That means it
                               4406                 :  * is unsafe to use this entry point for alterations that could break
 5576 tgl                      4407 ECB             :  * existing query plans.  On the assumption it's not used for such, we
                               4408                 :  * don't have to reject pending AFTER triggers, either.
                               4409                 :  *
                               4410                 :  * Also, since we don't have an AlterTableUtilityContext, this cannot be
                               4411                 :  * used for any subcommand types that require parse transformation or
 1180                          4412                 :  * could generate subcommands that have to be passed to ProcessUtility.
                               4413                 :  */
 8315 JanWieck                 4414                 : void
 6913 tgl                      4415 CBC         139 : AlterTableInternal(Oid relid, List *cmds, bool recurse)
                               4416                 : {
                               4417                 :     Relation    rel;
 4382 bruce                    4418 GIC         139 :     LOCKMODE    lockmode = AlterTableGetLockLevel(cmds);
 5910 tgl                      4419 ECB             : 
 4638 simon                    4420 GIC         139 :     rel = relation_open(relid, lockmode);
 4638 simon                    4421 ECB             : 
 2890 alvherre                 4422 GIC         139 :     EventTriggerAlterTableRelid(relid);
                               4423                 : 
 1180 tgl                      4424 CBC         139 :     ATController(NULL, rel, cmds, recurse, lockmode, NULL);
 4638 simon                    4425 GIC         139 : }
                               4426                 : 
                               4427                 : /*
                               4428                 :  * AlterTableGetLockLevel
                               4429                 :  *
                               4430                 :  * Sets the overall lock level required for the supplied list of subcommands.
                               4431                 :  * Policy for doing this set according to needs of AlterTable(), see
                               4432                 :  * comments there for overall explanation.
 4638 simon                    4433 ECB             :  *
                               4434                 :  * Function is called before and after parsing, so it must give same
                               4435                 :  * answer each time it is called. Some subcommands are transformed
                               4436                 :  * into other subcommand types, so the transform must never be made to a
                               4437                 :  * lower lock level than previously assigned. All transforms are noted below.
                               4438                 :  *
                               4439                 :  * Since this is called before we lock the table we cannot use table metadata
                               4440                 :  * to influence the type of lock we acquire.
                               4441                 :  *
                               4442                 :  * There should be no lockmodes hardcoded into the subcommand functions. All
                               4443                 :  * lockmode decisions for ALTER TABLE are made here only. The one exception is
                               4444                 :  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
                               4445                 :  * and does not travel through this section of code and cannot be combined with
                               4446                 :  * any of the subcommands given here.
                               4447                 :  *
 1029 andres                   4448                 :  * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
                               4449                 :  * so any changes that might affect SELECTs running on standbys need to use
                               4450                 :  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
                               4451                 :  * have a solution for that also.
                               4452                 :  *
                               4453                 :  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
                               4454                 :  * that takes a lock less than AccessExclusiveLock can change object definitions
 3290 simon                    4455                 :  * while pg_dump is running. Be careful to check that the appropriate data is
                               4456                 :  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
                               4457                 :  * otherwise we might end up with an inconsistent dump that can't restore.
                               4458                 :  */
                               4459                 : LOCKMODE
 4638 simon                    4460 GIC       45092 : AlterTableGetLockLevel(List *cmds)
                               4461                 : {
                               4462                 :     /*
                               4463                 :      * This only works if we read catalog tables using MVCC snapshots.
                               4464                 :      */
                               4465                 :     ListCell   *lcmd;
 4382 bruce                    4466           45092 :     LOCKMODE    lockmode = ShareUpdateExclusiveLock;
                               4467                 : 
 4638 simon                    4468           90928 :     foreach(lcmd, cmds)
                               4469                 :     {
                               4470           45836 :         AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
 4382 bruce                    4471           45836 :         LOCKMODE    cmd_lockmode = AccessExclusiveLock; /* default for compiler */
                               4472                 : 
 4638 simon                    4473 CBC       45836 :         switch (cmd->subtype)
 4638 simon                    4474 ECB             :         {
                               4475                 :                 /*
                               4476                 :                  * These subcommands rewrite the heap, so require full locks.
                               4477                 :                  */
 4382 bruce                    4478 GIC        1490 :             case AT_AddColumn:  /* may rewrite heap, in some cases and visible
 4382 bruce                    4479 ECB             :                                  * to SELECT */
                               4480                 :             case AT_SetAccessMethod:    /* must rewrite heap */
 2118 tgl                      4481                 :             case AT_SetTableSpace:  /* must rewrite heap */
 4638 simon                    4482                 :             case AT_AlterColumnType:    /* must rewrite heap */
 3290 simon                    4483 GBC        1490 :                 cmd_lockmode = AccessExclusiveLock;
 3290 simon                    4484 CBC        1490 :                 break;
                               4485                 : 
 3290 simon                    4486 ECB             :                 /*
 3260 bruce                    4487                 :                  * These subcommands may require addition of toast tables. If
                               4488                 :                  * we add a toast table to a table currently being scanned, we
                               4489                 :                  * might miss data added to the new toast table by concurrent
                               4490                 :                  * insert transactions.
                               4491                 :                  */
 2118 tgl                      4492 GIC         104 :             case AT_SetStorage: /* may add toast tables, see
                               4493                 :                                  * ATRewriteCatalogs() */
 3290 simon                    4494             104 :                 cmd_lockmode = AccessExclusiveLock;
                               4495             104 :                 break;
                               4496                 : 
                               4497                 :                 /*
 3290 simon                    4498 ECB             :                  * Removing constraints can affect SELECTs that have been
                               4499                 :                  * optimized assuming the constraint holds true. See also
                               4500                 :                  * CloneFkReferenced.
                               4501                 :                  */
 2118 tgl                      4502 GIC         393 :             case AT_DropConstraint: /* as DROP INDEX */
                               4503                 :             case AT_DropNotNull:    /* may change some SQL plans */
 3290 simon                    4504             393 :                 cmd_lockmode = AccessExclusiveLock;
                               4505             393 :                 break;
 3290 simon                    4506 ECB             : 
                               4507                 :                 /*
                               4508                 :                  * Subcommands that may be visible to concurrent SELECTs
                               4509                 :                  */
 2118 tgl                      4510 CBC         814 :             case AT_DropColumn: /* change visible to SELECT */
                               4511                 :             case AT_AddColumnToView:    /* CREATE VIEW */
                               4512                 :             case AT_DropOids:   /* used to equiv to DropColumn */
 4638 simon                    4513 ECB             :             case AT_EnableAlwaysRule:   /* may change SELECT rules */
                               4514                 :             case AT_EnableReplicaRule:  /* may change SELECT rules */
                               4515                 :             case AT_EnableRule: /* may change SELECT rules */
                               4516                 :             case AT_DisableRule:    /* may change SELECT rules */
 3290 simon                    4517 GIC         814 :                 cmd_lockmode = AccessExclusiveLock;
                               4518             814 :                 break;
 3290 simon                    4519 ECB             : 
                               4520                 :                 /*
                               4521                 :                  * Changing owner may remove implicit SELECT privileges
                               4522                 :                  */
 2118 tgl                      4523 GIC         861 :             case AT_ChangeOwner:    /* change visible to SELECT */
 3290 simon                    4524             861 :                 cmd_lockmode = AccessExclusiveLock;
                               4525             861 :                 break;
 3290 simon                    4526 ECB             : 
                               4527                 :                 /*
                               4528                 :                  * Changing foreign table options may affect optimization.
                               4529                 :                  */
 4481 rhaas                    4530 GIC         117 :             case AT_GenericOptions:
 4265 rhaas                    4531 ECB             :             case AT_AlterColumnGenericOptions:
 4638 simon                    4532 CBC         117 :                 cmd_lockmode = AccessExclusiveLock;
 4638 simon                    4533 GIC         117 :                 break;
                               4534                 : 
                               4535                 :                 /*
                               4536                 :                  * These subcommands affect write operations only.
                               4537                 :                  */
 4638 simon                    4538 CBC         168 :             case AT_EnableTrig:
 4638 simon                    4539 ECB             :             case AT_EnableAlwaysTrig:
                               4540                 :             case AT_EnableReplicaTrig:
                               4541                 :             case AT_EnableTrigAll:
                               4542                 :             case AT_EnableTrigUser:
                               4543                 :             case AT_DisableTrig:
                               4544                 :             case AT_DisableTrigAll:
                               4545                 :             case AT_DisableTrigUser:
 2926 simon                    4546 GIC         168 :                 cmd_lockmode = ShareRowExclusiveLock;
                               4547             168 :                 break;
                               4548                 : 
                               4549                 :                 /*
                               4550                 :                  * These subcommands affect write operations only. XXX
                               4551                 :                  * Theoretically, these could be ShareRowExclusiveLock.
                               4552                 :                  */
                               4553            4135 :             case AT_ColumnDefault:
  961 tgl                      4554 ECB             :             case AT_CookedColumnDefault:
                               4555                 :             case AT_AlterConstraint:
 4382 bruce                    4556                 :             case AT_AddIndex:   /* from ADD CONSTRAINT */
 4457 tgl                      4557                 :             case AT_AddIndexConstraint:
 3439 rhaas                    4558 EUB             :             case AT_ReplicaIdentity:
 3290 simon                    4559 ECB             :             case AT_SetNotNull:
                               4560                 :             case AT_SetAttNotNull:
                               4561                 :             case AT_EnableRowSecurity:
                               4562                 :             case AT_DisableRowSecurity:
                               4563                 :             case AT_ForceRowSecurity:
                               4564                 :             case AT_NoForceRowSecurity:
 2194 peter_e                  4565                 :             case AT_AddIdentity:
                               4566                 :             case AT_DropIdentity:
                               4567                 :             case AT_SetIdentity:
                               4568                 :             case AT_DropExpression:
  751 rhaas                    4569                 :             case AT_SetCompression:
 3290 simon                    4570 CBC        4135 :                 cmd_lockmode = AccessExclusiveLock;
 4638                          4571            4135 :                 break;
                               4572                 : 
 4638 simon                    4573 GIC       35237 :             case AT_AddConstraint:
                               4574                 :             case AT_ReAddConstraint:    /* becomes AT_AddConstraint */
                               4575                 :             case AT_ReAddDomainConstraint:  /* becomes AT_AddConstraint */
                               4576           35237 :                 if (IsA(cmd->def, Constraint))
                               4577                 :                 {
                               4578           35237 :                     Constraint *con = (Constraint *) cmd->def;
                               4579                 : 
                               4580           35237 :                     switch (con->contype)
                               4581                 :                     {
                               4582           33818 :                         case CONSTR_EXCLUSION:
                               4583                 :                         case CONSTR_PRIMARY:
                               4584                 :                         case CONSTR_UNIQUE:
                               4585                 : 
                               4586                 :                             /*
                               4587                 :                              * Cases essentially the same as CREATE INDEX. We
                               4588                 :                              * could reduce the lock strength to ShareLock if
                               4589                 :                              * we can work out how to allow concurrent catalog
                               4590                 :                              * updates. XXX Might be set down to
                               4591                 :                              * ShareRowExclusiveLock but requires further
                               4592                 :                              * analysis.
                               4593                 :                              */
 3290                          4594           33818 :                             cmd_lockmode = AccessExclusiveLock;
 4638                          4595           33818 :                             break;
                               4596            1000 :                         case CONSTR_FOREIGN:
                               4597                 : 
 4638 simon                    4598 ECB             :                             /*
                               4599                 :                              * We add triggers to both tables when we add a
                               4600                 :                              * Foreign Key, so the lock level must be at least
                               4601                 :                              * as strong as CREATE TRIGGER.
                               4602                 :                              */
 2926 simon                    4603 CBC        1000 :                             cmd_lockmode = ShareRowExclusiveLock;
 4638                          4604            1000 :                             break;
                               4605                 : 
 4638 simon                    4606 GIC         419 :                         default:
 3290                          4607             419 :                             cmd_lockmode = AccessExclusiveLock;
                               4608                 :                     }
                               4609                 :                 }
 4638 simon                    4610 CBC       35237 :                 break;
 4638 simon                    4611 ECB             : 
 4382 bruce                    4612                 :                 /*
                               4613                 :                  * These subcommands affect inheritance behaviour. Queries
                               4614                 :                  * started before us will continue to see the old inheritance
                               4615                 :                  * behaviour, while queries started after we commit will see
                               4616                 :                  * new behaviour. No need to prevent reads or writes to the
                               4617                 :                  * subtable while we hook it up though. Changing the TupDesc
 3260                          4618                 :                  * may be a problem, so keep highest lock.
                               4619                 :                  */
 4638 simon                    4620 GIC         165 :             case AT_AddInherit:
                               4621                 :             case AT_DropInherit:
 3290                          4622             165 :                 cmd_lockmode = AccessExclusiveLock;
 4638                          4623             165 :                 break;
                               4624                 : 
                               4625                 :                 /*
 4372 rhaas                    4626 ECB             :                  * These subcommands affect implicit row type conversion. They
                               4627                 :                  * have affects similar to CREATE/DROP CAST on queries. don't
 3260 bruce                    4628                 :                  * provide for invalidating parse trees as a result of such
                               4629                 :                  * changes, so we keep these at AccessExclusiveLock.
                               4630                 :                  */
 4372 rhaas                    4631 GIC          36 :             case AT_AddOf:
                               4632                 :             case AT_DropOf:
 3290 simon                    4633              36 :                 cmd_lockmode = AccessExclusiveLock;
                               4634              36 :                 break;
                               4635                 : 
                               4636                 :                 /*
                               4637                 :                  * Only used by CREATE OR REPLACE VIEW which must conflict
                               4638                 :                  * with an SELECTs currently using the view.
                               4639                 :                  */
                               4640              97 :             case AT_ReplaceRelOptions:
                               4641              97 :                 cmd_lockmode = AccessExclusiveLock;
                               4642              97 :                 break;
                               4643                 : 
                               4644                 :                 /*
                               4645                 :                  * These subcommands affect general strategies for performance
                               4646                 :                  * and maintenance, though don't change the semantic results
                               4647                 :                  * from normal data reads and writes. Delaying an ALTER TABLE
                               4648                 :                  * behind currently active writes only delays the point where
                               4649                 :                  * the new strategy begins to take effect, so there is no
                               4650                 :                  * benefit in waiting. In this case the minimum restriction
                               4651                 :                  * applies: we don't currently allow concurrent catalog
                               4652                 :                  * updates.
                               4653                 :                  */
 2118 tgl                      4654             117 :             case AT_SetStatistics:  /* Uses MVCC in getTableAttrs() */
                               4655                 :             case AT_ClusterOn:  /* Uses MVCC in getIndexes() */
                               4656                 :             case AT_DropCluster:    /* Uses MVCC in getIndexes() */
                               4657                 :             case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
                               4658                 :             case AT_ResetOptions:   /* Uses MVCC in getTableAttrs() */
 4638 simon                    4659             117 :                 cmd_lockmode = ShareUpdateExclusiveLock;
                               4660             117 :                 break;
                               4661                 : 
 3152 alvherre                 4662              35 :             case AT_SetLogged:
                               4663                 :             case AT_SetUnLogged:
                               4664              35 :                 cmd_lockmode = AccessExclusiveLock;
                               4665              35 :                 break;
                               4666                 : 
 2118 tgl                      4667             194 :             case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
 3290 simon                    4668             194 :                 cmd_lockmode = ShareUpdateExclusiveLock;
                               4669             194 :                 break;
                               4670                 : 
                               4671                 :                 /*
                               4672                 :                  * Rel options are more complex than first appears. Options
                               4673                 :                  * are set here for tables, views and indexes; for historical
                               4674                 :                  * reasons these can all be used with ALTER TABLE, so we can't
                               4675                 :                  * decide between them using the basic grammar.
                               4676                 :                  */
 2118 tgl                      4677             367 :             case AT_SetRelOptions:  /* Uses MVCC in getIndexes() and
                               4678                 :                                      * getTables() */
                               4679                 :             case AT_ResetRelOptions:    /* Uses MVCC in getIndexes() and
                               4680                 :                                          * getTables() */
 2795 simon                    4681             367 :                 cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
 3290                          4682             367 :                 break;
                               4683                 : 
 2314 rhaas                    4684            1241 :             case AT_AttachPartition:
 1494 rhaas                    4685 CBC        1241 :                 cmd_lockmode = ShareUpdateExclusiveLock;
 1494 rhaas                    4686 GIC        1241 :                 break;
                               4687                 : 
 2314                          4688             258 :             case AT_DetachPartition:
  745 alvherre                 4689             258 :                 if (((PartitionCmd *) cmd->def)->concurrent)
                               4690              79 :                     cmd_lockmode = ShareUpdateExclusiveLock;
  745 alvherre                 4691 ECB             :                 else
  745 alvherre                 4692 GIC         179 :                     cmd_lockmode = AccessExclusiveLock;
  745 alvherre                 4693 CBC         258 :                 break;
                               4694                 : 
                               4695               7 :             case AT_DetachPartitionFinalize:
                               4696               7 :                 cmd_lockmode = ShareUpdateExclusiveLock;
 2314 rhaas                    4697 GIC           7 :                 break;
                               4698                 : 
 1447 tgl                      4699 UIC           0 :             case AT_CheckNotNull:
                               4700                 : 
                               4701                 :                 /*
                               4702                 :                  * This only examines the table's schema; but lock must be
                               4703                 :                  * strong enough to prevent concurrent DROP NOT NULL.
                               4704                 :                  */
                               4705               0 :                 cmd_lockmode = AccessShareLock;
                               4706               0 :                 break;
                               4707                 : 
 4382 bruce                    4708               0 :             default:            /* oops */
 4638 simon                    4709               0 :                 elog(ERROR, "unrecognized alter table type: %d",
                               4710                 :                      (int) cmd->subtype);
                               4711                 :                 break;
                               4712                 :         }
                               4713                 : 
 4638 simon                    4714 ECB             :         /*
                               4715                 :          * Take the greatest lockmode from any subcommand
                               4716                 :          */
 4638 simon                    4717 CBC       45836 :         if (cmd_lockmode > lockmode)
 4638 simon                    4718 GIC       43180 :             lockmode = cmd_lockmode;
 4638 simon                    4719 ECB             :     }
                               4720                 : 
 4638 simon                    4721 CBC       45092 :     return lockmode;
                               4722                 : }
 8315 JanWieck                 4723 ECB             : 
 3044 simon                    4724                 : /*
                               4725                 :  * ATController provides top level control over the phases.
                               4726                 :  *
                               4727                 :  * parsetree is passed in to allow it to be passed to event triggers
                               4728                 :  * when requested.
                               4729                 :  */
                               4730                 : static void
 3044 simon                    4731 GIC       44972 : ATController(AlterTableStmt *parsetree,
                               4732                 :              Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
                               4733                 :              AlterTableUtilityContext *context)
                               4734                 : {
 6913 tgl                      4735           44972 :     List       *wqueue = NIL;
                               4736                 :     ListCell   *lcmd;
                               4737                 : 
                               4738                 :     /* Phase 1: preliminary examination of commands, create work queue */
                               4739           90549 :     foreach(lcmd, cmds)
                               4740                 :     {
                               4741           45713 :         AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
                               4742                 : 
 1180                          4743           45713 :         ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
                               4744                 :     }
                               4745                 : 
                               4746                 :     /* Close the relation, but keep lock until commit */
 6913                          4747           44836 :     relation_close(rel, NoLock);
                               4748                 : 
                               4749                 :     /* Phase 2: update system catalogs */
 1180                          4750           44836 :     ATRewriteCatalogs(&wqueue, lockmode, context);
                               4751                 : 
                               4752                 :     /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
                               4753           43800 :     ATRewriteTables(parsetree, &wqueue, lockmode, context);
 6913                          4754           43653 : }
                               4755                 : 
                               4756                 : /*
                               4757                 :  * ATPrepCmd
                               4758                 :  *
 6869 tgl                      4759 ECB             :  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
                               4760                 :  * recursion and permission checks.
                               4761                 :  *
                               4762                 :  * Caller must have acquired appropriate lock type on relation already.
                               4763                 :  * This lock should be held until commit.
                               4764                 :  */
 6913                          4765                 : static void
 6913 tgl                      4766 GIC       45921 : ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 1180 tgl                      4767 ECB             :           bool recurse, bool recursing, LOCKMODE lockmode,
                               4768                 :           AlterTableUtilityContext *context)
 6913                          4769                 : {
                               4770                 :     AlteredTableInfo *tab;
 3571 simon                    4771 GIC       45921 :     int         pass = AT_PASS_UNSET;
 6913 tgl                      4772 ECB             : 
                               4773                 :     /* Find or create work queue entry for this table */
 6913 tgl                      4774 GIC       45921 :     tab = ATGetQueueEntry(wqueue, rel);
                               4775                 : 
                               4776                 :     /*
  745 alvherre                 4777 ECB             :      * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
                               4778                 :      * partitions that are pending detach.
                               4779                 :      */
  745 alvherre                 4780 GIC       45921 :     if (rel->rd_rel->relispartition &&
                               4781            1124 :         cmd->subtype != AT_DetachPartitionFinalize &&
  745 alvherre                 4782 CBC         562 :         PartitionHasPendingDetach(RelationGetRelid(rel)))
                               4783               1 :         ereport(ERROR,
                               4784                 :                 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               4785                 :                 errmsg("cannot alter partition \"%s\" with an incomplete detach",
                               4786                 :                        RelationGetRelationName(rel)),
                               4787                 :                 errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
                               4788                 : 
                               4789                 :     /*
                               4790                 :      * Copy the original subcommand for each table, so we can scribble on it.
  248 alvherre                 4791 ECB             :      * This avoids conflicts when different child tables need to make
                               4792                 :      * different parse transformations (for example, the same column may have
                               4793                 :      * different column numbers in different children).
 7653 tgl                      4794                 :      */
 6913 tgl                      4795 GIC       45920 :     cmd = copyObject(cmd);
                               4796                 : 
                               4797                 :     /*
                               4798                 :      * Do permissions and relkind checking, recursion to child tables if
                               4799                 :      * needed, and any additional phase-1 processing needed.  (But beware of
                               4800                 :      * adding any processing that looks at table details that another
 1180 tgl                      4801 ECB             :      * subcommand could change.  In some cases we reject multiple subcommands
                               4802                 :      * that could try to change the same state in contrary ways.)
 8313 JanWieck                 4803                 :      */
 6913 tgl                      4804 CBC       45920 :     switch (cmd->subtype)
                               4805                 :     {
 6913 tgl                      4806 GIC         911 :         case AT_AddColumn:      /* ADD COLUMN */
  640 peter                    4807             911 :             ATSimplePermissions(cmd->subtype, rel,
                               4808                 :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
 2963 alvherre                 4809 CBC         911 :             ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
                               4810                 :                             lockmode, context);
                               4811                 :             /* Recursion occurs during execution phase */
 6913 tgl                      4812 GIC         905 :             pass = AT_PASS_ADD_COL;
                               4813             905 :             break;
 2118                          4814              12 :         case AT_AddColumnToView:    /* add column via CREATE OR REPLACE VIEW */
  640 peter                    4815              12 :             ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
 2963 alvherre                 4816 CBC          12 :             ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
 1180 tgl                      4817 ECB             :                             lockmode, context);
                               4818                 :             /* Recursion occurs during execution phase */
 5237 bruce                    4819 GIC          12 :             pass = AT_PASS_ADD_COL;
                               4820              12 :             break;
 6913 tgl                      4821             266 :         case AT_ColumnDefault:  /* ALTER COLUMN DEFAULT */
 6797 bruce                    4822 ECB             : 
 6913 tgl                      4823                 :             /*
 6385 bruce                    4824                 :              * We allow defaults on views so that INSERT into a view can have
                               4825                 :              * default-ish behavior.  This works because the rewriter
                               4826                 :              * substitutes default values into INSERTs before it expands
                               4827                 :              * rules.
                               4828                 :              */
  640 peter                    4829 CBC         266 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
 1180 tgl                      4830 GIC         266 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
 6913 tgl                      4831 ECB             :             /* No command-specific prep needed */
 1180 tgl                      4832 CBC         266 :             pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
 6913 tgl                      4833 GIC         266 :             break;
  961                          4834              28 :         case AT_CookedColumnDefault:    /* add a pre-cooked default */
                               4835                 :             /* This is currently used only in CREATE TABLE */
                               4836                 :             /* (so the permission check really isn't necessary) */
  640 peter                    4837 CBC          28 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4838                 :             /* This command never recurses */
  961 tgl                      4839 GIC          28 :             pass = AT_PASS_ADD_OTHERCONSTR;
                               4840              28 :             break;
 2194 peter_e                  4841              51 :         case AT_AddIdentity:
  640 peter                    4842              51 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
                               4843                 :             /* This command never recurses */
 1180 tgl                      4844              51 :             pass = AT_PASS_ADD_OTHERCONSTR;
 2194 peter_e                  4845 CBC          51 :             break;
                               4846              19 :         case AT_SetIdentity:
  640 peter                    4847 GIC          19 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
                               4848                 :             /* This command never recurses */
                               4849                 :             /* This should run after AddIdentity, so do it in MISC pass */
 1180 tgl                      4850              19 :             pass = AT_PASS_MISC;
 2194 peter_e                  4851              19 :             break;
 1356 alvherre                 4852 CBC          19 :         case AT_DropIdentity:
  640 peter                    4853 GIC          19 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
                               4854                 :             /* This command never recurses */
 1356 alvherre                 4855              19 :             pass = AT_PASS_DROP;
                               4856              19 :             break;
 6913 tgl                      4857             110 :         case AT_DropNotNull:    /* ALTER COLUMN DROP NOT NULL */
  640 peter                    4858             110 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4859                 :             /* Set up recursion for phase 2; no other prep needed */
    2 alvherre                 4860 GNC         107 :             if (recurse)
                               4861             101 :                 cmd->recurse = true;
 6913 tgl                      4862 GIC         107 :             pass = AT_PASS_DROP;
                               4863             107 :             break;
                               4864             162 :         case AT_SetNotNull:     /* ALTER COLUMN SET NOT NULL */
  640 peter                    4865             162 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4866                 :             /* Need command-specific recursion decision */
    2 alvherre                 4867 GNC         159 :             if (recurse)
                               4868             150 :                 cmd->recurse = true;
                               4869             159 :             pass = AT_PASS_COL_ATTRS;
                               4870             159 :             break;
                               4871            3155 :         case AT_SetAttNotNull:  /* set pg_attribute.attnotnull without adding
                               4872                 :                                  * a constraint */
                               4873            3155 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4874                 :             /* Need command-specific recursion decision */
                               4875            3155 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
 1447 tgl                      4876 GIC        3155 :             pass = AT_PASS_COL_ATTRS;
 1447 tgl                      4877 CBC        3155 :             break;
 1447 tgl                      4878 LBC           0 :         case AT_CheckNotNull:   /* check column is already marked NOT NULL */
  640 peter                    4879 UIC           0 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 1180 tgl                      4880 LBC           0 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
                               4881                 :             /* No command-specific prep needed */
 1447 tgl                      4882 UIC           0 :             pass = AT_PASS_COL_ATTRS;
 6913 tgl                      4883 LBC           0 :             break;
 1180 tgl                      4884 GIC          22 :         case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
  640 peter                    4885 CBC          22 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 1180 tgl                      4886 GIC          22 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
  887 peter                    4887 CBC          22 :             ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
 1181 peter                    4888 GIC          16 :             pass = AT_PASS_DROP;
 1181 peter                    4889 CBC          16 :             break;
 4998 tgl                      4890 GIC          82 :         case AT_SetStatistics:  /* ALTER COLUMN SET STATISTICS */
  640 peter                    4891              82 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE);
 1180 tgl                      4892              82 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
                               4893                 :             /* No command-specific prep needed */
 4637 simon                    4894              82 :             pass = AT_PASS_MISC;
 6913 tgl                      4895              82 :             break;
 4825 rhaas                    4896              22 :         case AT_SetOptions:     /* ALTER COLUMN SET ( options ) */
                               4897                 :         case AT_ResetOptions:   /* ALTER COLUMN RESET ( options ) */
  537 michael                  4898              22 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
                               4899                 :             /* This command never recurses */
 4637 simon                    4900              16 :             pass = AT_PASS_MISC;
 4998 tgl                      4901 CBC          16 :             break;
                               4902             115 :         case AT_SetStorage:     /* ALTER COLUMN SET STORAGE */
  640 peter                    4903             115 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
 1180 tgl                      4904 GIC         115 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
                               4905                 :             /* No command-specific prep needed */
 4637 simon                    4906             115 :             pass = AT_PASS_MISC;
 6913 tgl                      4907             115 :             break;
  697                          4908              33 :         case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
  640 peter                    4909              33 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
  751 rhaas                    4910 ECB             :             /* This command never recurses */
                               4911                 :             /* No command-specific prep needed */
  751 rhaas                    4912 GIC          33 :             pass = AT_PASS_MISC;
  751 rhaas                    4913 CBC          33 :             break;
 6913 tgl                      4914             781 :         case AT_DropColumn:     /* DROP COLUMN */
  640 peter                    4915 GIC         781 :             ATSimplePermissions(cmd->subtype, rel,
                               4916                 :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
 1180 tgl                      4917 CBC         778 :             ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
                               4918                 :                              lockmode, context);
                               4919                 :             /* Recursion occurs during execution phase */
 6913 tgl                      4920 GIC         772 :             pass = AT_PASS_DROP;
                               4921             772 :             break;
 6913 tgl                      4922 UIC           0 :         case AT_AddIndex:       /* ADD INDEX */
  640 peter                    4923               0 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               4924                 :             /* This command never recurses */
                               4925                 :             /* No command-specific prep needed */
 6913 tgl                      4926               0 :             pass = AT_PASS_ADD_INDEX;
 6913 tgl                      4927 LBC           0 :             break;
 6913 tgl                      4928 GIC       35224 :         case AT_AddConstraint:  /* ADD CONSTRAINT */
  640 peter                    4929 CBC       35224 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 5448 tgl                      4930 ECB             :             /* Recursion occurs during execution phase */
                               4931                 :             /* No command-specific prep needed except saving recurse flag */
 5448 tgl                      4932 GIC       35224 :             if (recurse)
  118 alvherre                 4933 GNC       35072 :                 cmd->recurse = true;
 6913 tgl                      4934 GIC       35224 :             pass = AT_PASS_ADD_CONSTR;
                               4935           35224 :             break;
 2118 tgl                      4936 UIC           0 :         case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
  640 peter                    4937               0 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
 4457 tgl                      4938 ECB             :             /* This command never recurses */
                               4939                 :             /* No command-specific prep needed */
 1180 tgl                      4940 LBC           0 :             pass = AT_PASS_ADD_INDEXCONSTR;
 4457                          4941               0 :             break;
 2118 tgl                      4942 GIC         264 :         case AT_DropConstraint: /* DROP CONSTRAINT */
  640 peter                    4943             264 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 1356 alvherre                 4944             264 :             ATCheckPartitionsNotInUse(rel, lockmode);
                               4945                 :             /* Other recursion occurs during execution phase */
                               4946                 :             /* No command-specific prep needed except saving recurse flag */
 5448 tgl                      4947 CBC         261 :             if (recurse)
  118 alvherre                 4948 GNC         249 :                 cmd->recurse = true;
 6913 tgl                      4949 CBC         261 :             pass = AT_PASS_DROP;
 6913 tgl                      4950 GIC         261 :             break;
 2118                          4951             553 :         case AT_AlterColumnType:    /* ALTER COLUMN TYPE */
  640 peter                    4952             553 :             ATSimplePermissions(cmd->subtype, rel,
                               4953                 :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
                               4954                 :             /* See comments for ATPrepAlterColumnType */
 1180 tgl                      4955             553 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
                               4956                 :                                       AT_PASS_UNSET, context);
                               4957             550 :             Assert(cmd != NULL);
                               4958                 :             /* Performs own recursion */
                               4959             550 :             ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
                               4960                 :                                   lockmode, context);
 6913 tgl                      4961 CBC         478 :             pass = AT_PASS_ALTER_TYPE;
 6913 tgl                      4962 GIC         478 :             break;
 4265 rhaas                    4963              82 :         case AT_AlterColumnGenericOptions:
  640 peter                    4964              82 :             ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
                               4965                 :             /* This command never recurses */
 4265 rhaas                    4966 ECB             :             /* No command-specific prep needed */
 4265 rhaas                    4967 CBC          82 :             pass = AT_PASS_MISC;
 4265 rhaas                    4968 GIC          82 :             break;
 6913 tgl                      4969 CBC         849 :         case AT_ChangeOwner:    /* ALTER OWNER */
                               4970                 :             /* This command never recurses */
 6913 tgl                      4971 ECB             :             /* No command-specific prep needed */
 6913 tgl                      4972 CBC         849 :             pass = AT_PASS_MISC;
 6913 tgl                      4973 GIC         849 :             break;
 6797 bruce                    4974 CBC          32 :         case AT_ClusterOn:      /* CLUSTER ON */
 6885 bruce                    4975 ECB             :         case AT_DropCluster:    /* SET WITHOUT CLUSTER */
  640 peter                    4976 CBC          32 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
                               4977                 :             /* These commands never recurse */
                               4978                 :             /* No command-specific prep needed */
 6913 tgl                      4979 GIC          32 :             pass = AT_PASS_MISC;
                               4980              32 :             break;
 3152 alvherre                 4981              16 :         case AT_SetLogged:      /* SET LOGGED */
  367 peter                    4982              16 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE);
 1180 tgl                      4983              16 :             if (tab->chgPersistence)
 1180 tgl                      4984 LBC           0 :                 ereport(ERROR,
                               4985                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               4986                 :                          errmsg("cannot change persistence setting twice")));
 3149 alvherre                 4987 GIC          16 :             tab->chgPersistence = ATPrepChangePersistence(rel, true);
 3149 alvherre                 4988 ECB             :             /* force rewrite if necessary; see comment in ATRewriteTables */
 3149 alvherre                 4989 CBC          13 :             if (tab->chgPersistence)
                               4990                 :             {
 3044 simon                    4991              10 :                 tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
 3149 alvherre                 4992              10 :                 tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
 3149 alvherre                 4993 ECB             :             }
 3152 alvherre                 4994 GIC          13 :             pass = AT_PASS_MISC;
 3152 alvherre                 4995 CBC          13 :             break;
                               4996              19 :         case AT_SetUnLogged:    /* SET UNLOGGED */
  367 peter                    4997              19 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE);
 1180 tgl                      4998 GIC          19 :             if (tab->chgPersistence)
 1180 tgl                      4999 LBC           0 :                 ereport(ERROR,
 1180 tgl                      5000 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               5001                 :                          errmsg("cannot change persistence setting twice")));
 3149 alvherre                 5002 CBC          19 :             tab->chgPersistence = ATPrepChangePersistence(rel, false);
 3149 alvherre                 5003 ECB             :             /* force rewrite if necessary; see comment in ATRewriteTables */
 3149 alvherre                 5004 CBC          16 :             if (tab->chgPersistence)
                               5005                 :             {
 3044 simon                    5006 GBC          13 :                 tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
 3149 alvherre                 5007 GIC          13 :                 tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
                               5008                 :             }
 3152                          5009              16 :             pass = AT_PASS_MISC;
                               5010              16 :             break;
 6797 bruce                    5011               3 :         case AT_DropOids:       /* SET WITHOUT OIDS */
  640 peter                    5012 GBC           3 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 6913 tgl                      5013               3 :             pass = AT_PASS_DROP;
 6913 tgl                      5014 GIC           3 :             break;
  620 michael                  5015 GBC          24 :         case AT_SetAccessMethod:    /* SET ACCESS METHOD */
                               5016              24 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
                               5017                 : 
                               5018                 :             /* partitioned tables don't have an access method */
  620 michael                  5019 GIC          24 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               5020               3 :                 ereport(ERROR,
                               5021                 :                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               5022                 :                          errmsg("cannot change access method of a partitioned table")));
                               5023                 : 
  620 michael                  5024 ECB             :             /* check if another access method change was already requested */
  620 michael                  5025 CBC          21 :             if (OidIsValid(tab->newAccessMethod))
  620 michael                  5026 GIC           6 :                 ereport(ERROR,
                               5027                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  620 michael                  5028 ECB             :                          errmsg("cannot have multiple SET ACCESS METHOD subcommands")));
                               5029                 : 
  620 michael                  5030 GIC          15 :             ATPrepSetAccessMethod(tab, rel, cmd->name);
                               5031              15 :             pass = AT_PASS_MISC;    /* does not matter; no work in Phase 2 */
                               5032              15 :             break;
 6846 tgl                      5033              79 :         case AT_SetTableSpace:  /* SET TABLESPACE */
  640 peter                    5034              79 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
                               5035                 :                                 ATT_PARTITIONED_INDEX);
                               5036                 :             /* This command never recurses */
 4638 simon                    5037              79 :             ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
 6797 bruce                    5038 CBC          79 :             pass = AT_PASS_MISC;    /* doesn't actually matter */
 6846 tgl                      5039 GIC          79 :             break;
 6031 bruce                    5040             464 :         case AT_SetRelOptions:  /* SET (...) */
                               5041                 :         case AT_ResetRelOptions:    /* RESET (...) */
 2118 tgl                      5042 ECB             :         case AT_ReplaceRelOptions:  /* reset them all, then set just these */
  640 peter                    5043 GIC         464 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
                               5044                 :             /* This command never recurses */
                               5045                 :             /* No command-specific prep needed */
 6125 bruce                    5046 CBC         464 :             pass = AT_PASS_MISC;
 6125 bruce                    5047 GIC         464 :             break;
 4643 peter_e                  5048 CBC         143 :         case AT_AddInherit:     /* INHERIT */
  640 peter                    5049 GIC         143 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 4643 peter_e                  5050 ECB             :             /* This command never recurses */
 4643 peter_e                  5051 GIC         143 :             ATPrepAddInherit(rel);
                               5052             134 :             pass = AT_PASS_MISC;
                               5053             134 :             break;
 2940 tgl                      5054 CBC          22 :         case AT_DropInherit:    /* NO INHERIT */
  640 peter                    5055 GIC          22 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               5056                 :             /* This command never recurses */
 2940 tgl                      5057 ECB             :             /* No command-specific prep needed */
 2940 tgl                      5058 GIC          22 :             pass = AT_PASS_MISC;
                               5059              22 :             break;
 2118 tgl                      5060 CBC          36 :         case AT_AlterConstraint:    /* ALTER CONSTRAINT */
  640 peter                    5061              36 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5062                 :             /* Recursion occurs during execution phase */
 3571 simon                    5063 GIC          33 :             pass = AT_PASS_MISC;
                               5064              33 :             break;
 2118 tgl                      5065             194 :         case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
  640 peter                    5066             194 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               5067                 :             /* Recursion occurs during execution phase */
                               5068                 :             /* No command-specific prep needed except saving recurse flag */
 4330 alvherre                 5069             194 :             if (recurse)
  118 alvherre                 5070 GNC         194 :                 cmd->recurse = true;
 4330 alvherre                 5071 GIC         194 :             pass = AT_PASS_MISC;
                               5072             194 :             break;
 2118 tgl                      5073 CBC         198 :         case AT_ReplicaIdentity:    /* REPLICA IDENTITY ... */
  640 peter                    5074 GIC         198 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
 3439 rhaas                    5075             198 :             pass = AT_PASS_MISC;
                               5076                 :             /* This command never recurses */
                               5077                 :             /* No command-specific prep needed */
 3439 rhaas                    5078 CBC         198 :             break;
 6438 tgl                      5079 GIC         168 :         case AT_EnableTrig:     /* ENABLE TRIGGER variants */
                               5080                 :         case AT_EnableAlwaysTrig:
 5865 JanWieck                 5081 ECB             :         case AT_EnableReplicaTrig:
                               5082                 :         case AT_EnableTrigAll:
                               5083                 :         case AT_EnableTrigUser:
                               5084                 :         case AT_DisableTrig:    /* DISABLE TRIGGER variants */
                               5085                 :         case AT_DisableTrigAll:
                               5086                 :         case AT_DisableTrigUser:
  640 peter                    5087 CBC         168 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
  248 alvherre                 5088 ECB             :             /* Set up recursion for phase 2; no other prep needed */
  248 alvherre                 5089 CBC         168 :             if (recurse)
                               5090             154 :                 cmd->recurse = true;
 3304 noah                     5091 GIC         168 :             pass = AT_PASS_MISC;
                               5092             168 :             break;
 5865 JanWieck                 5093             239 :         case AT_EnableRule:     /* ENABLE/DISABLE RULE variants */
                               5094                 :         case AT_EnableAlwaysRule:
                               5095                 :         case AT_EnableReplicaRule:
                               5096                 :         case AT_DisableRule:
                               5097                 :         case AT_AddOf:          /* OF */
                               5098                 :         case AT_DropOf:         /* NOT OF */
                               5099                 :         case AT_EnableRowSecurity:
                               5100                 :         case AT_DisableRowSecurity:
                               5101                 :         case AT_ForceRowSecurity:
 2744 sfrost                   5102 ECB             :         case AT_NoForceRowSecurity:
  640 peter                    5103 GIC         239 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5104                 :             /* These commands never recurse */
                               5105                 :             /* No command-specific prep needed */
 4481 rhaas                    5106             239 :             pass = AT_PASS_MISC;
                               5107             239 :             break;
                               5108              23 :         case AT_GenericOptions:
  640 peter                    5109              23 :             ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
                               5110                 :             /* No command-specific prep needed */
 4481 rhaas                    5111 CBC          23 :             pass = AT_PASS_MISC;
 4481 rhaas                    5112 GIC          23 :             break;
 2314 rhaas                    5113 CBC        1235 :         case AT_AttachPartition:
  640 peter                    5114            1235 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
                               5115                 :             /* No command-specific prep needed */
 1906 alvherre                 5116            1235 :             pass = AT_PASS_MISC;
 1906 alvherre                 5117 GIC        1235 :             break;
 2314 rhaas                    5118             258 :         case AT_DetachPartition:
  640 peter                    5119 CBC         258 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
 2314 rhaas                    5120 ECB             :             /* No command-specific prep needed */
 2314 rhaas                    5121 CBC         255 :             pass = AT_PASS_MISC;
                               5122             255 :             break;
  745 alvherre                 5123               7 :         case AT_DetachPartitionFinalize:
  640 peter                    5124 GIC           7 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5125                 :             /* No command-specific prep needed */
  745 alvherre                 5126 CBC           7 :             pass = AT_PASS_MISC;
                               5127               7 :             break;
 6797 bruce                    5128 LBC           0 :         default:                /* oops */
 6913 tgl                      5129 UIC           0 :             elog(ERROR, "unrecognized alter table type: %d",
                               5130                 :                  (int) cmd->subtype);
                               5131                 :             pass = AT_PASS_UNSET;   /* keep compiler quiet */
                               5132                 :             break;
                               5133                 :     }
 3571 simon                    5134 GIC       45779 :     Assert(pass > AT_PASS_UNSET);
                               5135                 : 
 6913 tgl                      5136 ECB             :     /* Add the subcommand to the appropriate list for phase 2 */
 6913 tgl                      5137 CBC       45779 :     tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
 6913 tgl                      5138 GIC       45779 : }
 7653 tgl                      5139 ECB             : 
 6913                          5140                 : /*
                               5141                 :  * ATRewriteCatalogs
                               5142                 :  *
                               5143                 :  * Traffic cop for ALTER TABLE Phase 2 operations.  Subcommands are
                               5144                 :  * dispatched in a "safe" execution order (designed to avoid unnecessary
                               5145                 :  * conflicts).
                               5146                 :  */
                               5147                 : static void
 1180 tgl                      5148 CBC       44836 : ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
 1180 tgl                      5149 ECB             :                   AlterTableUtilityContext *context)
                               5150                 : {
 6913                          5151                 :     int         pass;
 6892 neilc                    5152                 :     ListCell   *ltab;
 6913 tgl                      5153                 : 
                               5154                 :     /*
                               5155                 :      * We process all the tables "in parallel", one pass at a time.  This is
                               5156                 :      * needed because we may have to propagate work from one table to another
 6385 bruce                    5157                 :      * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
                               5158                 :      * re-adding of the foreign key constraint to the other table).  Work can
                               5159                 :      * only be propagated into later passes, however.
 6913 tgl                      5160                 :      */
 6913 tgl                      5161 GIC      533639 :     for (pass = 0; pass < AT_NUM_PASSES; pass++)
 6913 tgl                      5162 ECB             :     {
                               5163                 :         /* Go through each table that needs to be processed */
 6913 tgl                      5164 CBC      983980 :         foreach(ltab, *wqueue)
 7653 tgl                      5165 ECB             :         {
 6913 tgl                      5166 GIC      495177 :             AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
 6913 tgl                      5167 CBC      495177 :             List       *subcmds = tab->subcmds[pass];
 6892 neilc                    5168 ECB             :             ListCell   *lcmd;
 7653 tgl                      5169                 : 
 6913 tgl                      5170 CBC      495177 :             if (subcmds == NIL)
 7653                          5171          395396 :                 continue;
 7653 tgl                      5172 ECB             : 
                               5173                 :             /*
  745 alvherre                 5174                 :              * Open the relation and store it in tab.  This allows subroutines
                               5175                 :              * close and reopen, if necessary.  Appropriate lock was obtained
                               5176                 :              * by phase 1, needn't get it again.
 6797 bruce                    5177                 :              */
  745 alvherre                 5178 CBC       99781 :             tab->rel = relation_open(tab->relid, NoLock);
                               5179                 : 
 6913 tgl                      5180          205421 :             foreach(lcmd, subcmds)
  745 alvherre                 5181 GIC      106676 :                 ATExecCmd(wqueue, tab,
  629 peter                    5182 CBC      106676 :                           lfirst_node(AlterTableCmd, lcmd),
 1180 tgl                      5183 ECB             :                           lockmode, pass, context);
 7463                          5184                 : 
 7463 tgl                      5185 EUB             :             /*
 6385 bruce                    5186                 :              * After the ALTER TYPE pass, do cleanup work (this is not done in
                               5187                 :              * ATExecAlterColumnType since it should be done only once if
                               5188                 :              * multiple columns of a table are altered).
 7463 tgl                      5189                 :              */
 6913 tgl                      5190 GBC       98745 :             if (pass == AT_PASS_ALTER_TYPE)
 4638 simon                    5191 CBC         430 :                 ATPostAlterTypeCleanup(wqueue, tab, lockmode);
 7475 bruce                    5192 ECB             : 
  745 alvherre                 5193 CBC       98745 :             if (tab->rel)
  745 alvherre                 5194 ECB             :             {
  745 alvherre                 5195 CBC       98745 :                 relation_close(tab->rel, NoLock);
                               5196           98745 :                 tab->rel = NULL;
  745 alvherre                 5197 ECB             :             }
 6913 tgl                      5198                 :         }
                               5199                 :     }
                               5200                 : 
 4379 rhaas                    5201                 :     /* Check to see if a toast table must be added. */
 6913 tgl                      5202 CBC       89325 :     foreach(ltab, *wqueue)
 6913 tgl                      5203 ECB             :     {
 6913 tgl                      5204 GIC       45525 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
 7463 tgl                      5205 ECB             : 
                               5206                 :         /*
 2314 rhaas                    5207                 :          * If the table is source table of ATTACH PARTITION command, we did
                               5208                 :          * not modify anything about it that will change its toasting
                               5209                 :          * requirement, so no need to check.
                               5210                 :          */
 2314 rhaas                    5211 CBC       45525 :         if (((tab->relkind == RELKIND_RELATION ||
 2314 rhaas                    5212 GIC        2926 :               tab->relkind == RELKIND_PARTITIONED_TABLE) &&
 2205 tgl                      5213 CBC       44623 :              tab->partition_constraint == NULL) ||
 3689 kgrittn                  5214            1811 :             tab->relkind == RELKIND_MATVIEW)
 3290 simon                    5215           43739 :             AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
 7653 tgl                      5216 ECB             :     }
 6913 tgl                      5217 GIC       43800 : }
                               5218                 : 
 6913 tgl                      5219 ECB             : /*
                               5220                 :  * ATExecCmd: dispatch a subcommand to appropriate execution routine
                               5221                 :  */
                               5222                 : static void
  745 alvherre                 5223 GIC      106676 : ATExecCmd(List **wqueue, AlteredTableInfo *tab,
 1180 tgl                      5224 ECB             :           AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass,
                               5225                 :           AlterTableUtilityContext *context)
                               5226                 : {
 2937 alvherre                 5227 CBC      106676 :     ObjectAddress address = InvalidObjectAddress;
  745                          5228          106676 :     Relation    rel = tab->rel;
 2937 alvherre                 5229 EUB             : 
 6913 tgl                      5230 GBC      106676 :     switch (cmd->subtype)
                               5231                 :     {
 6913 tgl                      5232 GIC         914 :         case AT_AddColumn:      /* ADD COLUMN */
 2118 tgl                      5233 EUB             :         case AT_AddColumnToView:    /* add column via CREATE OR REPLACE VIEW */
 1180 tgl                      5234 GBC         914 :             address = ATExecAddColumn(wqueue, tab, rel, &cmd,
  118 alvherre                 5235 GNC         914 :                                       cmd->recurse, false,
 1180 tgl                      5236 ECB             :                                       lockmode, cur_pass, context);
 6913 tgl                      5237 CBC         857 :             break;
 6913 tgl                      5238 GBC         266 :         case AT_ColumnDefault:  /* ALTER COLUMN DEFAULT */
 2937 alvherre                 5239             266 :             address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
 6913 tgl                      5240 GIC         242 :             break;
  961                          5241              28 :         case AT_CookedColumnDefault:    /* add a pre-cooked default */
  961 tgl                      5242 GBC          28 :             address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
                               5243              28 :             break;
 2194 peter_e                  5244 CBC          51 :         case AT_AddIdentity:
 1180 tgl                      5245              51 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
 1180 tgl                      5246 ECB             :                                       cur_pass, context);
 1180 tgl                      5247 GIC          48 :             Assert(cmd != NULL);
 2194 peter_e                  5248              48 :             address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode);
 2194 peter_e                  5249 CBC          36 :             break;
                               5250              19 :         case AT_SetIdentity:
 1180 tgl                      5251              19 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
 1180 tgl                      5252 ECB             :                                       cur_pass, context);
 1180 tgl                      5253 CBC          19 :             Assert(cmd != NULL);
 2194 peter_e                  5254              19 :             address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode);
 2194 peter_e                  5255 GIC          16 :             break;
                               5256              19 :         case AT_DropIdentity:
 2194 peter_e                  5257 CBC          19 :             address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode);
 2194 peter_e                  5258 GIC          16 :             break;
 6913 tgl                      5259 CBC         107 :         case AT_DropNotNull:    /* ALTER COLUMN DROP NOT NULL */
    2 alvherre                 5260 GNC         107 :             address = ATExecDropNotNull(rel, cmd->name, cmd->recurse, lockmode);
 6913 tgl                      5261 CBC          65 :             break;
 6913 tgl                      5262 GIC         159 :         case AT_SetNotNull:     /* ALTER COLUMN SET NOT NULL */
    2 alvherre                 5263 GNC         159 :             address = ATExecSetNotNull(wqueue, rel, NULL, cmd->name,
                               5264             159 :                                        cmd->recurse, false, NULL, lockmode);
                               5265             144 :             break;
                               5266           28396 :         case AT_SetAttNotNull:  /* set pg_attribute.attnotnull */
                               5267           28396 :             ATExecSetAttNotNull(wqueue, rel, cmd->name, lockmode);
 6913 tgl                      5268 CBC       28387 :             break;
 1447 tgl                      5269 LBC           0 :         case AT_CheckNotNull:   /* check column is already marked NOT NULL */
                               5270               0 :             ATExecCheckNotNull(tab, rel, cmd->name, lockmode);
 1447 tgl                      5271 UIC           0 :             break;
 1181 peter                    5272 GIC          16 :         case AT_DropExpression:
 1181 peter                    5273 CBC          16 :             address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
                               5274              13 :             break;
 4998 tgl                      5275              82 :         case AT_SetStatistics:  /* ALTER COLUMN SET STATISTICS */
 2041 simon                    5276 GIC          82 :             address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
 6913 tgl                      5277              58 :             break;
 4825 rhaas                    5278 CBC          13 :         case AT_SetOptions:     /* ALTER COLUMN SET ( options ) */
 2937 alvherre                 5279              13 :             address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
 4825 rhaas                    5280              13 :             break;
 4825 rhaas                    5281 GIC           3 :         case AT_ResetOptions:   /* ALTER COLUMN RESET ( options ) */
 2937 alvherre                 5282 CBC           3 :             address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
 4998 tgl                      5283 GIC           3 :             break;
                               5284             115 :         case AT_SetStorage:     /* ALTER COLUMN SET STORAGE */
 2937 alvherre                 5285 CBC         115 :             address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
 6913 tgl                      5286             109 :             break;
  270 peter                    5287 GNC          33 :         case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
                               5288              33 :             address = ATExecSetCompression(rel, cmd->name, cmd->def,
  751 rhaas                    5289 ECB             :                                            lockmode);
  751 rhaas                    5290 GBC          30 :             break;
 6913 tgl                      5291 GIC         772 :         case AT_DropColumn:     /* DROP COLUMN */
 2937 alvherre                 5292             772 :             address = ATExecDropColumn(wqueue, rel, cmd->name,
  118 alvherre                 5293 GNC         772 :                                        cmd->behavior, cmd->recurse, false,
 1274 michael                  5294 CBC         772 :                                        cmd->missing_ok, lockmode,
 1274 michael                  5295 ECB             :                                        NULL);
 6913 tgl                      5296 CBC         688 :             break;
                               5297             435 :         case AT_AddIndex:       /* ADD INDEX */
 2937 alvherre                 5298             435 :             address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
 2937 alvherre                 5299 EUB             :                                      lockmode);
 6913 tgl                      5300 GIC         383 :             break;
                               5301             199 :         case AT_ReAddIndex:     /* ADD INDEX */
 2937 alvherre                 5302 CBC         199 :             address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
                               5303                 :                                      lockmode);
 6913 tgl                      5304             199 :             break;
  744 tomas.vondra             5305 GIC           7 :         case AT_ReAddStatistics:    /* ADD STATISTICS */
  744 tomas.vondra             5306 CBC           7 :             address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
  744 tomas.vondra             5307 ECB             :                                           true, lockmode);
  744 tomas.vondra             5308 GIC           7 :             break;
 6913 tgl                      5309 CBC       36768 :         case AT_AddConstraint:  /* ADD CONSTRAINT */
  960 tgl                      5310 ECB             :             /* Transform the command only during initial examination */
  960 tgl                      5311 CBC       36768 :             if (cur_pass == AT_PASS_ADD_CONSTR)
                               5312           35209 :                 cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
  118 alvherre                 5313 GNC       35224 :                                           cmd->recurse, lockmode,
  960 tgl                      5314 ECB             :                                           cur_pass, context);
                               5315                 :             /* Depending on constraint type, might be no more work to do now */
 1180 tgl                      5316 CBC       36753 :             if (cmd != NULL)
                               5317                 :                 address =
 1180 tgl                      5318 GIC        1544 :                     ATExecAddConstraint(wqueue, tab, rel,
 1180 tgl                      5319 CBC        1544 :                                         (Constraint *) cmd->def,
  118 alvherre                 5320 GNC        1544 :                                         cmd->recurse, false, lockmode);
 3807 tgl                      5321 CBC       36566 :             break;
 2118 tgl                      5322 GIC          82 :         case AT_ReAddConstraint:    /* Re-add pre-existing check constraint */
                               5323                 :             address =
 2937 alvherre                 5324 CBC          82 :                 ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
 2697 tgl                      5325 ECB             :                                     true, true, lockmode);
 6913 tgl                      5326 CBC          76 :             break;
 1985                          5327               7 :         case AT_ReAddDomainConstraint:  /* Re-add pre-existing domain check
                               5328                 :                                          * constraint */
                               5329                 :             address =
                               5330               7 :                 AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
 1985 tgl                      5331 GIC           7 :                                          ((AlterDomainStmt *) cmd->def)->def,
                               5332                 :                                          NULL);
 1985 tgl                      5333 CBC           4 :             break;
 2826 heikki.linnakangas       5334              27 :         case AT_ReAddComment:   /* Re-add existing comment */
                               5335              27 :             address = CommentObject((CommentStmt *) cmd->def);
                               5336              27 :             break;
 2118 tgl                      5337 GIC       33361 :         case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
 2937 alvherre                 5338 CBC       33361 :             address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
 2937 alvherre                 5339 ECB             :                                                lockmode);
 4457 tgl                      5340 CBC       33355 :             break;
 2118                          5341              33 :         case AT_AlterConstraint:    /* ALTER CONSTRAINT */
 2937 alvherre                 5342              33 :             address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
 3571 simon                    5343 GIC          27 :             break;
 2118 tgl                      5344             194 :         case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
  118 alvherre                 5345 GNC         194 :             address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
  999 drowley                  5346 ECB             :                                                false, lockmode);
 4443 simon                    5347 CBC         194 :             break;
 2118 tgl                      5348             261 :         case AT_DropConstraint: /* DROP CONSTRAINT */
 5011 andrew                   5349 GIC         261 :             ATExecDropConstraint(rel, cmd->name, cmd->behavior,
  118 alvherre                 5350 GNC         261 :                                  cmd->recurse, false,
 4638 simon                    5351 CBC         261 :                                  cmd->missing_ok, lockmode);
 6913 tgl                      5352             174 :             break;
 2118 tgl                      5353 GIC         463 :         case AT_AlterColumnType:    /* ALTER COLUMN TYPE */
                               5354                 :             /* parse transformation was done earlier */
 2937 alvherre                 5355 CBC         463 :             address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
 6913 tgl                      5356             445 :             break;
 2118 tgl                      5357 GIC          82 :         case AT_AlterColumnGenericOptions:  /* ALTER COLUMN OPTIONS */
                               5358                 :             address =
 2937 alvherre                 5359              82 :                 ATExecAlterColumnGenericOptions(rel, cmd->name,
                               5360              82 :                                                 (List *) cmd->def, lockmode);
 4265 rhaas                    5361              79 :             break;
 6913 tgl                      5362             849 :         case AT_ChangeOwner:    /* ALTER OWNER */
 6494                          5363             846 :             ATExecChangeOwner(RelationGetRelid(rel),
 2953 alvherre                 5364 CBC         849 :                               get_rolespec_oid(cmd->newowner, false),
                               5365                 :                               false, lockmode);
 6913 tgl                      5366             840 :             break;
                               5367              32 :         case AT_ClusterOn:      /* CLUSTER ON */
 2937 alvherre                 5368              32 :             address = ATExecClusterOn(rel, cmd->name, lockmode);
 6913 tgl                      5369              29 :             break;
 6797 bruce                    5370               9 :         case AT_DropCluster:    /* SET WITHOUT CLUSTER */
 4638 simon                    5371 GIC           9 :             ATExecDropCluster(rel, lockmode);
 6885 bruce                    5372               6 :             break;
 3152 alvherre                 5373              29 :         case AT_SetLogged:      /* SET LOGGED */
                               5374                 :         case AT_SetUnLogged:    /* SET UNLOGGED */
                               5375              29 :             break;
 6913 tgl                      5376               3 :         case AT_DropOids:       /* SET WITHOUT OIDS */
                               5377                 :             /* nothing to do here, oid columns don't exist anymore */
                               5378               3 :             break;
  620 michael                  5379               9 :         case AT_SetAccessMethod:    /* SET ACCESS METHOD */
  620 michael                  5380 ECB             :             /* handled specially in Phase 3 */
  620 michael                  5381 GIC           9 :             break;
 6797 bruce                    5382              79 :         case AT_SetTableSpace:  /* SET TABLESPACE */
 1418 tgl                      5383 ECB             : 
 6846                          5384                 :             /*
 1574 alvherre                 5385                 :              * Only do this for partitioned tables and indexes, for which this
                               5386                 :              * is just a catalog change.  Other relation types which have
                               5387                 :              * storage are handled by Phase 3.
 6846 tgl                      5388                 :              */
 1574 alvherre                 5389 CBC          79 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
                               5390              73 :                 rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
                               5391              18 :                 ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
                               5392                 : 
 6846 tgl                      5393              76 :             break;
 6031 bruce                    5394             464 :         case AT_SetRelOptions:  /* SET (...) */
 2118 tgl                      5395 ECB             :         case AT_ResetRelOptions:    /* RESET (...) */
                               5396                 :         case AT_ReplaceRelOptions:  /* replace entire option list */
 4126 rhaas                    5397 GIC         464 :             ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
 6125 bruce                    5398 CBC         438 :             break;
 5624                          5399              60 :         case AT_EnableTrig:     /* ENABLE TRIGGER name */
                               5400              60 :             ATExecEnableDisableTrigger(rel, cmd->name,
  248 alvherre                 5401 ECB             :                                        TRIGGER_FIRES_ON_ORIGIN, false,
  248 alvherre                 5402 GIC          60 :                                        cmd->recurse,
  248 alvherre                 5403 ECB             :                                        lockmode);
 5865 JanWieck                 5404 CBC          60 :             break;
 2118 tgl                      5405 GBC          20 :         case AT_EnableAlwaysTrig:   /* ENABLE ALWAYS TRIGGER name */
 5624 bruce                    5406              20 :             ATExecEnableDisableTrigger(rel, cmd->name,
                               5407                 :                                        TRIGGER_FIRES_ALWAYS, false,
  248 alvherre                 5408 GIC          20 :                                        cmd->recurse,
                               5409                 :                                        lockmode);
 5865 JanWieck                 5410              20 :             break;
 2118 tgl                      5411 CBC           8 :         case AT_EnableReplicaTrig:  /* ENABLE REPLICA TRIGGER name */
 5624 bruce                    5412 GIC           8 :             ATExecEnableDisableTrigger(rel, cmd->name,
                               5413                 :                                        TRIGGER_FIRES_ON_REPLICA, false,
  248 alvherre                 5414 CBC           8 :                                        cmd->recurse,
  248 alvherre                 5415 ECB             :                                        lockmode);
 6438 tgl                      5416 GIC           8 :             break;
                               5417              68 :         case AT_DisableTrig:    /* DISABLE TRIGGER name */
 5624 bruce                    5418              68 :             ATExecEnableDisableTrigger(rel, cmd->name,
                               5419                 :                                        TRIGGER_DISABLED, false,
  248 alvherre                 5420              68 :                                        cmd->recurse,
                               5421                 :                                        lockmode);
 6438 tgl                      5422              68 :             break;
 6438 tgl                      5423 UIC           0 :         case AT_EnableTrigAll:  /* ENABLE TRIGGER ALL */
 5624 bruce                    5424               0 :             ATExecEnableDisableTrigger(rel, NULL,
  248 alvherre                 5425 ECB             :                                        TRIGGER_FIRES_ON_ORIGIN, false,
  248 alvherre                 5426 UIC           0 :                                        cmd->recurse,
                               5427                 :                                        lockmode);
 6438 tgl                      5428               0 :             break;
 2118 tgl                      5429 GIC           6 :         case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
 5624 bruce                    5430               6 :             ATExecEnableDisableTrigger(rel, NULL,
                               5431                 :                                        TRIGGER_DISABLED, false,
  248 alvherre                 5432               6 :                                        cmd->recurse,
                               5433                 :                                        lockmode);
 6438 tgl                      5434               6 :             break;
 2118 tgl                      5435 UIC           0 :         case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
 5624 bruce                    5436               0 :             ATExecEnableDisableTrigger(rel, NULL,
                               5437                 :                                        TRIGGER_FIRES_ON_ORIGIN, true,
  248 alvherre                 5438 LBC           0 :                                        cmd->recurse,
                               5439                 :                                        lockmode);
 6438 tgl                      5440 UIC           0 :             break;
 2118 tgl                      5441 CBC           6 :         case AT_DisableTrigUser:    /* DISABLE TRIGGER USER */
 5624 bruce                    5442 GIC           6 :             ATExecEnableDisableTrigger(rel, NULL,
  248 alvherre                 5443 ECB             :                                        TRIGGER_DISABLED, true,
  248 alvherre                 5444 CBC           6 :                                        cmd->recurse,
                               5445                 :                                        lockmode);
 5865 JanWieck                 5446 GIC           6 :             break;
 5865 JanWieck                 5447 ECB             : 
 5624 bruce                    5448 CBC           3 :         case AT_EnableRule:     /* ENABLE RULE name */
 5624 bruce                    5449 GIC           3 :             ATExecEnableDisableRule(rel, cmd->name,
                               5450                 :                                     RULE_FIRES_ON_ORIGIN, lockmode);
 5865 JanWieck                 5451               3 :             break;
 2118 tgl                      5452 UIC           0 :         case AT_EnableAlwaysRule:   /* ENABLE ALWAYS RULE name */
 5624 bruce                    5453               0 :             ATExecEnableDisableRule(rel, cmd->name,
                               5454                 :                                     RULE_FIRES_ALWAYS, lockmode);
 5865 JanWieck                 5455 LBC           0 :             break;
 2118 tgl                      5456 GIC           3 :         case AT_EnableReplicaRule:  /* ENABLE REPLICA RULE name */
 5624 bruce                    5457 CBC           3 :             ATExecEnableDisableRule(rel, cmd->name,
 4638 simon                    5458 ECB             :                                     RULE_FIRES_ON_REPLICA, lockmode);
 5865 JanWieck                 5459 CBC           3 :             break;
 5865 JanWieck                 5460 GIC           3 :         case AT_DisableRule:    /* DISABLE RULE name */
 5624 bruce                    5461               3 :             ATExecEnableDisableRule(rel, cmd->name,
                               5462                 :                                     RULE_DISABLED, lockmode);
 6438 tgl                      5463               3 :             break;
                               5464                 : 
 6022                          5465             134 :         case AT_AddInherit:
 2937 alvherre                 5466             134 :             address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
 6125 bruce                    5467 CBC          95 :             break;
 6022 tgl                      5468              22 :         case AT_DropInherit:
 2937 alvherre                 5469 GIC          22 :             address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
 6125 bruce                    5470 CBC          19 :             break;
 4372 rhaas                    5471 GIC          33 :         case AT_AddOf:
 2937 alvherre                 5472 CBC          33 :             address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
 4372 rhaas                    5473              15 :             break;
 4372 rhaas                    5474 GIC           3 :         case AT_DropOf:
                               5475               3 :             ATExecDropOf(rel, lockmode);
                               5476               3 :             break;
 3439                          5477             207 :         case AT_ReplicaIdentity:
                               5478             207 :             ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
 3439 rhaas                    5479 CBC         186 :             break;
 3124 sfrost                   5480 GIC         135 :         case AT_EnableRowSecurity:
  768 michael                  5481 CBC         135 :             ATExecSetRowSecurity(rel, true);
 3124 sfrost                   5482 GIC         135 :             break;
                               5483               4 :         case AT_DisableRowSecurity:
  768 michael                  5484               4 :             ATExecSetRowSecurity(rel, false);
 3124 sfrost                   5485               4 :             break;
 2744                          5486              40 :         case AT_ForceRowSecurity:
                               5487              40 :             ATExecForceNoForceRowSecurity(rel, true);
 2744 sfrost                   5488 CBC          40 :             break;
                               5489              15 :         case AT_NoForceRowSecurity:
                               5490              15 :             ATExecForceNoForceRowSecurity(rel, false);
                               5491              15 :             break;
 4481 rhaas                    5492              23 :         case AT_GenericOptions:
 4481 rhaas                    5493 GIC          23 :             ATExecGenericOptions(rel, (List *) cmd->def);
 4481 rhaas                    5494 CBC          22 :             break;
 2314 rhaas                    5495 GIC        1235 :         case AT_AttachPartition:
 1180 tgl                      5496            1235 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
                               5497                 :                                       cur_pass, context);
                               5498            1220 :             Assert(cmd != NULL);
 1906 alvherre                 5499            1220 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
  252 michael                  5500 GNC        1034 :                 address = ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
                               5501                 :                                                 context);
                               5502                 :             else
                               5503             186 :                 address = ATExecAttachPartitionIdx(wqueue, rel,
                               5504             186 :                                                    ((PartitionCmd *) cmd->def)->name);
 2314 rhaas                    5505 CBC        1064 :             break;
 2314 rhaas                    5506 GIC         255 :         case AT_DetachPartition:
 1180 tgl                      5507 CBC         255 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
                               5508                 :                                       cur_pass, context);
                               5509             252 :             Assert(cmd != NULL);
                               5510                 :             /* ATPrepCmd ensures it must be a table */
 1906 alvherre                 5511             252 :             Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
  252 michael                  5512 GNC         252 :             address = ATExecDetachPartition(wqueue, tab, rel,
                               5513             252 :                                             ((PartitionCmd *) cmd->def)->name,
                               5514             252 :                                             ((PartitionCmd *) cmd->def)->concurrent);
  745 alvherre                 5515 CBC         187 :             break;
                               5516               7 :         case AT_DetachPartitionFinalize:
  252 michael                  5517 GNC           7 :             address = ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
 2314 rhaas                    5518 CBC           7 :             break;
 6797 bruce                    5519 LBC           0 :         default:                /* oops */
 6913 tgl                      5520               0 :             elog(ERROR, "unrecognized alter table type: %d",
 6913 tgl                      5521 ECB             :                  (int) cmd->subtype);
                               5522                 :             break;
                               5523                 :     }
 7653                          5524                 : 
 2890 alvherre                 5525                 :     /*
                               5526                 :      * Report the subcommand to interested event triggers.
                               5527                 :      */
 1180 tgl                      5528 CBC      105640 :     if (cmd)
 1180 tgl                      5529 GIC       70431 :         EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
 2937 alvherre                 5530 ECB             : 
 7653 tgl                      5531                 :     /*
 6385 bruce                    5532                 :      * Bump the command counter to ensure the next subcommand in the sequence
                               5533                 :      * can see the changes so far
 7653 tgl                      5534                 :      */
 6913 tgl                      5535 CBC      105640 :     CommandCounterIncrement();
                               5536          105640 : }
 7653 tgl                      5537 ECB             : 
 1180                          5538                 : /*
                               5539                 :  * ATParseTransformCmd: perform parse transformation for one subcommand
                               5540                 :  *
                               5541                 :  * Returns the transformed subcommand tree, if there is one, else NULL.
                               5542                 :  *
                               5543                 :  * The parser may hand back additional AlterTableCmd(s) and/or other
                               5544                 :  * utility statements, either before or after the original subcommand.
                               5545                 :  * Other AlterTableCmds are scheduled into the appropriate slot of the
 1180 tgl                      5546 EUB             :  * AlteredTableInfo (they had better be for later passes than the current one).
                               5547                 :  * Utility statements that are supposed to happen before the AlterTableCmd
                               5548                 :  * are executed immediately.  Those that are supposed to happen afterwards
 1180 tgl                      5549 ECB             :  * are added to the tab->afterStmts list to be done at the very end.
                               5550                 :  */
                               5551                 : static AlterTableCmd *
 1180 tgl                      5552 CBC       38191 : ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 1180 tgl                      5553 ECB             :                     AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
                               5554                 :                     int cur_pass, AlterTableUtilityContext *context)
                               5555                 : {
 1180 tgl                      5556 CBC       38191 :     AlterTableCmd *newcmd = NULL;
                               5557           38191 :     AlterTableStmt *atstmt = makeNode(AlterTableStmt);
 1180 tgl                      5558 ECB             :     List       *beforeStmts;
                               5559                 :     List       *afterStmts;
                               5560                 :     ListCell   *lc;
                               5561                 : 
                               5562                 :     /* Gin up an AlterTableStmt with just this subcommand and this table */
 1180 tgl                      5563 CBC       38191 :     atstmt->relation =
                               5564           38191 :         makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
                               5565           38191 :                      pstrdup(RelationGetRelationName(rel)),
                               5566                 :                      -1);
                               5567           38191 :     atstmt->relation->inh = recurse;
                               5568           38191 :     atstmt->cmds = list_make1(cmd);
 1002 michael                  5569           38191 :     atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
 1180 tgl                      5570           38191 :     atstmt->missing_ok = false;
 1180 tgl                      5571 ECB             : 
                               5572                 :     /* Transform the AlterTableStmt */
 1180 tgl                      5573 CBC       38191 :     atstmt = transformAlterTableStmt(RelationGetRelid(rel),
 1180 tgl                      5574 ECB             :                                      atstmt,
                               5575                 :                                      context->queryString,
                               5576                 :                                      &beforeStmts,
                               5577                 :                                      &afterStmts);
                               5578                 : 
                               5579                 :     /* Execute any statements that should happen before these subcommand(s) */
 1180 tgl                      5580 GIC       38313 :     foreach(lc, beforeStmts)
 1180 tgl                      5581 ECB             :     {
 1180 tgl                      5582 CBC         161 :         Node       *stmt = (Node *) lfirst(lc);
 1180 tgl                      5583 ECB             : 
 1180 tgl                      5584 GIC         161 :         ProcessUtilityForAlterTable(stmt, context);
 1180 tgl                      5585 CBC         155 :         CommandCounterIncrement();
 1180 tgl                      5586 ECB             :     }
                               5587                 : 
                               5588                 :     /* Examine the transformed subcommands and schedule them appropriately */
 1180 tgl                      5589 CBC      101688 :     foreach(lc, atstmt->cmds)
 1180 tgl                      5590 ECB             :     {
 1180 tgl                      5591 GIC       63536 :         AlterTableCmd *cmd2 = lfirst_node(AlterTableCmd, lc);
                               5592                 :         int         pass;
 1180 tgl                      5593 ECB             : 
                               5594                 :         /*
  960                          5595                 :          * This switch need only cover the subcommand types that can be added
                               5596                 :          * by parse_utilcmd.c; otherwise, we'll use the default strategy of
                               5597                 :          * executing the subcommand immediately, as a substitute for the
                               5598                 :          * original subcommand.  (Note, however, that this does cause
                               5599                 :          * AT_AddConstraint subcommands to be rescheduled into later passes,
                               5600                 :          * which is important for index and foreign key constraints.)
                               5601                 :          *
                               5602                 :          * We assume we needn't do any phase-1 checks for added subcommands.
                               5603                 :          */
  960 tgl                      5604 CBC       63536 :         switch (cmd2->subtype)
                               5605                 :         {
    2 alvherre                 5606 GNC       25241 :             case AT_SetAttNotNull:
                               5607           25241 :                 ATSimpleRecursion(wqueue, rel, cmd2, recurse, lockmode, context);
  960 tgl                      5608 CBC       25241 :                 pass = AT_PASS_COL_ATTRS;
                               5609           25241 :                 break;
                               5610             444 :             case AT_AddIndex:
  960 tgl                      5611 ECB             :                 /* This command never recurses */
                               5612                 :                 /* No command-specific prep needed */
  960 tgl                      5613 GIC         444 :                 pass = AT_PASS_ADD_INDEX;
  960 tgl                      5614 CBC         444 :                 break;
                               5615           33361 :             case AT_AddIndexConstraint:
  960 tgl                      5616 ECB             :                 /* This command never recurses */
                               5617                 :                 /* No command-specific prep needed */
  960 tgl                      5618 CBC       33361 :                 pass = AT_PASS_ADD_INDEXCONSTR;
                               5619           33361 :                 break;
  960 tgl                      5620 GIC        1547 :             case AT_AddConstraint:
  960 tgl                      5621 ECB             :                 /* Recursion occurs during execution phase */
  960 tgl                      5622 CBC        1547 :                 if (recurse)
  118 alvherre                 5623 GNC        1526 :                     cmd2->recurse = true;
  960 tgl                      5624 CBC        1547 :                 switch (castNode(Constraint, cmd2->def)->contype)
  960 tgl                      5625 ECB             :                 {
  960 tgl                      5626 LBC           0 :                     case CONSTR_PRIMARY:
  960 tgl                      5627 ECB             :                     case CONSTR_UNIQUE:
                               5628                 :                     case CONSTR_EXCLUSION:
  960 tgl                      5629 LBC           0 :                         pass = AT_PASS_ADD_INDEXCONSTR;
                               5630               0 :                         break;
  960 tgl                      5631 CBC        1547 :                     default:
  960 tgl                      5632 GIC        1547 :                         pass = AT_PASS_ADD_OTHERCONSTR;
  960 tgl                      5633 CBC        1547 :                         break;
  960 tgl                      5634 ECB             :                 }
  960 tgl                      5635 CBC        1547 :                 break;
  960 tgl                      5636 LBC           0 :             case AT_AlterColumnGenericOptions:
  960 tgl                      5637 ECB             :                 /* This command never recurses */
                               5638                 :                 /* No command-specific prep needed */
  960 tgl                      5639 UIC           0 :                 pass = AT_PASS_MISC;
  960 tgl                      5640 LBC           0 :                 break;
  960 tgl                      5641 CBC        2943 :             default:
                               5642            2943 :                 pass = cur_pass;
                               5643            2943 :                 break;
  960 tgl                      5644 ECB             :         }
                               5645                 : 
  960 tgl                      5646 CBC       63536 :         if (pass < cur_pass)
  960 tgl                      5647 ECB             :         {
                               5648                 :             /* Cannot schedule into a pass we already finished */
  960 tgl                      5649 LBC           0 :             elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
  960 tgl                      5650 ECB             :                  pass);
                               5651                 :         }
  960 tgl                      5652 CBC       63536 :         else if (pass > cur_pass)
  960 tgl                      5653 ECB             :         {
                               5654                 :             /* OK, queue it up for later */
  960 tgl                      5655 CBC       60593 :             tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
 1180 tgl                      5656 ECB             :         }
                               5657                 :         else
                               5658                 :         {
                               5659                 :             /*
                               5660                 :              * We should see at most one subcommand for the current pass,
                               5661                 :              * which is the transformed version of the original subcommand.
                               5662                 :              */
  960 tgl                      5663 CBC        2943 :             if (newcmd == NULL && cmd->subtype == cmd2->subtype)
 1180 tgl                      5664 ECB             :             {
  960                          5665                 :                 /* Found the transformed version of our subcommand */
  960 tgl                      5666 GIC        2943 :                 newcmd = cmd2;
 1180 tgl                      5667 ECB             :             }
  960                          5668                 :             else
  960 tgl                      5669 UIC           0 :                 elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
                               5670                 :                      pass);
 1180 tgl                      5671 ECB             :         }
                               5672                 :     }
                               5673                 : 
                               5674                 :     /* Queue up any after-statements to happen at the end */
 1180 tgl                      5675 GIC       38152 :     tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
 1180 tgl                      5676 ECB             : 
 1180 tgl                      5677 GIC       38152 :     return newcmd;
 1180 tgl                      5678 ECB             : }
                               5679                 : 
 6913                          5680                 : /*
                               5681                 :  * ATRewriteTables: ALTER TABLE phase 3
                               5682                 :  */
                               5683                 : static void
 1180 tgl                      5684 CBC       43800 : ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
 1180 tgl                      5685 ECB             :                 AlterTableUtilityContext *context)
 6913                          5686                 : {
                               5687                 :     ListCell   *ltab;
 7653                          5688                 : 
                               5689                 :     /* Go through each table that needs to be checked or rewritten */
 6913 tgl                      5690 CBC       89203 :     foreach(ltab, *wqueue)
 6913 tgl                      5691 ECB             :     {
 6913 tgl                      5692 CBC       45519 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
                               5693                 : 
 1464 tgl                      5694 ECB             :         /* Relations without storage may be ignored here */
 1464 tgl                      5695 GIC       45519 :         if (!RELKIND_HAS_STORAGE(tab->relkind))
 4481 rhaas                    5696 CBC        2788 :             continue;
 4481 rhaas                    5697 EUB             : 
 4439                          5698                 :         /*
                               5699                 :          * If we change column data types, the operation has to be propagated
 1028 michael                  5700                 :          * to tables that use this table's rowtype as a column type.
                               5701                 :          * tab->newvals will also be non-NULL in the case where we're adding a
                               5702                 :          * column with a default.  We choose to forbid that case as well,
 1028 michael                  5703 ECB             :          * since composite types might eventually support defaults.
 4439 rhaas                    5704                 :          *
                               5705                 :          * (Eventually we'll probably need to check for composite type
                               5706                 :          * dependencies even when we're just scanning the table without a
                               5707                 :          * rewrite, but at the moment a composite type does not enforce any
 4382 bruce                    5708                 :          * constraints, so it's not necessary/appropriate to enforce them just
 4382 bruce                    5709 EUB             :          * during ALTER.)
 4439 rhaas                    5710                 :          */
 3044 simon                    5711 GIC       42731 :         if (tab->newvals != NIL || tab->rewrite > 0)
 4439 rhaas                    5712 EUB             :         {
                               5713                 :             Relation    rel;
                               5714                 : 
 1539 andres                   5715 CBC         652 :             rel = table_open(tab->relid, NoLock);
 4439 rhaas                    5716             652 :             find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
 1539 andres                   5717 GIC         646 :             table_close(rel, NoLock);
 4439 rhaas                    5718 ECB             :         }
                               5719                 : 
 6913 tgl                      5720                 :         /*
                               5721                 :          * We only need to rewrite the table if at least one column needs to
  620 michael                  5722                 :          * be recomputed, or we are changing its persistence or access method.
 3149 alvherre                 5723                 :          *
                               5724                 :          * There are two reasons for requiring a rewrite when changing
                               5725                 :          * persistence: on one hand, we need to ensure that the buffers
 3149 alvherre                 5726 EUB             :          * belonging to each of the two relations are marked with or without
                               5727                 :          * BM_PERMANENT properly.  On the other hand, since rewriting creates
                               5728                 :          * and assigns a new relfilenumber, we automatically create or drop an
                               5729                 :          * init fork for the relation as appropriate.
 6913 tgl                      5730 ECB             :          */
  367 peter                    5731 CBC       42725 :         if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE)
 6913 tgl                      5732 GIC         356 :         {
 6913 tgl                      5733 ECB             :             /* Build a temporary relation and copy data */
 4812                          5734                 :             Relation    OldHeap;
 6913                          5735                 :             Oid         OIDNewHeap;
                               5736                 :             Oid         NewAccessMethod;
 6846                          5737                 :             Oid         NewTableSpace;
                               5738                 :             char        persistence;
 6913                          5739                 : 
 1539 andres                   5740 CBC         372 :             OldHeap = table_open(tab->relid, NoLock);
 6910 tgl                      5741 ECB             : 
                               5742                 :             /*
 4790 bruce                    5743                 :              * We don't support rewriting of system catalogs; there are too
                               5744                 :              * many corner cases and too little benefit.  In particular this
                               5745                 :              * is certainly not going to work for mapped catalogs.
 6910 tgl                      5746                 :              */
 4809 tgl                      5747 CBC         372 :             if (IsSystemRelation(OldHeap))
 6910 tgl                      5748 LBC           0 :                 ereport(ERROR,
 6910 tgl                      5749 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               5750                 :                          errmsg("cannot rewrite system relation \"%s\"",
                               5751                 :                                 RelationGetRelationName(OldHeap))));
                               5752                 : 
 3407 rhaas                    5753 CBC         372 :             if (RelationIsUsedAsCatalogTable(OldHeap))
                               5754               1 :                 ereport(ERROR,
 3407 rhaas                    5755 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 2118 tgl                      5756                 :                          errmsg("cannot rewrite table \"%s\" used as a catalog table",
                               5757                 :                                 RelationGetRelationName(OldHeap))));
 3407 rhaas                    5758                 : 
 6910 tgl                      5759                 :             /*
 6385 bruce                    5760                 :              * Don't allow rewrite on temp tables of other backends ... their
                               5761                 :              * local buffer manager is not going to cope.
 6910 tgl                      5762                 :              */
 5122 tgl                      5763 CBC         371 :             if (RELATION_IS_OTHER_TEMP(OldHeap))
 6910 tgl                      5764 LBC           0 :                 ereport(ERROR,
 6910 tgl                      5765 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 2118                          5766                 :                          errmsg("cannot rewrite temporary tables of other sessions")));
 6910                          5767                 : 
 6846                          5768                 :             /*
                               5769                 :              * Select destination tablespace (same as original unless user
                               5770                 :              * requested a change)
                               5771                 :              */
 6846 tgl                      5772 CBC         371 :             if (tab->newTableSpace)
 6846 tgl                      5773 LBC           0 :                 NewTableSpace = tab->newTableSpace;
 6846 tgl                      5774 ECB             :             else
 6846 tgl                      5775 GIC         371 :                 NewTableSpace = OldHeap->rd_rel->reltablespace;
                               5776                 : 
  620 michael                  5777 ECB             :             /*
                               5778                 :              * Select destination access method (same as original unless user
                               5779                 :              * requested a change)
                               5780                 :              */
  620 michael                  5781 CBC         371 :             if (OidIsValid(tab->newAccessMethod))
  620 michael                  5782 GIC           9 :                 NewAccessMethod = tab->newAccessMethod;
  620 michael                  5783 ECB             :             else
  620 michael                  5784 GIC         362 :                 NewAccessMethod = OldHeap->rd_rel->relam;
  620 michael                  5785 ECB             : 
 3152 alvherre                 5786                 :             /*
                               5787                 :              * Select persistence of transient table (same as original unless
                               5788                 :              * user requested a change)
                               5789                 :              */
 3149 alvherre                 5790 CBC         371 :             persistence = tab->chgPersistence ?
 3152                          5791             354 :                 tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
 3152 alvherre                 5792 ECB             : 
 1539 andres                   5793 GBC         371 :             table_close(OldHeap, NoLock);
 8179 tgl                      5794 EUB             : 
                               5795                 :             /*
                               5796                 :              * Fire off an Event Trigger now, before actually rewriting the
                               5797                 :              * table.
                               5798                 :              *
                               5799                 :              * We don't support Event Trigger for nested commands anywhere,
                               5800                 :              * here included, and parsetree is given NULL when coming from
                               5801                 :              * AlterTableInternal.
 3044 simon                    5802 ECB             :              *
                               5803                 :              * And fire it only once.
                               5804                 :              */
 3044 simon                    5805 GIC         371 :             if (parsetree)
 2878 bruce                    5806             371 :                 EventTriggerTableRewrite((Node *) parsetree,
                               5807                 :                                          tab->relid,
                               5808                 :                                          tab->rewrite);
 3044 simon                    5809 ECB             : 
 3152 alvherre                 5810                 :             /*
                               5811                 :              * Create transient table that will receive the modified data.
                               5812                 :              *
                               5813                 :              * Ensure it is marked correctly as logged or unlogged.  We have
                               5814                 :              * to do this here so that buffers for the new relfilenumber will
                               5815                 :              * have the right persistence set, and at the same time ensure
                               5816                 :              * that the original filenumbers's buffers will get read in with
                               5817                 :              * the correct setting (i.e. the original one).  Otherwise a
                               5818                 :              * rollback after the rewrite would possibly result with buffers
                               5819                 :              * for the original filenumbers having the wrong persistence
                               5820                 :              * setting.
                               5821                 :              *
                               5822                 :              * NB: This relies on swap_relation_files() also swapping the
                               5823                 :              * persistence. That wouldn't work for pg_class, but that can't be
                               5824                 :              * unlogged anyway.
                               5825                 :              */
  620 michael                  5826 GIC         368 :             OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod,
  620 michael                  5827 ECB             :                                        persistence, lockmode);
                               5828                 : 
                               5829                 :             /*
                               5830                 :              * Copy the heap data into the new table with the desired
 6913 tgl                      5831                 :              * modifications, and test the current data within the table
                               5832                 :              * against new constraints generated by ALTER TABLE commands.
                               5833                 :              */
 4638 simon                    5834 GIC         368 :             ATRewriteTable(tab, OIDNewHeap, lockmode);
                               5835                 : 
                               5836                 :             /*
                               5837                 :              * Swap the physical files of the old and new heaps, then rebuild
 4462 rhaas                    5838 ECB             :              * indexes and discard the old heap.  We can use RecentXmin for
 4809 tgl                      5839                 :              * the table's new relfrozenxid because we rewrote all the tuples
                               5840                 :              * in ATRewriteTable, so no older Xid remains in the table.  Also,
                               5841                 :              * we never try to swap toast tables by content, since we have no
                               5842                 :              * interest in letting this code work on system catalogs.
 6913                          5843                 :              */
 4462 rhaas                    5844 CBC         359 :             finish_heap_swap(tab->relid, OIDNewHeap,
 3675 rhaas                    5845 ECB             :                              false, false, true,
 3675 rhaas                    5846 GIC         359 :                              !OidIsValid(tab->newTableSpace),
                               5847                 :                              RecentXmin,
 3067 alvherre                 5848 ECB             :                              ReadNextMultiXactId(),
                               5849                 :                              persistence);
                               5850                 : 
  607 michael                  5851 GIC         356 :             InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0);
                               5852                 :         }
  367 peter                    5853           42353 :         else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE)
                               5854                 :         {
  367 peter                    5855 CBC           6 :             if (tab->chgPersistence)
  367 peter                    5856 GIC           6 :                 SequenceChangePersistence(tab->relid, tab->newrelpersistence);
  367 peter                    5857 ECB             :         }
                               5858                 :         else
 6913 tgl                      5859                 :         {
                               5860                 :             /*
                               5861                 :              * If required, test the current data within the table against new
                               5862                 :              * constraints generated by ALTER TABLE commands, but don't
                               5863                 :              * rebuild data.
                               5864                 :              */
 1488 rhaas                    5865 GIC       42347 :             if (tab->constraints != NIL || tab->verify_new_notnull ||
 2205 tgl                      5866 CBC       41184 :                 tab->partition_constraint != NULL)
 4638 simon                    5867 GIC        1998 :                 ATRewriteTable(tab, InvalidOid, lockmode);
                               5868                 : 
                               5869                 :             /*
                               5870                 :              * If we had SET TABLESPACE but no reason to reconstruct tuples,
                               5871                 :              * just do a block-by-block copy.
                               5872                 :              */
 6846 tgl                      5873           42253 :             if (tab->newTableSpace)
 4638 simon                    5874              61 :                 ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
                               5875                 :         }
                               5876                 : 
                               5877                 :         /*
                               5878                 :          * Also change persistence of owned sequences, so that it matches the
  367 peter                    5879 ECB             :          * table persistence.
                               5880                 :          */
  367 peter                    5881 CBC       42615 :         if (tab->chgPersistence)
  367 peter                    5882 ECB             :         {
  367 peter                    5883 CBC          23 :             List       *seqlist = getOwnedSequences(tab->relid);
  367 peter                    5884 ECB             :             ListCell   *lc;
                               5885                 : 
  367 peter                    5886 GIC          38 :             foreach(lc, seqlist)
                               5887                 :             {
  332 tgl                      5888 CBC          15 :                 Oid         seq_relid = lfirst_oid(lc);
  367 peter                    5889 ECB             : 
  367 peter                    5890 CBC          15 :                 SequenceChangePersistence(seq_relid, tab->newrelpersistence);
                               5891                 :             }
                               5892                 :         }
 6913 tgl                      5893 ECB             :     }
 8314                          5894                 : 
 7912                          5895                 :     /*
                               5896                 :      * Foreign key constraints are checked in a final pass, since (a) it's
 6385 bruce                    5897                 :      * generally best to examine each one separately, and (b) it's at least
                               5898                 :      * theoretically possible that we have changed both relations of the
                               5899                 :      * foreign key, and we'd better have finished both rewrites before we try
                               5900                 :      * to read the tables.
 7912 tgl                      5901 EUB             :      */
 6913 tgl                      5902 GIC       88994 :     foreach(ltab, *wqueue)
                               5903                 :     {
 6797 bruce                    5904 GBC       45341 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
                               5905           45341 :         Relation    rel = NULL;
 6797 bruce                    5906 ECB             :         ListCell   *lcon;
 8304 tgl                      5907                 : 
 1464                          5908                 :         /* Relations without storage may be ignored here too */
 1464 tgl                      5909 GIC       45341 :         if (!RELKIND_HAS_STORAGE(tab->relkind))
 1464 tgl                      5910 CBC        2751 :             continue;
 1464 tgl                      5911 EUB             : 
 6913 tgl                      5912 GIC       43348 :         foreach(lcon, tab->constraints)
                               5913                 :         {
 6913 tgl                      5914 GBC         789 :             NewConstraint *con = lfirst(lcon);
 7524 tgl                      5915 EUB             : 
 6913 tgl                      5916 CBC         789 :             if (con->contype == CONSTR_FOREIGN)
 6913 tgl                      5917 ECB             :             {
 5001 tgl                      5918 CBC         466 :                 Constraint *fkconstraint = (Constraint *) con->qual;
                               5919                 :                 Relation    refrel;
                               5920                 : 
 6913                          5921             466 :                 if (rel == NULL)
                               5922                 :                 {
                               5923                 :                     /* Long since locked, no need for another */
 1539 andres                   5924 GBC         460 :                     rel = table_open(tab->relid, NoLock);
                               5925                 :                 }
                               5926                 : 
 1539 andres                   5927 CBC         466 :                 refrel = table_open(con->refrelid, RowShareLock);
                               5928                 : 
 4443 simon                    5929 GIC         466 :                 validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
 5003 tgl                      5930 ECB             :                                              con->refindid,
                               5931                 :                                              con->conid);
                               5932                 : 
                               5933                 :                 /*
                               5934                 :                  * No need to mark the constraint row as validated, we did
                               5935                 :                  * that when we inserted the row earlier.
                               5936                 :                  */
                               5937                 : 
 1539 andres                   5938 CBC         435 :                 table_close(refrel, NoLock);
                               5939                 :             }
                               5940                 :         }
 8315 JanWieck                 5941 ECB             : 
 6913 tgl                      5942 GIC       42559 :         if (rel)
 1539 andres                   5943             429 :             table_close(rel, NoLock);
 6913 tgl                      5944 EUB             :     }
                               5945                 : 
                               5946                 :     /* Finally, run any afterStmts that were queued up */
 1180 tgl                      5947 GIC       88944 :     foreach(ltab, *wqueue)
                               5948                 :     {
                               5949           45291 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
 1180 tgl                      5950 ECB             :         ListCell   *lc;
                               5951                 : 
 1180 tgl                      5952 CBC       45325 :         foreach(lc, tab->afterStmts)
                               5953                 :         {
 1180 tgl                      5954 GIC          34 :             Node       *stmt = (Node *) lfirst(lc);
                               5955                 : 
                               5956              34 :             ProcessUtilityForAlterTable(stmt, context);
                               5957              34 :             CommandCounterIncrement();
                               5958                 :         }
 1180 tgl                      5959 ECB             :     }
 6913 tgl                      5960 GIC       43653 : }
                               5961                 : 
                               5962                 : /*
                               5963                 :  * ATRewriteTable: scan or rewrite one table
                               5964                 :  *
 6913 tgl                      5965 ECB             :  * OIDNewHeap is InvalidOid if we don't need to rewrite
                               5966                 :  */
                               5967                 : static void
 4638 simon                    5968 GIC        2366 : ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
                               5969                 : {
 6913 tgl                      5970 ECB             :     Relation    oldrel;
                               5971                 :     Relation    newrel;
                               5972                 :     TupleDesc   oldTupDesc;
                               5973                 :     TupleDesc   newTupDesc;
 6913 tgl                      5974 GIC        2366 :     bool        needscan = false;
                               5975                 :     List       *notnull_attrs;
                               5976                 :     int         i;
                               5977                 :     ListCell   *l;
                               5978                 :     EState     *estate;
                               5979                 :     CommandId   mycid;
                               5980                 :     BulkInsertState bistate;
                               5981                 :     int         ti_options;
 2217 andres                   5982            2366 :     ExprState  *partqualstate = NULL;
                               5983                 : 
                               5984                 :     /*
                               5985                 :      * Open the relation(s).  We have surely already locked the existing
 6913 tgl                      5986 ECB             :      * table.
                               5987                 :      */
 1539 andres                   5988 GIC        2366 :     oldrel = table_open(tab->relid, NoLock);
 6913 tgl                      5989            2366 :     oldTupDesc = tab->oldDesc;
 2118 tgl                      5990 CBC        2366 :     newTupDesc = RelationGetDescr(oldrel);  /* includes all mods */
 6913 tgl                      5991 ECB             : 
 6913 tgl                      5992 CBC        2366 :     if (OidIsValid(OIDNewHeap))
 1539 andres                   5993 GIC         368 :         newrel = table_open(OIDNewHeap, lockmode);
                               5994                 :     else
 6913 tgl                      5995            1998 :         newrel = NULL;
                               5996                 : 
                               5997                 :     /*
                               5998                 :      * Prepare a BulkInsertState and options for table_tuple_insert.  The FSM
                               5999                 :      * is empty, so don't bother using it.
                               6000                 :      */
 4904 heikki.linnakangas       6001            2366 :     if (newrel)
                               6002                 :     {
                               6003             368 :         mycid = GetCurrentCommandId(true);
                               6004             368 :         bistate = GetBulkInsertState();
 1469 andres                   6005             368 :         ti_options = TABLE_INSERT_SKIP_FSM;
 4904 heikki.linnakangas       6006 ECB             :     }
                               6007                 :     else
                               6008                 :     {
                               6009                 :         /* keep compiler quiet about using these uninitialized */
 4904 heikki.linnakangas       6010 GIC        1998 :         mycid = 0;
                               6011            1998 :         bistate = NULL;
 1469 andres                   6012            1998 :         ti_options = 0;
                               6013                 :     }
                               6014                 : 
 7653 tgl                      6015 ECB             :     /*
                               6016                 :      * Generate the constraint and default execution states
                               6017                 :      */
                               6018                 : 
 6913 tgl                      6019 GIC        2366 :     estate = CreateExecutorState();
                               6020                 : 
                               6021                 :     /* Build the needed expression execution states */
 6913 tgl                      6022 CBC        3200 :     foreach(l, tab->constraints)
 6913 tgl                      6023 EUB             :     {
 6913 tgl                      6024 GIC         834 :         NewConstraint *con = lfirst(l);
                               6025                 : 
                               6026             834 :         switch (con->contype)
                               6027                 :         {
 6913 tgl                      6028 CBC         365 :             case CONSTR_CHECK:
                               6029             365 :                 needscan = true;
 2217 andres                   6030 GIC         365 :                 con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
 6913 tgl                      6031             365 :                 break;
                               6032             469 :             case CONSTR_FOREIGN:
                               6033                 :                 /* Nothing to do here */
                               6034             469 :                 break;
 6913 tgl                      6035 UIC           0 :             default:
                               6036               0 :                 elog(ERROR, "unrecognized constraint type: %d",
                               6037                 :                      (int) con->contype);
 6913 tgl                      6038 ECB             :         }
 6913 tgl                      6039 EUB             :     }
                               6040                 : 
                               6041                 :     /* Build expression execution states for partition check quals */
 2314 rhaas                    6042 GIC        2366 :     if (tab->partition_constraint)
                               6043                 :     {
                               6044             906 :         needscan = true;
 2205 tgl                      6045             906 :         partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
                               6046                 :     }
 2314 rhaas                    6047 ECB             : 
 6913 tgl                      6048 GBC        2747 :     foreach(l, tab->newvals)
                               6049                 :     {
 6797 bruce                    6050 CBC         381 :         NewColumnValue *ex = lfirst(l);
                               6051                 : 
                               6052                 :         /* expr already planned */
 4310 rhaas                    6053 GIC         381 :         ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
                               6054                 :     }
                               6055                 : 
 6117 tgl                      6056 CBC        2366 :     notnull_attrs = NIL;
 1488 rhaas                    6057            2366 :     if (newrel || tab->verify_new_notnull)
                               6058                 :     {
 6117 tgl                      6059 ECB             :         /*
                               6060                 :          * If we are rebuilding the tuples OR if we added any new but not
                               6061                 :          * verified NOT NULL constraints, check all not-null constraints. This
                               6062                 :          * is a bit of overkill but it minimizes risk of bugs, and
                               6063                 :          * heap_attisnull is a pretty cheap test anyway.
                               6064                 :          */
 6117 tgl                      6065 CBC        2831 :         for (i = 0; i < newTupDesc->natts; i++)
 6117 tgl                      6066 ECB             :         {
 2058 andres                   6067 GIC        2073 :             Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
 2058 andres                   6068 ECB             : 
 2058 andres                   6069 GIC        2073 :             if (attr->attnotnull && !attr->attisdropped)
 6117 tgl                      6070             805 :                 notnull_attrs = lappend_int(notnull_attrs, i);
                               6071                 :         }
                               6072             758 :         if (notnull_attrs)
                               6073             571 :             needscan = true;
                               6074                 :     }
                               6075                 : 
 5170                          6076            2366 :     if (newrel || needscan)
                               6077                 :     {
                               6078                 :         ExprContext *econtext;
                               6079                 :         TupleTableSlot *oldslot;
 6913 tgl                      6080 ECB             :         TupleTableSlot *newslot;
 1490 andres                   6081                 :         TableScanDesc scan;
                               6082                 :         MemoryContext oldCxt;
 6385 bruce                    6083 GIC        1983 :         List       *dropped_attrs = NIL;
                               6084                 :         ListCell   *lc;
                               6085                 :         Snapshot    snapshot;
                               6086                 : 
 4439 rhaas                    6087            1983 :         if (newrel)
                               6088             368 :             ereport(DEBUG1,
                               6089                 :                     (errmsg_internal("rewriting table \"%s\"",
                               6090                 :                                      RelationGetRelationName(oldrel))));
                               6091                 :         else
                               6092            1615 :             ereport(DEBUG1,
                               6093                 :                     (errmsg_internal("verifying table \"%s\"",
                               6094                 :                                      RelationGetRelationName(oldrel))));
                               6095                 : 
 4323 heikki.linnakangas       6096            1983 :         if (newrel)
                               6097                 :         {
                               6098                 :             /*
                               6099                 :              * All predicate locks on the tuples or pages are about to be made
                               6100                 :              * invalid, because we move tuples around.  Promote them to
 4323 heikki.linnakangas       6101 ECB             :              * relation locks.
                               6102                 :              */
 4323 heikki.linnakangas       6103 GIC         368 :             TransferPredicateLocksToHeapRelation(oldrel);
                               6104                 :         }
                               6105                 : 
 6913 tgl                      6106            1983 :         econtext = GetPerTupleExprContext(estate);
                               6107                 : 
                               6108                 :         /*
 1490 andres                   6109 ECB             :          * Create necessary tuple slots. When rewriting, two slots are needed,
                               6110                 :          * otherwise one suffices. In the case where one slot suffices, we
                               6111                 :          * need to use the new tuple descriptor, otherwise some constraints
                               6112                 :          * can't be evaluated.  Note that even when the tuple layout is the
                               6113                 :          * same and no rewrite is required, the tupDescs might not be
                               6114                 :          * (consider ADD COLUMN without a default).
                               6115                 :          */
 1490 andres                   6116 GIC        1983 :         if (tab->rewrite)
                               6117                 :         {
                               6118             368 :             Assert(newrel != NULL);
 1490 andres                   6119 CBC         368 :             oldslot = MakeSingleTupleTableSlot(oldTupDesc,
                               6120                 :                                                table_slot_callbacks(oldrel));
                               6121             368 :             newslot = MakeSingleTupleTableSlot(newTupDesc,
                               6122                 :                                                table_slot_callbacks(newrel));
                               6123                 : 
                               6124                 :             /*
                               6125                 :              * Set all columns in the new slot to NULL initially, to ensure
 1203 tgl                      6126 ECB             :              * columns added as part of the rewrite are initialized to NULL.
                               6127                 :              * That is necessary as tab->newvals will not contain an
 1278 andres                   6128                 :              * expression for columns with a NULL default, e.g. when adding a
                               6129                 :              * column without a default together with a column with a default
                               6130                 :              * requiring an actual rewrite.
                               6131                 :              */
 1278 andres                   6132 GIC         368 :             ExecStoreAllNullTuple(newslot);
                               6133                 :         }
                               6134                 :         else
                               6135                 :         {
 1490                          6136            1615 :             oldslot = MakeSingleTupleTableSlot(newTupDesc,
                               6137                 :                                                table_slot_callbacks(oldrel));
                               6138            1615 :             newslot = NULL;
                               6139                 :         }
 6913 tgl                      6140 ECB             : 
 6633 neilc                    6141                 :         /*
                               6142                 :          * Any attributes that are dropped according to the new tuple
                               6143                 :          * descriptor can be set to NULL. We precompute the list of dropped
                               6144                 :          * attributes to avoid needing to do so in the per-tuple loop.
                               6145                 :          */
 6633 neilc                    6146 GIC        7029 :         for (i = 0; i < newTupDesc->natts; i++)
                               6147                 :         {
 2058 andres                   6148 CBC        5046 :             if (TupleDescAttr(newTupDesc, i)->attisdropped)
 6633 neilc                    6149             381 :                 dropped_attrs = lappend_int(dropped_attrs, i);
                               6150                 :         }
                               6151                 : 
                               6152                 :         /*
                               6153                 :          * Scan through the rows, generating a new row if needed and then
                               6154                 :          * checking all the constraints.
                               6155                 :          */
 3568 rhaas                    6156            1983 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
 1490 andres                   6157 GIC        1983 :         scan = table_beginscan(oldrel, snapshot, 0, NULL);
 6913 tgl                      6158 ECB             : 
                               6159                 :         /*
                               6160                 :          * Switch to per-tuple memory context and reset it for each tuple
 6385 bruce                    6161                 :          * produced, so we don't leak memory.
                               6162                 :          */
 6633 neilc                    6163 CBC        1983 :         oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
                               6164                 : 
 1490 andres                   6165          385085 :         while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
                               6166                 :         {
                               6167                 :             TupleTableSlot *insertslot;
                               6168                 : 
 3044 simon                    6169 GIC      381222 :             if (tab->rewrite > 0)
                               6170                 :             {
                               6171                 :                 /* Extract data from old tuple */
 1490 andres                   6172           48647 :                 slot_getallattrs(oldslot);
                               6173           48647 :                 ExecClearTuple(newslot);
                               6174                 : 
                               6175                 :                 /* copy attributes */
                               6176           48647 :                 memcpy(newslot->tts_values, oldslot->tts_values,
 1490 andres                   6177 CBC       48647 :                        sizeof(Datum) * oldslot->tts_nvalid);
 1490 andres                   6178 GIC       48647 :                 memcpy(newslot->tts_isnull, oldslot->tts_isnull,
 1490 andres                   6179 CBC       48647 :                        sizeof(bool) * oldslot->tts_nvalid);
 8262 tgl                      6180 ECB             : 
                               6181                 :                 /* Set dropped attributes to null in new tuple */
 6385 bruce                    6182 GIC       48690 :                 foreach(lc, dropped_attrs)
 1490 andres                   6183              43 :                     newslot->tts_isnull[lfirst_int(lc)] = true;
 7836 bruce                    6184 ECB             : 
  688 tgl                      6185                 :                 /*
                               6186                 :                  * Constraints and GENERATED expressions might reference the
                               6187                 :                  * tableoid column, so fill tts_tableOid with the desired
                               6188                 :                  * value.  (We must do this each time, because it gets
                               6189                 :                  * overwritten with newrel's OID during storing.)
                               6190                 :                  */
  688 tgl                      6191 CBC       48647 :                 newslot->tts_tableOid = RelationGetRelid(oldrel);
                               6192                 : 
 6913 tgl                      6193 ECB             :                 /*
                               6194                 :                  * Process supplied expressions to replace selected columns.
                               6195                 :                  *
 1187                          6196                 :                  * First, evaluate expressions whose inputs come from the old
                               6197                 :                  * tuple.
                               6198                 :                  */
 6913 tgl                      6199 CBC       48647 :                 econtext->ecxt_scantuple = oldslot;
                               6200                 : 
 6913 tgl                      6201 GIC      100279 :                 foreach(l, tab->newvals)
 6913 tgl                      6202 ECB             :                 {
 6797 bruce                    6203 GIC       51638 :                     NewColumnValue *ex = lfirst(l);
 6913 tgl                      6204 ECB             : 
 1187 tgl                      6205 GIC       51638 :                     if (ex->is_generated)
                               6206              30 :                         continue;
                               6207                 : 
 1490 andres                   6208           51608 :                     newslot->tts_values[ex->attnum - 1]
                               6209           51602 :                         = ExecEvalExpr(ex->exprstate,
                               6210                 :                                        econtext,
                               6211           51608 :                                        &newslot->tts_isnull[ex->attnum - 1]);
                               6212                 :                 }
 7664 tgl                      6213 ECB             : 
 1490 andres                   6214 GIC       48641 :                 ExecStoreVirtualTuple(newslot);
                               6215                 : 
                               6216                 :                 /*
 1187 tgl                      6217 ECB             :                  * Now, evaluate any expressions whose inputs come from the
                               6218                 :                  * new tuple.  We assume these columns won't reference each
                               6219                 :                  * other, so that there's no ordering dependency.
                               6220                 :                  */
 1187 tgl                      6221 GIC       48641 :                 econtext->ecxt_scantuple = newslot;
 1187 tgl                      6222 ECB             : 
 1187 tgl                      6223 GIC      100273 :                 foreach(l, tab->newvals)
 1187 tgl                      6224 ECB             :                 {
 1187 tgl                      6225 GIC       51632 :                     NewColumnValue *ex = lfirst(l);
                               6226                 : 
 1187 tgl                      6227 CBC       51632 :                     if (!ex->is_generated)
 1187 tgl                      6228 GIC       51602 :                         continue;
 1187 tgl                      6229 ECB             : 
 1187 tgl                      6230 GIC          30 :                     newslot->tts_values[ex->attnum - 1]
 1187 tgl                      6231 CBC          30 :                         = ExecEvalExpr(ex->exprstate,
 1187 tgl                      6232 ECB             :                                        econtext,
 1187 tgl                      6233 GIC          30 :                                        &newslot->tts_isnull[ex->attnum - 1]);
                               6234                 :                 }
 1187 tgl                      6235 ECB             : 
 1490 andres                   6236 GIC       48641 :                 insertslot = newslot;
                               6237                 :             }
                               6238                 :             else
                               6239                 :             {
                               6240                 :                 /*
                               6241                 :                  * If there's no rewrite, old and new table are guaranteed to
                               6242                 :                  * have the same AM, so we can just use the old slot to verify
 1418 tgl                      6243 ECB             :                  * new constraints etc.
                               6244                 :                  */
 1490 andres                   6245 GIC      332575 :                 insertslot = oldslot;
                               6246                 :             }
                               6247                 : 
                               6248                 :             /* Now check any constraints on the possibly-changed tuple */
 1490 andres                   6249 CBC      381216 :             econtext->ecxt_scantuple = insertslot;
                               6250                 : 
 6117 tgl                      6251 GIC     1669304 :             foreach(l, notnull_attrs)
                               6252                 :             {
 6031 bruce                    6253         1288115 :                 int         attn = lfirst_int(l);
                               6254                 : 
 1490 andres                   6255         1288115 :                 if (slot_attisnull(insertslot, attn + 1))
                               6256                 :                 {
 2058 andres                   6257 CBC          27 :                     Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
                               6258                 : 
 6117 tgl                      6259 GIC          27 :                     ereport(ERROR,
                               6260                 :                             (errcode(ERRCODE_NOT_NULL_VIOLATION),
                               6261                 :                              errmsg("column \"%s\" of relation \"%s\" contains null values",
                               6262                 :                                     NameStr(attr->attname),
 1167 akapila                  6263 ECB             :                                     RelationGetRelationName(oldrel)),
 3722 tgl                      6264                 :                              errtablecol(oldrel, attn + 1)));
 2058 andres                   6265                 :                 }
                               6266                 :             }
 6117 tgl                      6267                 : 
 6913 tgl                      6268 CBC      385230 :             foreach(l, tab->constraints)
                               6269                 :             {
                               6270            4074 :                 NewConstraint *con = lfirst(l);
                               6271                 : 
 6913 tgl                      6272 GIC        4074 :                 switch (con->contype)
                               6273                 :                 {
                               6274            4030 :                     case CONSTR_CHECK:
 2217 andres                   6275            4030 :                         if (!ExecCheck(con->qualstate, econtext))
 6913 tgl                      6276 CBC          33 :                             ereport(ERROR,
                               6277                 :                                     (errcode(ERRCODE_CHECK_VIOLATION),
 1167 akapila                  6278 ECB             :                                      errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
                               6279                 :                                             con->name,
                               6280                 :                                             RelationGetRelationName(oldrel)),
                               6281                 :                                      errtableconstraint(oldrel, con->name)));
 6913 tgl                      6282 GIC        3997 :                         break;
    2 alvherre                 6283 GNC          44 :                     case CONSTR_NOTNULL:
                               6284                 :                     case CONSTR_FOREIGN:
                               6285                 :                         /* Nothing to do here */
 6913 tgl                      6286 CBC          44 :                         break;
 6913 tgl                      6287 LBC           0 :                     default:
                               6288               0 :                         elog(ERROR, "unrecognized constraint type: %d",
                               6289                 :                              (int) con->contype);
                               6290                 :                 }
                               6291                 :             }
                               6292                 : 
 2217 andres                   6293 GIC      381156 :             if (partqualstate && !ExecCheck(partqualstate, econtext))
                               6294                 :             {
 2039 rhaas                    6295 CBC          37 :                 if (tab->validate_default)
 2039 rhaas                    6296 GIC          13 :                     ereport(ERROR,
                               6297                 :                             (errcode(ERRCODE_CHECK_VIOLATION),
 1167 akapila                  6298 ECB             :                              errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
                               6299                 :                                     RelationGetRelationName(oldrel)),
 1112                          6300                 :                              errtable(oldrel)));
                               6301                 :                 else
 2039 rhaas                    6302 CBC          24 :                     ereport(ERROR,
                               6303                 :                             (errcode(ERRCODE_CHECK_VIOLATION),
 1167 akapila                  6304 ECB             :                              errmsg("partition constraint of relation \"%s\" is violated by some row",
 1112                          6305                 :                                     RelationGetRelationName(oldrel)),
                               6306                 :                              errtable(oldrel)));
 2039 rhaas                    6307                 :             }
 2314                          6308                 : 
                               6309                 :             /* Write the tuple out to the new relation */
 6913 tgl                      6310 CBC      381119 :             if (newrel)
 1417 andres                   6311 GBC       48638 :                 table_tuple_insert(newrel, insertslot, mycid,
 1417 andres                   6312 EUB             :                                    ti_options, bistate);
                               6313                 : 
 6913 tgl                      6314 GIC      381119 :             ResetExprContext(econtext);
                               6315                 : 
                               6316          381119 :             CHECK_FOR_INTERRUPTS();
                               6317                 :         }
 7664 tgl                      6318 ECB             : 
 6633 neilc                    6319 GIC        1880 :         MemoryContextSwitchTo(oldCxt);
 1490 andres                   6320 CBC        1880 :         table_endscan(scan);
 3568 rhaas                    6321            1880 :         UnregisterSnapshot(snapshot);
                               6322                 : 
 6141 tgl                      6323 GIC        1880 :         ExecDropSingleTupleTableSlot(oldslot);
 1490 andres                   6324 CBC        1880 :         if (newslot)
 1490 andres                   6325 GIC         359 :             ExecDropSingleTupleTableSlot(newslot);
 7653 tgl                      6326 ECB             :     }
                               6327                 : 
 6913 tgl                      6328 GIC        2263 :     FreeExecutorState(estate);
 7664 tgl                      6329 ECB             : 
 1539 andres                   6330 GIC        2263 :     table_close(oldrel, NoLock);
 6913 tgl                      6331            2263 :     if (newrel)
 4904 heikki.linnakangas       6332 ECB             :     {
 4904 heikki.linnakangas       6333 CBC         359 :         FreeBulkInsertState(bistate);
                               6334                 : 
 1469 andres                   6335 GIC         359 :         table_finish_bulk_insert(newrel, ti_options);
                               6336                 : 
 1539                          6337             359 :         table_close(newrel, NoLock);
                               6338                 :     }
 6913 tgl                      6339            2263 : }
                               6340                 : 
 6913 tgl                      6341 ECB             : /*
                               6342                 :  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
                               6343                 :  */
                               6344                 : static AlteredTableInfo *
 6913 tgl                      6345 CBC       48759 : ATGetQueueEntry(List **wqueue, Relation rel)
 6913 tgl                      6346 ECB             : {
 6913 tgl                      6347 GIC       48759 :     Oid         relid = RelationGetRelid(rel);
 6913 tgl                      6348 ECB             :     AlteredTableInfo *tab;
 6892 neilc                    6349                 :     ListCell   *ltab;
                               6350                 : 
 6913 tgl                      6351 GIC       52842 :     foreach(ltab, *wqueue)
 6913 tgl                      6352 ECB             :     {
 6913 tgl                      6353 GIC        6083 :         tab = (AlteredTableInfo *) lfirst(ltab);
                               6354            6083 :         if (tab->relid == relid)
                               6355            2000 :             return tab;
                               6356                 :     }
                               6357                 : 
                               6358                 :     /*
 6913 tgl                      6359 ECB             :      * Not there, so add it.  Note that we make a copy of the relation's
                               6360                 :      * existing descriptor before anything interesting can happen to it.
                               6361                 :      */
 6913 tgl                      6362 GIC       46759 :     tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
 6913 tgl                      6363 CBC       46759 :     tab->relid = relid;
  745 alvherre                 6364           46759 :     tab->rel = NULL;         /* set later */
 6910 tgl                      6365 GIC       46759 :     tab->relkind = rel->rd_rel->relkind;
 1838 andrew                   6366           46759 :     tab->oldDesc = CreateTupleDescCopyConstr(RelationGetDescr(rel));
  620 michael                  6367           46759 :     tab->newAccessMethod = InvalidOid;
  620 michael                  6368 CBC       46759 :     tab->newTableSpace = InvalidOid;
 3152 alvherre                 6369 GIC       46759 :     tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
 3149                          6370           46759 :     tab->chgPersistence = false;
                               6371                 : 
 6913 tgl                      6372 CBC       46759 :     *wqueue = lappend(*wqueue, tab);
                               6373                 : 
 6913 tgl                      6374 GIC       46759 :     return tab;
                               6375                 : }
                               6376                 : 
                               6377                 : static const char *
  640 peter                    6378              21 : alter_table_type_to_string(AlterTableType cmdtype)
  640 peter                    6379 ECB             : {
  640 peter                    6380 GIC          21 :     switch (cmdtype)
                               6381                 :     {
  640 peter                    6382 LBC           0 :         case AT_AddColumn:
                               6383                 :         case AT_AddColumnToView:
  640 peter                    6384 UIC           0 :             return "ADD COLUMN";
                               6385               0 :         case AT_ColumnDefault:
                               6386                 :         case AT_CookedColumnDefault:
                               6387               0 :             return "ALTER COLUMN ... SET DEFAULT";
  640 peter                    6388 GIC           3 :         case AT_DropNotNull:
                               6389               3 :             return "ALTER COLUMN ... DROP NOT NULL";
                               6390               3 :         case AT_SetNotNull:
  640 peter                    6391 CBC           3 :             return "ALTER COLUMN ... SET NOT NULL";
    2 alvherre                 6392 UNC           0 :         case AT_SetAttNotNull:
                               6393               0 :             return NULL;        /* not real grammar */
  640 peter                    6394 UIC           0 :         case AT_DropExpression:
  640 peter                    6395 LBC           0 :             return "ALTER COLUMN ... DROP EXPRESSION";
                               6396               0 :         case AT_CheckNotNull:
  633 tgl                      6397 UIC           0 :             return NULL;        /* not real grammar */
  640 peter                    6398 LBC           0 :         case AT_SetStatistics:
  640 peter                    6399 UIC           0 :             return "ALTER COLUMN ... SET STATISTICS";
  640 peter                    6400 GIC           6 :         case AT_SetOptions:
                               6401               6 :             return "ALTER COLUMN ... SET";
  640 peter                    6402 UIC           0 :         case AT_ResetOptions:
                               6403               0 :             return "ALTER COLUMN ... RESET";
                               6404               0 :         case AT_SetStorage:
                               6405               0 :             return "ALTER COLUMN ... SET STORAGE";
                               6406               0 :         case AT_SetCompression:
                               6407               0 :             return "ALTER COLUMN ... SET COMPRESSION";
  640 peter                    6408 GIC           3 :         case AT_DropColumn:
                               6409               3 :             return "DROP COLUMN";
  640 peter                    6410 UIC           0 :         case AT_AddIndex:
                               6411                 :         case AT_ReAddIndex:
  633 tgl                      6412 LBC           0 :             return NULL;        /* not real grammar */
  640 peter                    6413 UIC           0 :         case AT_AddConstraint:
                               6414                 :         case AT_ReAddConstraint:
                               6415                 :         case AT_ReAddDomainConstraint:
                               6416                 :         case AT_AddIndexConstraint:
                               6417               0 :             return "ADD CONSTRAINT";
  640 peter                    6418 GIC           3 :         case AT_AlterConstraint:
                               6419               3 :             return "ALTER CONSTRAINT";
  640 peter                    6420 UIC           0 :         case AT_ValidateConstraint:
                               6421               0 :             return "VALIDATE CONSTRAINT";
  640 peter                    6422 LBC           0 :         case AT_DropConstraint:
  640 peter                    6423 UIC           0 :             return "DROP CONSTRAINT";
                               6424               0 :         case AT_ReAddComment:
  633 tgl                      6425               0 :             return NULL;        /* not real grammar */
  640 peter                    6426               0 :         case AT_AlterColumnType:
                               6427               0 :             return "ALTER COLUMN ... SET DATA TYPE";
                               6428               0 :         case AT_AlterColumnGenericOptions:
  640 peter                    6429 LBC           0 :             return "ALTER COLUMN ... OPTIONS";
                               6430               0 :         case AT_ChangeOwner:
  640 peter                    6431 UIC           0 :             return "OWNER TO";
                               6432               0 :         case AT_ClusterOn:
                               6433               0 :             return "CLUSTER ON";
                               6434               0 :         case AT_DropCluster:
                               6435               0 :             return "SET WITHOUT CLUSTER";
  620 michael                  6436 LBC           0 :         case AT_SetAccessMethod:
  620 michael                  6437 UIC           0 :             return "SET ACCESS METHOD";
  640 peter                    6438 LBC           0 :         case AT_SetLogged:
  640 peter                    6439 UIC           0 :             return "SET LOGGED";
                               6440               0 :         case AT_SetUnLogged:
                               6441               0 :             return "SET UNLOGGED";
  640 peter                    6442 LBC           0 :         case AT_DropOids:
  640 peter                    6443 UIC           0 :             return "SET WITHOUT OIDS";
                               6444               0 :         case AT_SetTableSpace:
  640 peter                    6445 LBC           0 :             return "SET TABLESPACE";
                               6446               0 :         case AT_SetRelOptions:
  640 peter                    6447 UIC           0 :             return "SET";
                               6448               0 :         case AT_ResetRelOptions:
  640 peter                    6449 LBC           0 :             return "RESET";
                               6450               0 :         case AT_ReplaceRelOptions:
  633 tgl                      6451               0 :             return NULL;        /* not real grammar */
  640 peter                    6452               0 :         case AT_EnableTrig:
  640 peter                    6453 UIC           0 :             return "ENABLE TRIGGER";
                               6454               0 :         case AT_EnableAlwaysTrig:
  640 peter                    6455 LBC           0 :             return "ENABLE ALWAYS TRIGGER";
                               6456               0 :         case AT_EnableReplicaTrig:
  640 peter                    6457 UIC           0 :             return "ENABLE REPLICA TRIGGER";
                               6458               0 :         case AT_DisableTrig:
                               6459               0 :             return "DISABLE TRIGGER";
                               6460               0 :         case AT_EnableTrigAll:
                               6461               0 :             return "ENABLE TRIGGER ALL";
                               6462               0 :         case AT_DisableTrigAll:
                               6463               0 :             return "DISABLE TRIGGER ALL";
  640 peter                    6464 LBC           0 :         case AT_EnableTrigUser:
  640 peter                    6465 UIC           0 :             return "ENABLE TRIGGER USER";
                               6466               0 :         case AT_DisableTrigUser:
                               6467               0 :             return "DISABLE TRIGGER USER";
                               6468               0 :         case AT_EnableRule:
                               6469               0 :             return "ENABLE RULE";
                               6470               0 :         case AT_EnableAlwaysRule:
                               6471               0 :             return "ENABLE ALWAYS RULE";
  640 peter                    6472 LBC           0 :         case AT_EnableReplicaRule:
  640 peter                    6473 UIC           0 :             return "ENABLE REPLICA RULE";
  640 peter                    6474 LBC           0 :         case AT_DisableRule:
  640 peter                    6475 UIC           0 :             return "DISABLE RULE";
  640 peter                    6476 LBC           0 :         case AT_AddInherit:
  640 peter                    6477 UIC           0 :             return "INHERIT";
  640 peter                    6478 LBC           0 :         case AT_DropInherit:
                               6479               0 :             return "NO INHERIT";
  640 peter                    6480 UIC           0 :         case AT_AddOf:
  640 peter                    6481 LBC           0 :             return "OF";
                               6482               0 :         case AT_DropOf:
  640 peter                    6483 UIC           0 :             return "NOT OF";
  640 peter                    6484 LBC           0 :         case AT_ReplicaIdentity:
  640 peter                    6485 UIC           0 :             return "REPLICA IDENTITY";
                               6486               0 :         case AT_EnableRowSecurity:
  640 peter                    6487 LBC           0 :             return "ENABLE ROW SECURITY";
  640 peter                    6488 UIC           0 :         case AT_DisableRowSecurity:
                               6489               0 :             return "DISABLE ROW SECURITY";
                               6490               0 :         case AT_ForceRowSecurity:
                               6491               0 :             return "FORCE ROW SECURITY";
                               6492               0 :         case AT_NoForceRowSecurity:
                               6493               0 :             return "NO FORCE ROW SECURITY";
  640 peter                    6494 LBC           0 :         case AT_GenericOptions:
  640 peter                    6495 UIC           0 :             return "OPTIONS";
  640 peter                    6496 LBC           0 :         case AT_AttachPartition:
  640 peter                    6497 UIC           0 :             return "ATTACH PARTITION";
  640 peter                    6498 CBC           3 :         case AT_DetachPartition:
  640 peter                    6499 GIC           3 :             return "DETACH PARTITION";
  640 peter                    6500 LBC           0 :         case AT_DetachPartitionFinalize:
                               6501               0 :             return "DETACH PARTITION ... FINALIZE";
  640 peter                    6502 UIC           0 :         case AT_AddIdentity:
  640 peter                    6503 LBC           0 :             return "ALTER COLUMN ... ADD IDENTITY";
                               6504               0 :         case AT_SetIdentity:
  640 peter                    6505 UIC           0 :             return "ALTER COLUMN ... SET";
  640 peter                    6506 LBC           0 :         case AT_DropIdentity:
  640 peter                    6507 UIC           0 :             return "ALTER COLUMN ... DROP IDENTITY";
                               6508               0 :         case AT_ReAddStatistics:
  633 tgl                      6509 LBC           0 :             return NULL;        /* not real grammar */
                               6510                 :     }
                               6511                 : 
  640 peter                    6512 UIC           0 :     return NULL;
                               6513                 : }
                               6514                 : 
                               6515                 : /*
                               6516                 :  * ATSimplePermissions
                               6517                 :  *
 6913 tgl                      6518 ECB             :  * - Ensure that it is a relation (or possibly a view)
                               6519                 :  * - Ensure this user is the owner
                               6520                 :  * - Ensure that it is not a system table
                               6521                 :  */
                               6522                 : static void
  640 peter                    6523 GIC       47080 : ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
 7689 tgl                      6524 ECB             : {
                               6525                 :     int         actual_target;
 4481 rhaas                    6526                 : 
 4481 rhaas                    6527 GIC       47080 :     switch (rel->rd_rel->relkind)
 6913 tgl                      6528 ECB             :     {
 4481 rhaas                    6529 GIC       45994 :         case RELKIND_RELATION:
 2314 rhaas                    6530 ECB             :         case RELKIND_PARTITIONED_TABLE:
 4481 rhaas                    6531 GIC       45994 :             actual_target = ATT_TABLE;
 4481 rhaas                    6532 CBC       45994 :             break;
 4481 rhaas                    6533 GIC         198 :         case RELKIND_VIEW:
                               6534             198 :             actual_target = ATT_VIEW;
                               6535             198 :             break;
 3689 kgrittn                  6536              23 :         case RELKIND_MATVIEW:
                               6537              23 :             actual_target = ATT_MATVIEW;
                               6538              23 :             break;
 4481 rhaas                    6539             113 :         case RELKIND_INDEX:
                               6540             113 :             actual_target = ATT_INDEX;
 4481 rhaas                    6541 CBC         113 :             break;
 1906 alvherre                 6542 GIC         207 :         case RELKIND_PARTITIONED_INDEX:
 1906 alvherre                 6543 CBC         207 :             actual_target = ATT_PARTITIONED_INDEX;
 1906 alvherre                 6544 GIC         207 :             break;
 4481 rhaas                    6545 CBC         107 :         case RELKIND_COMPOSITE_TYPE:
 4481 rhaas                    6546 GIC         107 :             actual_target = ATT_COMPOSITE_TYPE;
 4481 rhaas                    6547 CBC         107 :             break;
                               6548             432 :         case RELKIND_FOREIGN_TABLE:
                               6549             432 :             actual_target = ATT_FOREIGN_TABLE;
 4481 rhaas                    6550 GIC         432 :             break;
  367 peter                    6551               6 :         case RELKIND_SEQUENCE:
                               6552               6 :             actual_target = ATT_SEQUENCE;
                               6553               6 :             break;
 4481 rhaas                    6554 UIC           0 :         default:
 4481 rhaas                    6555 LBC           0 :             actual_target = 0;
                               6556               0 :             break;
                               6557                 :     }
                               6558                 : 
 4481 rhaas                    6559 ECB             :     /* Wrong target type? */
 4481 rhaas                    6560 GBC       47080 :     if ((actual_target & allowed_targets) == 0)
  640 peter                    6561 EUB             :     {
  640 peter                    6562 GIC          21 :         const char *action_str = alter_table_type_to_string(cmdtype);
                               6563                 : 
                               6564              21 :         if (action_str)
                               6565              21 :             ereport(ERROR,
  640 peter                    6566 ECB             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               6567                 :             /* translator: %s is a group of some SQL keywords */
                               6568                 :                      errmsg("ALTER action %s cannot be performed on relation \"%s\"",
                               6569                 :                             action_str, RelationGetRelationName(rel)),
                               6570                 :                      errdetail_relkind_not_supported(rel->rd_rel->relkind)));
                               6571                 :         else
                               6572                 :             /* internal error? */
  640 peter                    6573 UIC           0 :             elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
                               6574                 :                  RelationGetRelationName(rel));
  640 peter                    6575 ECB             :     }
                               6576                 : 
                               6577                 :     /* Permissions checks */
  147 peter                    6578 GNC       47059 :     if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
 1954 peter_e                  6579 GIC           3 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
 7191 tgl                      6580               3 :                        RelationGetRelationName(rel));
                               6581                 : 
 7203                          6582           47056 :     if (!allowSystemTableMods && IsSystemRelation(rel))
 7203 tgl                      6583 LBC           0 :         ereport(ERROR,
 7203 tgl                      6584 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                               6585                 :                  errmsg("permission denied: \"%s\" is a system catalog",
                               6586                 :                         RelationGetRelationName(rel))));
 6913 tgl                      6587 CBC       47056 : }
                               6588                 : 
 6913 tgl                      6589 ECB             : /*
                               6590                 :  * ATSimpleRecursion
                               6591                 :  *
                               6592                 :  * Simple table recursion sufficient for most ALTER TABLE operations.
                               6593                 :  * All direct and indirect children are processed in an unspecified order.
                               6594                 :  * Note that if a child inherits from the original table via multiple
                               6595                 :  * inheritance paths, it will be visited just once.
                               6596                 :  */
                               6597                 : static void
 6913 tgl                      6598 CBC       28881 : ATSimpleRecursion(List **wqueue, Relation rel,
                               6599                 :                   AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
                               6600                 :                   AlterTableUtilityContext *context)
 6913 tgl                      6601 ECB             : {
                               6602                 :     /*
  935                          6603                 :      * Propagate to children, if desired and if there are (or might be) any
                               6604                 :      * children.
                               6605                 :      */
  935 tgl                      6606 CBC       28881 :     if (recurse && rel->rd_rel->relhassubclass)
                               6607                 :     {
 6913                          6608              50 :         Oid         relid = RelationGetRelid(rel);
                               6609                 :         ListCell   *child;
 6892 neilc                    6610 ECB             :         List       *children;
                               6611                 : 
 4638 simon                    6612 CBC          50 :         children = find_all_inheritors(relid, lockmode, NULL);
                               6613                 : 
                               6614                 :         /*
                               6615                 :          * find_all_inheritors does the recursive search of the inheritance
                               6616                 :          * hierarchy, so all we have to do is process all of the relids in the
                               6617                 :          * list that it returns.
 7653 tgl                      6618 ECB             :          */
 7653 tgl                      6619 GIC         192 :         foreach(child, children)
 7664 tgl                      6620 ECB             :         {
 6892 neilc                    6621 GIC         142 :             Oid         childrelid = lfirst_oid(child);
                               6622                 :             Relation    childrel;
                               6623                 : 
 6913 tgl                      6624 CBC         142 :             if (childrelid == relid)
 7653 tgl                      6625 GIC          50 :                 continue;
 5080 tgl                      6626 ECB             :             /* find_all_inheritors already got lock */
 5080 tgl                      6627 CBC          92 :             childrel = relation_open(childrelid, NoLock);
 5548                          6628              92 :             CheckTableNotInUse(childrel, "ALTER TABLE");
 1180 tgl                      6629 GIC          92 :             ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
 6913                          6630              92 :             relation_close(childrel, NoLock);
                               6631                 :         }
                               6632                 :     }
                               6633           28881 : }
                               6634                 : 
 1356 alvherre                 6635 ECB             : /*
                               6636                 :  * Obtain list of partitions of the given table, locking them all at the given
                               6637                 :  * lockmode and ensuring that they all pass CheckTableNotInUse.
                               6638                 :  *
                               6639                 :  * This function is a no-op if the given relation is not a partitioned table;
                               6640                 :  * in particular, nothing is done if it's a legacy inheritance parent.
                               6641                 :  */
                               6642                 : static void
 1356 alvherre                 6643 CBC         264 : ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
                               6644                 : {
                               6645             264 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               6646                 :     {
 1356 alvherre                 6647 ECB             :         List       *inh;
                               6648                 :         ListCell   *cell;
                               6649                 : 
 1356 alvherre                 6650 GIC          61 :         inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
 1356 alvherre                 6651 ECB             :         /* first element is the parent rel; must ignore it */
  923 tgl                      6652 GIC         206 :         for_each_from(cell, inh, 1)
 1356 alvherre                 6653 ECB             :         {
                               6654                 :             Relation    childrel;
 1356 alvherre                 6655 EUB             : 
                               6656                 :             /* find_all_inheritors already got lock */
 1356 alvherre                 6657 GBC         148 :             childrel = table_open(lfirst_oid(cell), NoLock);
                               6658             148 :             CheckTableNotInUse(childrel, "ALTER TABLE");
 1356 alvherre                 6659 GIC         145 :             table_close(childrel, NoLock);
 1356 alvherre                 6660 EUB             :         }
 1356 alvherre                 6661 CBC          58 :         list_free(inh);
 1356 alvherre                 6662 ECB             :     }
 1356 alvherre                 6663 CBC         261 : }
 1356 alvherre                 6664 ECB             : 
 4520 peter_e                  6665 EUB             : /*
                               6666                 :  * ATTypedTableRecursion
                               6667                 :  *
                               6668                 :  * Propagate ALTER TYPE operations to the typed tables of that type.
 4372 rhaas                    6669                 :  * Also check the RESTRICT/CASCADE behavior.  Given CASCADE, also permit
                               6670                 :  * recursion to inheritance children of the typed tables.
 4520 peter_e                  6671                 :  */
                               6672                 : static void
 4520 peter_e                  6673 CBC          95 : ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
 1180 tgl                      6674 ECB             :                       LOCKMODE lockmode, AlterTableUtilityContext *context)
 4520 peter_e                  6675 EUB             : {
                               6676                 :     ListCell   *child;
                               6677                 :     List       *children;
                               6678                 : 
 4520 peter_e                  6679 GBC          95 :     Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
 4520 peter_e                  6680 EUB             : 
 4520 peter_e                  6681 CBC          95 :     children = find_typed_table_dependencies(rel->rd_rel->reltype,
                               6682              95 :                                              RelationGetRelationName(rel),
 4520 peter_e                  6683 EUB             :                                              cmd->behavior);
                               6684                 : 
 4520 peter_e                  6685 GBC         101 :     foreach(child, children)
 4520 peter_e                  6686 EUB             :     {
 4520 peter_e                  6687 GIC          15 :         Oid         childrelid = lfirst_oid(child);
                               6688                 :         Relation    childrel;
                               6689                 : 
 4520 peter_e                  6690 GBC          15 :         childrel = relation_open(childrelid, lockmode);
 4520 peter_e                  6691 CBC          15 :         CheckTableNotInUse(childrel, "ALTER TABLE");
 1180 tgl                      6692              15 :         ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
 4520 peter_e                  6693 GBC          15 :         relation_close(childrel, NoLock);
 4520 peter_e                  6694 EUB             :     }
 4520 peter_e                  6695 GBC          86 : }
 4520 peter_e                  6696 EUB             : 
 6881 tgl                      6697                 : 
                               6698                 : /*
                               6699                 :  * find_composite_type_dependencies
                               6700                 :  *
 2069                          6701                 :  * Check to see if the type "typeOid" is being used as a column in some table
                               6702                 :  * (possibly nested several levels deep in composite types, arrays, etc!).
 6881                          6703                 :  * Eventually, we'd like to propagate the check or rewrite operation
 2069                          6704                 :  * into such tables, but for now, just error out if we find any.
 6881                          6705                 :  *
 2069                          6706                 :  * Caller should provide either the associated relation of a rowtype,
                               6707                 :  * or a type name (not both) for use in the error message, if any.
                               6708                 :  *
                               6709                 :  * Note that "typeOid" is not necessarily a composite type; it could also be
                               6710                 :  * another container type such as an array or range, or a domain over one of
                               6711                 :  * these things.  The name of this function is therefore somewhat historical,
                               6712                 :  * but it's not worth changing.
 5812                          6713                 :  *
 6881                          6714                 :  * We assume that functions and views depending on the type are not reasons
                               6715                 :  * to reject the ALTER.  (How safe is this really?)
                               6716                 :  */
 5812                          6717                 : void
 4440 rhaas                    6718 GBC        1752 : find_composite_type_dependencies(Oid typeOid, Relation origRelation,
 4440 rhaas                    6719 EUB             :                                  const char *origTypeName)
 6881 tgl                      6720                 : {
                               6721                 :     Relation    depRel;
                               6722                 :     ScanKeyData key[2];
                               6723                 :     SysScanDesc depScan;
                               6724                 :     HeapTuple   depTup;
 2069                          6725                 : 
                               6726                 :     /* since this function recurses, it could be driven to stack overflow */
 2069 tgl                      6727 GBC        1752 :     check_stack_depth();
 6881 tgl                      6728 EUB             : 
                               6729                 :     /*
 2069                          6730                 :      * We scan pg_depend to find those things that depend on the given type.
                               6731                 :      * (We assume we can ignore refobjsubid for a type.)
 6881                          6732                 :      */
 1539 andres                   6733 GBC        1752 :     depRel = table_open(DependRelationId, AccessShareLock);
 6881 tgl                      6734 EUB             : 
 6881 tgl                      6735 GBC        1752 :     ScanKeyInit(&key[0],
 6881 tgl                      6736 EUB             :                 Anum_pg_depend_refclassid,
                               6737                 :                 BTEqualStrategyNumber, F_OIDEQ,
 6569                          6738                 :                 ObjectIdGetDatum(TypeRelationId));
 6881 tgl                      6739 GBC        1752 :     ScanKeyInit(&key[1],
 6881 tgl                      6740 EUB             :                 Anum_pg_depend_refobjid,
                               6741                 :                 BTEqualStrategyNumber, F_OIDEQ,
                               6742                 :                 ObjectIdGetDatum(typeOid));
                               6743                 : 
 6569 tgl                      6744 GBC        1752 :     depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
 3568 rhaas                    6745 EUB             :                                  NULL, 2, key);
 6881 tgl                      6746                 : 
 6881 tgl                      6747 GBC        2720 :     while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
 6881 tgl                      6748 EUB             :     {
 6881 tgl                      6749 GBC        1016 :         Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
 6881 tgl                      6750 EUB             :         Relation    rel;
   13                          6751                 :         TupleDesc   tupleDesc;
 6881                          6752                 :         Form_pg_attribute att;
                               6753                 : 
 2069                          6754                 :         /* Check for directly dependent types */
 2069 tgl                      6755 GBC        1016 :         if (pg_depend->classid == TypeRelationId)
 2069 tgl                      6756 EUB             :         {
                               6757                 :             /*
                               6758                 :              * This must be an array, domain, or range containing the given
                               6759                 :              * type, so recursively check for uses of this type.  Note that
                               6760                 :              * any error message will mention the original type not the
                               6761                 :              * container; this is intentional.
                               6762                 :              */
 2069 tgl                      6763 GBC         843 :             find_composite_type_dependencies(pg_depend->objid,
 2069 tgl                      6764 EUB             :                                              origRelation, origTypeName);
 2069 tgl                      6765 GBC         831 :             continue;
 2069 tgl                      6766 EUB             :         }
                               6767                 : 
   13                          6768                 :         /* Else, ignore dependees that aren't relations */
   13 tgl                      6769 GBC         173 :         if (pg_depend->classid != RelationRelationId)
 6881                          6770              61 :             continue;
 6881 tgl                      6771 ECB             : 
 6881 tgl                      6772 CBC         112 :         rel = relation_open(pg_depend->objid, AccessShareLock);
   13 tgl                      6773 GBC         112 :         tupleDesc = RelationGetDescr(rel);
   13 tgl                      6774 EUB             : 
                               6775                 :         /*
                               6776                 :          * If objsubid identifies a specific column, refer to that in error
                               6777                 :          * messages.  Otherwise, search to see if there's a user column of the
                               6778                 :          * type.  (We assume system columns are never of interesting types.)
                               6779                 :          * The search is needed because an index containing an expression
                               6780                 :          * column of the target type will just be recorded as a whole-relation
                               6781                 :          * dependency.  If we do not find a column of the type, the dependency
                               6782                 :          * must indicate that the type is transiently referenced in an index
                               6783                 :          * expression but not stored on disk, which we assume is OK, just as
                               6784                 :          * we do for references in views.  (It could also be that the target
                               6785                 :          * type is embedded in some container type that is stored in an index
                               6786                 :          * column, but the previous recursion should catch such cases.)
                               6787                 :          */
   13 tgl                      6788 GIC         112 :         if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
                               6789              33 :             att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
                               6790                 :         else
                               6791                 :         {
                               6792              79 :             att = NULL;
                               6793             203 :             for (int attno = 1; attno <= tupleDesc->natts; attno++)
                               6794                 :             {
                               6795             127 :                 att = TupleDescAttr(tupleDesc, attno - 1);
   13 tgl                      6796 CBC         127 :                 if (att->atttypid == typeOid && !att->attisdropped)
   13 tgl                      6797 GIC           3 :                     break;
                               6798             124 :                 att = NULL;
                               6799                 :             }
   13 tgl                      6800 CBC          79 :             if (att == NULL)
                               6801                 :             {
   13 tgl                      6802 ECB             :                 /* No such column, so assume OK */
   13 tgl                      6803 GIC          76 :                 relation_close(rel, AccessShareLock);
   13 tgl                      6804 CBC          76 :                 continue;
   13 tgl                      6805 ECB             :             }
                               6806                 :         }
 6881                          6807                 : 
   13                          6808                 :         /*
                               6809                 :          * We definitely should reject if the relation has storage.  If it's
                               6810                 :          * partitioned, then perhaps we don't have to reject: if there are
                               6811                 :          * partitions then we'll fail when we find one, else there is no
                               6812                 :          * stored data to worry about.  However, it's possible that the type
                               6813                 :          * change would affect conclusions about whether the type is sortable
                               6814                 :          * or hashable and thus (if it's a partitioning column) break the
                               6815                 :          * partitioning rule.  For now, reject for partitioned rels too.
                               6816                 :          */
   13 tgl                      6817 CBC          36 :         if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
   13 tgl                      6818 LBC           0 :             RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
 6881 tgl                      6819 ECB             :         {
 4394 tgl                      6820 CBC          36 :             if (origTypeName)
                               6821              15 :                 ereport(ERROR,
 4394 tgl                      6822 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 4309 peter_e                  6823                 :                          errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
 4394 tgl                      6824                 :                                 origTypeName,
                               6825                 :                                 RelationGetRelationName(rel),
                               6826                 :                                 NameStr(att->attname))));
 4394 tgl                      6827 GBC          21 :             else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
                               6828               9 :                 ereport(ERROR,
 4394 tgl                      6829 EUB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               6830                 :                          errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
                               6831                 :                                 RelationGetRelationName(origRelation),
                               6832                 :                                 RelationGetRelationName(rel),
 4394 tgl                      6833 ECB             :                                 NameStr(att->attname))));
 4440 rhaas                    6834 GIC          12 :             else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
 4394 tgl                      6835 CBC           3 :                 ereport(ERROR,
                               6836                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 4309 peter_e                  6837 ECB             :                          errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
 4394 tgl                      6838                 :                                 RelationGetRelationName(origRelation),
                               6839                 :                                 RelationGetRelationName(rel),
                               6840                 :                                 NameStr(att->attname))));
                               6841                 :             else
 4394 tgl                      6842 GIC           9 :                 ereport(ERROR,
                               6843                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               6844                 :                          errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
                               6845                 :                                 RelationGetRelationName(origRelation),
 4394 tgl                      6846 EUB             :                                 RelationGetRelationName(rel),
                               6847                 :                                 NameStr(att->attname))));
                               6848                 :         }
 6881 tgl                      6849 UIC           0 :         else if (OidIsValid(rel->rd_rel->reltype))
                               6850                 :         {
 6881 tgl                      6851 ECB             :             /*
 6385 bruce                    6852                 :              * A view or composite type itself isn't a problem, but we must
                               6853                 :              * recursively check for indirect dependencies via its rowtype.
                               6854                 :              */
 6881 tgl                      6855 LBC           0 :             find_composite_type_dependencies(rel->rd_rel->reltype,
 4440 rhaas                    6856 EUB             :                                              origRelation, origTypeName);
                               6857                 :         }
                               6858                 : 
 6881 tgl                      6859 UIC           0 :         relation_close(rel, AccessShareLock);
 6881 tgl                      6860 ECB             :     }
                               6861                 : 
 6881 tgl                      6862 GIC        1704 :     systable_endscan(depScan);
                               6863                 : 
                               6864            1704 :     relation_close(depRel, AccessShareLock);
                               6865            1704 : }
                               6866                 : 
                               6867                 : 
                               6868                 : /*
                               6869                 :  * find_typed_table_dependencies
                               6870                 :  *
 4578 peter_e                  6871 ECB             :  * Check to see if a composite type is being used as the type of a
                               6872                 :  * typed table.  Abort if any are found and behavior is RESTRICT.
                               6873                 :  * Else return the list of tables.
                               6874                 :  */
                               6875                 : static List *
 4520 peter_e                  6876 GIC         107 : find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
                               6877                 : {
                               6878                 :     Relation    classRel;
 4578 peter_e                  6879 ECB             :     ScanKeyData key[1];
                               6880                 :     TableScanDesc scan;
                               6881                 :     HeapTuple   tuple;
 4520 peter_e                  6882 GIC         107 :     List       *result = NIL;
                               6883                 : 
 1539 andres                   6884             107 :     classRel = table_open(RelationRelationId, AccessShareLock);
 4578 peter_e                  6885 ECB             : 
 4578 peter_e                  6886 GIC         107 :     ScanKeyInit(&key[0],
                               6887                 :                 Anum_pg_class_reloftype,
                               6888                 :                 BTEqualStrategyNumber, F_OIDEQ,
                               6889                 :                 ObjectIdGetDatum(typeOid));
                               6890                 : 
 1490 andres                   6891             107 :     scan = table_beginscan_catalog(classRel, 1, key);
 4578 peter_e                  6892 ECB             : 
 4384 rhaas                    6893 GIC         125 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 4578 peter_e                  6894 ECB             :     {
 1601 andres                   6895 GIC          30 :         Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
                               6896                 : 
 4520 peter_e                  6897 CBC          30 :         if (behavior == DROP_RESTRICT)
                               6898              12 :             ereport(ERROR,
                               6899                 :                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
 4520 peter_e                  6900 ECB             :                      errmsg("cannot alter type \"%s\" because it is the type of a typed table",
                               6901                 :                             typeName),
 2118 tgl                      6902                 :                      errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
 4520 peter_e                  6903                 :         else
 1601 andres                   6904 GIC          18 :             result = lappend_oid(result, classform->oid);
                               6905                 :     }
 4578 peter_e                  6906 ECB             : 
 1490 andres                   6907 GIC          95 :     table_endscan(scan);
 1539                          6908              95 :     table_close(classRel, AccessShareLock);
                               6909                 : 
 4520 peter_e                  6910              95 :     return result;
                               6911                 : }
                               6912                 : 
                               6913                 : 
                               6914                 : /*
                               6915                 :  * check_of_type
 4372 rhaas                    6916 ECB             :  *
                               6917                 :  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF.  If it
                               6918                 :  * isn't suitable, throw an error.  Currently, we require that the type
                               6919                 :  * originated with CREATE TYPE AS.  We could support any row type, but doing so
                               6920                 :  * would require handling a number of extra corner cases in the DDL commands.
                               6921                 :  * (Also, allowing domain-over-composite would open up a can of worms about
                               6922                 :  * whether and how the domain's constraints should apply to derived tables.)
                               6923                 :  */
                               6924                 : void
 4372 rhaas                    6925 CBC          85 : check_of_type(HeapTuple typetuple)
                               6926                 : {
 4372 rhaas                    6927 GIC          85 :     Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
                               6928              85 :     bool        typeOk = false;
                               6929                 : 
 4372 rhaas                    6930 CBC          85 :     if (typ->typtype == TYPTYPE_COMPOSITE)
 4372 rhaas                    6931 ECB             :     {
                               6932                 :         Relation    typeRelation;
                               6933                 : 
 4372 rhaas                    6934 CBC          85 :         Assert(OidIsValid(typ->typrelid));
 4372 rhaas                    6935 GIC          85 :         typeRelation = relation_open(typ->typrelid, AccessShareLock);
 4372 rhaas                    6936 CBC          85 :         typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
                               6937                 : 
                               6938                 :         /*
                               6939                 :          * Close the parent rel, but keep our AccessShareLock on it until xact
                               6940                 :          * commit.  That will prevent someone else from deleting or ALTERing
                               6941                 :          * the type before the typed table creation/conversion commits.
                               6942                 :          */
 4372 rhaas                    6943 GIC          85 :         relation_close(typeRelation, NoLock);
                               6944                 :     }
                               6945              85 :     if (!typeOk)
 4372 rhaas                    6946 CBC           3 :         ereport(ERROR,
                               6947                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               6948                 :                  errmsg("type %s is not a composite type",
                               6949                 :                         format_type_be(typ->oid))));
 4372 rhaas                    6950 GIC          82 : }
                               6951                 : 
 4372 rhaas                    6952 ECB             : 
                               6953                 : /*
 6913 tgl                      6954                 :  * ALTER TABLE ADD COLUMN
                               6955                 :  *
                               6956                 :  * Adds an additional attribute to a relation making the assumption that
                               6957                 :  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
 5769                          6958                 :  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
                               6959                 :  * AlterTableCmd's.
 4389 rhaas                    6960                 :  *
                               6961                 :  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
                               6962                 :  * have to decide at runtime whether to recurse or not depending on whether we
                               6963                 :  * actually add a column or merely merge with an existing column.  (We can't
                               6964                 :  * check this in a static pre-pass because it won't handle multiple inheritance
                               6965                 :  * situations correctly.)
 6913 tgl                      6966                 :  */
                               6967                 : static void
 4520 peter_e                  6968 CBC         923 : ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                               6969                 :                 bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
                               6970                 :                 AlterTableUtilityContext *context)
                               6971                 : {
 4520 peter_e                  6972 GIC         923 :     if (rel->rd_rel->reloftype && !recursing)
 4643                          6973               3 :         ereport(ERROR,
                               6974                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               6975                 :                  errmsg("cannot add column to typed table")));
                               6976                 : 
 4578                          6977             920 :     if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
 1180 tgl                      6978              29 :         ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
                               6979                 : 
 2963 alvherre                 6980             917 :     if (recurse && !is_view)
  118 alvherre                 6981 GNC         867 :         cmd->recurse = true;
 6913 tgl                      6982 GIC         917 : }
                               6983                 : 
                               6984                 : /*
                               6985                 :  * Add a column to a table.  The return value is the address of the
                               6986                 :  * new column in the parent relation.
                               6987                 :  *
                               6988                 :  * cmd is pass-by-ref so that we can replace it with the parse-transformed
                               6989                 :  * copy (but that happens only after we check for IF NOT EXISTS).
                               6990                 :  */
 2937 alvherre                 6991 ECB             : static ObjectAddress
 4389 rhaas                    6992 GIC        1205 : ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
                               6993                 :                 AlterTableCmd **cmd, bool recurse, bool recursing,
                               6994                 :                 LOCKMODE lockmode, int cur_pass,
                               6995                 :                 AlterTableUtilityContext *context)
                               6996                 : {
 6913 tgl                      6997            1205 :     Oid         myrelid = RelationGetRelid(rel);
 1180                          6998            1205 :     ColumnDef  *colDef = castNode(ColumnDef, (*cmd)->def);
 1180 tgl                      6999 CBC        1205 :     bool        if_not_exists = (*cmd)->missing_ok;
                               7000                 :     Relation    pgclass,
                               7001                 :                 attrdesc;
                               7002                 :     HeapTuple   reltup;
                               7003                 :     FormData_pg_attribute attribute;
                               7004                 :     int         newattnum;
 5237 bruce                    7005 ECB             :     char        relkind;
                               7006                 :     HeapTuple   typeTuple;
 6649 tgl                      7007                 :     Oid         typeOid;
                               7008                 :     int32       typmod;
                               7009                 :     Oid         collOid;
                               7010                 :     Form_pg_type tform;
 6913                          7011                 :     Expr       *defval;
                               7012                 :     List       *children;
                               7013                 :     ListCell   *child;
                               7014                 :     AlterTableCmd *childcmd;
                               7015                 :     AclResult   aclresult;
 2937 alvherre                 7016                 :     ObjectAddress address;
                               7017                 :     TupleDesc   tupdesc;
  982 michael                  7018 GIC        1205 :     FormData_pg_attribute *aattr[] = {&attribute};
 4389 rhaas                    7019 ECB             : 
                               7020                 :     /* At top level, permission check was done in ATPrepCmd, else do it */
 4389 rhaas                    7021 CBC        1205 :     if (recursing)
  640 peter                    7022 GIC         291 :         ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               7023                 : 
 2314 rhaas                    7024            1205 :     if (rel->rd_rel->relispartition && !recursing)
                               7025               6 :         ereport(ERROR,
                               7026                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 2314 rhaas                    7027 ECB             :                  errmsg("cannot add column to a partition")));
                               7028                 : 
 1539 andres                   7029 GIC        1199 :     attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
                               7030                 : 
                               7031                 :     /*
                               7032                 :      * Are we adding the column to a recursion child?  If so, check whether to
                               7033                 :      * merge with an existing definition for the column.  If we do merge, we
                               7034                 :      * must not recurse.  Children will already have the column, and recursing
 4382 bruce                    7035 ECB             :      * into them would mess up attinhcount.
                               7036                 :      */
 6913 tgl                      7037 CBC        1199 :     if (colDef->inhcount > 0)
                               7038                 :     {
                               7039                 :         HeapTuple   tuple;
                               7040                 : 
 6913 tgl                      7041 ECB             :         /* Does child already have a column by this name? */
 6913 tgl                      7042 CBC         291 :         tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
 6913 tgl                      7043 GIC         291 :         if (HeapTupleIsValid(tuple))
 6913 tgl                      7044 ECB             :         {
 6913 tgl                      7045 CBC          12 :             Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
                               7046                 :             Oid         ctypeId;
                               7047                 :             int32       ctypmod;
                               7048                 :             Oid         ccollid;
                               7049                 : 
                               7050                 :             /* Child column must match on type, typmod, and collation */
 4414 tgl                      7051 GIC          12 :             typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
 5944                          7052              12 :             if (ctypeId != childatt->atttypid ||
                               7053              12 :                 ctypmod != childatt->atttypmod)
 6913 tgl                      7054 UIC           0 :                 ereport(ERROR,
                               7055                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                               7056                 :                          errmsg("child table \"%s\" has different type for column \"%s\"",
                               7057                 :                                 RelationGetRelationName(rel), colDef->colname)));
 4414 tgl                      7058 GIC          12 :             ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
 4443 peter_e                  7059              12 :             if (ccollid != childatt->attcollation)
 4443 peter_e                  7060 LBC           0 :                 ereport(ERROR,
 4443 peter_e                  7061 ECB             :                         (errcode(ERRCODE_COLLATION_MISMATCH),
                               7062                 :                          errmsg("child table \"%s\" has different collation for column \"%s\"",
                               7063                 :                                 RelationGetRelationName(rel), colDef->colname),
                               7064                 :                          errdetail("\"%s\" versus \"%s\"",
                               7065                 :                                    get_collation_name(ccollid),
                               7066                 :                                    get_collation_name(childatt->attcollation))));
 7664 tgl                      7067                 : 
 6913                          7068                 :             /* Bump the existing child att's inhcount */
 6913 tgl                      7069 CBC          12 :             childatt->attinhcount++;
   12 peter                    7070 GNC          12 :             if (childatt->attinhcount < 0)
   12 peter                    7071 UNC           0 :                 ereport(ERROR,
                               7072                 :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               7073                 :                         errmsg("too many inheritance parents"));
 2259 alvherre                 7074 CBC          12 :             CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
                               7075                 : 
 6913 tgl                      7076              12 :             heap_freetuple(tuple);
                               7077                 : 
                               7078                 :             /* Inform the user about the merge */
                               7079              12 :             ereport(NOTICE,
 2118 tgl                      7080 ECB             :                     (errmsg("merging definition of column \"%s\" for child \"%s\"",
                               7081                 :                             colDef->colname, RelationGetRelationName(rel))));
                               7082                 : 
 1539 andres                   7083 GIC          12 :             table_close(attrdesc, RowExclusiveLock);
 2937 alvherre                 7084              12 :             return InvalidObjectAddress;
                               7085                 :         }
                               7086                 :     }
                               7087                 : 
                               7088                 :     /* skip if the name already exists and if_not_exists is true */
 1180 tgl                      7089            1187 :     if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
                               7090                 :     {
                               7091              27 :         table_close(attrdesc, RowExclusiveLock);
                               7092              27 :         return InvalidObjectAddress;
 1180 tgl                      7093 ECB             :     }
 7664 tgl                      7094 EUB             : 
                               7095                 :     /*
 1180 tgl                      7096 ECB             :      * Okay, we need to add the column, so go ahead and do parse
                               7097                 :      * transformation.  This can result in queueing up, or even immediately
                               7098                 :      * executing, subsidiary operations (such as creation of unique indexes);
                               7099                 :      * so we mustn't do it until we have made the if_not_exists check.
                               7100                 :      *
                               7101                 :      * When recursing, the command was already transformed and we needn't do
                               7102                 :      * so again.  Also, if context isn't given we can't transform.  (That
                               7103                 :      * currently happens only for AT_AddColumnToView; we expect that view.c
                               7104                 :      * passed us a ColumnDef that doesn't need work.)
                               7105                 :      */
 1180 tgl                      7106 GIC        1145 :     if (context != NULL && !recursing)
                               7107                 :     {
                               7108             854 :         *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
                               7109                 :                                    cur_pass, context);
 1180 tgl                      7110 CBC         854 :         Assert(*cmd != NULL);
                               7111             854 :         colDef = castNode(ColumnDef, (*cmd)->def);
                               7112                 :     }
                               7113                 : 
                               7114                 :     /*
                               7115                 :      * Cannot add identity column if table has children, because identity does
                               7116                 :      * not inherit.  (Adding column and identity separately will work.)
                               7117                 :      */
 2194 peter_e                  7118            1145 :     if (colDef->identity &&
 2194 peter_e                  7119 GIC          15 :         recurse &&
  711 alvherre                 7120              15 :         find_inheritance_children(myrelid, NoLock) != NIL)
 2194 peter_e                  7121               3 :         ereport(ERROR,
                               7122                 :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7123                 :                  errmsg("cannot recursively add identity column to table that has child tables")));
                               7124                 : 
 1180 tgl                      7125 GBC        1142 :     pgclass = table_open(RelationRelationId, RowExclusiveLock);
                               7126                 : 
 1180 tgl                      7127 GIC        1142 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
                               7128            1142 :     if (!HeapTupleIsValid(reltup))
 1180 tgl                      7129 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
 1180 tgl                      7130 GIC        1142 :     relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
 7664 tgl                      7131 EUB             : 
                               7132                 :     /* Determine the new attribute's number */
 1601 andres                   7133 GIC        1142 :     newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
                               7134            1142 :     if (newattnum > MaxHeapAttributeNumber)
 1601 andres                   7135 UBC           0 :         ereport(ERROR,
                               7136                 :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
                               7137                 :                  errmsg("tables can have at most %d columns",
 1601 andres                   7138 ECB             :                         MaxHeapAttributeNumber)));
                               7139                 : 
 4414 tgl                      7140 CBC        1142 :     typeTuple = typenameType(NULL, colDef->typeName, &typmod);
 6913                          7141            1142 :     tform = (Form_pg_type) GETSTRUCT(typeTuple);
 1601 andres                   7142 GIC        1142 :     typeOid = tform->oid;
                               7143                 : 
  147 peter                    7144 GNC        1142 :     aclresult = object_aclcheck(TypeRelationId, typeOid, GetUserId(), ACL_USAGE);
 4128 peter_e                  7145 GIC        1142 :     if (aclresult != ACLCHECK_OK)
 3950                          7146               6 :         aclcheck_error_type(aclresult, typeOid);
                               7147                 : 
 4414 tgl                      7148            1136 :     collOid = GetColumnDefCollation(NULL, colDef, typeOid);
                               7149                 : 
                               7150                 :     /* make sure datatype is legal for a column */
 4395                          7151            1136 :     CheckAttributeType(colDef->colname, typeOid, collOid,
 4395 tgl                      7152 CBC        1136 :                        list_make1_oid(rel->rd_rel->reltype),
                               7153                 :                        0);
                               7154                 : 
                               7155                 :     /*
                               7156                 :      * Construct new attribute's pg_attribute entry.  (Variable-length fields
                               7157                 :      * are handled by InsertPgAttributeTuples().)
  499 peter                    7158 ECB             :      */
 5259 alvherre                 7159 GIC        1121 :     attribute.attrelid = myrelid;
 5259 alvherre                 7160 CBC        1121 :     namestrcpy(&(attribute.attname), colDef->colname);
 5259 alvherre                 7161 GIC        1121 :     attribute.atttypid = typeOid;
 5170 tgl                      7162 CBC        1121 :     attribute.attstattarget = (newattnum > 0) ? -1 : 0;
 5259 alvherre                 7163 GIC        1121 :     attribute.attlen = tform->typlen;
 5228 tgl                      7164            1121 :     attribute.attnum = newattnum;
   12 peter                    7165 GNC        1121 :     if (list_length(colDef->typeName->arrayBounds) > PG_INT16_MAX)
   12 peter                    7166 UNC           0 :         ereport(ERROR,
                               7167                 :                 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               7168                 :                 errmsg("too many array dimensions"));
 5015 peter_e                  7169 GIC        1121 :     attribute.attndims = list_length(colDef->typeName->arrayBounds);
  686 tgl                      7170            1121 :     attribute.atttypmod = typmod;
  686 tgl                      7171 CBC        1121 :     attribute.attbyval = tform->typbyval;
 5259 alvherre                 7172 GIC        1121 :     attribute.attalign = tform->typalign;
  270 peter                    7173 GNC        1121 :     if (colDef->storage_name)
  270 peter                    7174 UNC           0 :         attribute.attstorage = GetAttributeStorage(typeOid, colDef->storage_name);
                               7175                 :     else
  270 peter                    7176 GNC        1121 :         attribute.attstorage = tform->typstorage;
  682 tgl                      7177 GIC        1121 :     attribute.attcompression = GetAttributeCompression(typeOid,
  682 tgl                      7178 ECB             :                                                        colDef->compression);
 5259 alvherre                 7179 GIC        1121 :     attribute.attnotnull = colDef->is_not_null;
 5259 alvherre                 7180 CBC        1121 :     attribute.atthasdef = false;
 1838 andrew                   7181            1121 :     attribute.atthasmissing = false;
 2194 peter_e                  7182 GIC        1121 :     attribute.attidentity = colDef->identity;
 1471 peter                    7183            1121 :     attribute.attgenerated = colDef->generated;
 5259 alvherre                 7184            1121 :     attribute.attisdropped = false;
                               7185            1121 :     attribute.attislocal = colDef->is_local;
                               7186            1121 :     attribute.attinhcount = colDef->inhcount;
 4443 peter_e                  7187 CBC        1121 :     attribute.attcollation = collOid;
                               7188                 : 
 6913 tgl                      7189 GIC        1121 :     ReleaseSysCache(typeTuple);
 6913 tgl                      7190 ECB             : 
  982 michael                  7191 CBC        1121 :     tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
                               7192                 : 
                               7193            1121 :     InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
                               7194                 : 
 1539 andres                   7195 GIC        1121 :     table_close(attrdesc, RowExclusiveLock);
                               7196                 : 
                               7197                 :     /*
                               7198                 :      * Update pg_class tuple as appropriate
                               7199                 :      */
 1601                          7200            1121 :     ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
                               7201                 : 
 2259 alvherre                 7202            1121 :     CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
                               7203                 : 
 6913 tgl                      7204            1121 :     heap_freetuple(reltup);
                               7205                 : 
                               7206                 :     /* Post creation hook for new attribute */
 3686 rhaas                    7207            1121 :     InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
 4518 rhaas                    7208 ECB             : 
 1539 andres                   7209 GIC        1121 :     table_close(pgclass, RowExclusiveLock);
 6913 tgl                      7210 ECB             : 
                               7211                 :     /* Make the attribute's catalog entry visible */
 6913 tgl                      7212 GIC        1121 :     CommandCounterIncrement();
 7653 tgl                      7213 ECB             : 
                               7214                 :     /*
                               7215                 :      * Store the DEFAULT, if any, in the catalogs
                               7216                 :      */
 6913 tgl                      7217 CBC        1121 :     if (colDef->raw_default)
 7664 tgl                      7218 ECB             :     {
 7653                          7219                 :         RawColumnDefault *rawEnt;
                               7220                 : 
 7653 tgl                      7221 GIC         334 :         rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
 5259 alvherre                 7222             334 :         rawEnt->attnum = attribute.attnum;
 6913 tgl                      7223             334 :         rawEnt->raw_default = copyObject(colDef->raw_default);
                               7224                 : 
                               7225                 :         /*
 1838 andrew                   7226 ECB             :          * Attempt to skip a complete table rewrite by storing the specified
                               7227                 :          * DEFAULT value outside of the heap.  This may be disabled inside
                               7228                 :          * AddRelationNewConstraints if the optimization cannot be applied.
                               7229                 :          */
 1471 peter                    7230 GIC         334 :         rawEnt->missingMode = (!colDef->generated);
                               7231                 : 
                               7232             334 :         rawEnt->generated = colDef->generated;
 1838 andrew                   7233 ECB             : 
                               7234                 :         /*
                               7235                 :          * This function is intended for CREATE TABLE, so it processes a
                               7236                 :          * _list_ of defaults, but we just do one.
                               7237                 :          */
 3675 rhaas                    7238 GIC         334 :         AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
                               7239                 :                                   false, true, false, NULL);
                               7240                 : 
                               7241                 :         /* Make the additional catalog changes visible */
 6913 tgl                      7242             328 :         CommandCounterIncrement();
                               7243                 : 
                               7244                 :         /*
                               7245                 :          * Did the request for a missing value work? If not we'll have to do a
                               7246                 :          * rewrite
                               7247                 :          */
 1838 andrew                   7248             328 :         if (!rawEnt->missingMode)
                               7249              48 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
                               7250                 :     }
 7664 tgl                      7251 ECB             : 
                               7252                 :     /*
                               7253                 :      * Tell Phase 3 to fill in the default expression, if there is one.
                               7254                 :      *
 6347 bruce                    7255                 :      * If there is no default, Phase 3 doesn't have to do anything, because
                               7256                 :      * that effectively means that the default is NULL.  The heap tuple access
                               7257                 :      * routines always check for attnum > # of attributes in tuple, and return
                               7258                 :      * NULL if so, so without any modification of the tuple data we will get
                               7259                 :      * the effect of NULL values in the new column.
 6913 tgl                      7260                 :      *
 6385 bruce                    7261                 :      * An exception occurs when the new column is of a domain type: the domain
                               7262                 :      * might have a NOT NULL constraint, or a check constraint that indirectly
                               7263                 :      * rejects nulls.  If there are any domain constraints then we construct
                               7264                 :      * an explicit NULL default value that will be passed through
                               7265                 :      * CoerceToDomain processing.  (This is a tad inefficient, since it causes
                               7266                 :      * rewriting the table which we really don't have to do, but the present
                               7267                 :      * design of domain processing doesn't offer any simple way of checking
                               7268                 :      * the constraints more directly.)
                               7269                 :      *
                               7270                 :      * Note: we use build_column_default, and not just the cooked default
                               7271                 :      * returned by AddRelationNewConstraints, so that the right thing happens
                               7272                 :      * when a datatype's default applies.
                               7273                 :      *
                               7274                 :      * Note: it might seem that this should happen at the end of Phase 2, so
 1174 tgl                      7275                 :      * that the effects of subsequent subcommands can be taken into account.
                               7276                 :      * It's intentional that we do it now, though.  The new column should be
                               7277                 :      * filled according to what is said in the ADD COLUMN subcommand, so that
                               7278                 :      * the effects are the same as if this subcommand had been run by itself
                               7279                 :      * and the later subcommands had been issued in new ALTER TABLE commands.
                               7280                 :      *
                               7281                 :      * We can skip this entirely for relations without storage, since Phase 3
                               7282                 :      * is certainly not going to touch them.  System attributes don't have
                               7283                 :      * interesting defaults, either.
                               7284                 :      */
 1174 tgl                      7285 GIC        1115 :     if (RELKIND_HAS_STORAGE(relkind) && attribute.attnum > 0)
                               7286                 :     {
                               7287                 :         /*
                               7288                 :          * For an identity column, we can't use build_column_default(),
                               7289                 :          * because the sequence ownership isn't set yet.  So do it manually.
                               7290                 :          */
 1892 peter_e                  7291             945 :         if (colDef->identity)
                               7292                 :         {
                               7293              12 :             NextValueExpr *nve = makeNode(NextValueExpr);
                               7294                 : 
                               7295              12 :             nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
                               7296              12 :             nve->typeId = typeOid;
                               7297                 : 
                               7298              12 :             defval = (Expr *) nve;
                               7299                 : 
                               7300                 :             /* must do a rewrite for identity columns */
 1838 andrew                   7301 CBC          12 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
                               7302                 :         }
                               7303                 :         else
 1892 peter_e                  7304             933 :             defval = (Expr *) build_column_default(rel, attribute.attnum);
 6649 tgl                      7305 ECB             : 
 2961 tgl                      7306 GIC         945 :         if (!defval && DomainHasConstraints(typeOid))
 5237 bruce                    7307 ECB             :         {
                               7308                 :             Oid         baseTypeId;
                               7309                 :             int32       baseTypeMod;
                               7310                 :             Oid         baseTypeColl;
                               7311                 : 
 5237 bruce                    7312 CBC           3 :             baseTypeMod = typmod;
 5237 bruce                    7313 GIC           3 :             baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
 4398 tgl                      7314               3 :             baseTypeColl = get_typcollation(baseTypeId);
                               7315               3 :             defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
 5237 bruce                    7316               3 :             defval = (Expr *) coerce_to_target_type(NULL,
                               7317                 :                                                     (Node *) defval,
                               7318                 :                                                     baseTypeId,
                               7319                 :                                                     typeOid,
 5237 bruce                    7320 ECB             :                                                     typmod,
                               7321                 :                                                     COERCION_ASSIGNMENT,
                               7322                 :                                                     COERCE_IMPLICIT_CAST,
                               7323                 :                                                     -1);
 5050 bruce                    7324 GIC           3 :             if (defval == NULL) /* should not happen */
 5237 bruce                    7325 LBC           0 :                 elog(ERROR, "failed to coerce base type to domain");
 5237 bruce                    7326 ECB             :         }
                               7327                 : 
 5237 bruce                    7328 CBC         945 :         if (defval)
                               7329                 :         {
                               7330                 :             NewColumnValue *newval;
                               7331                 : 
 5237 bruce                    7332 GIC         286 :             newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
                               7333             286 :             newval->attnum = attribute.attnum;
 4310 rhaas                    7334 CBC         286 :             newval->expr = expression_planner(defval);
 1187 tgl                      7335             286 :             newval->is_generated = (colDef->generated != '\0');
 7664 tgl                      7336 ECB             : 
 5237 bruce                    7337 GBC         286 :             tab->newvals = lappend(tab->newvals, newval);
                               7338                 :         }
                               7339                 : 
 1838 andrew                   7340 GIC         945 :         if (DomainHasConstraints(typeOid))
 1838 andrew                   7341 CBC           6 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
 1838 andrew                   7342 ECB             : 
 1838 andrew                   7343 GBC         945 :         if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
                               7344                 :         {
                               7345                 :             /*
                               7346                 :              * If the new column is NOT NULL, and there is no missing value,
                               7347                 :              * tell Phase 3 it needs to check for NULLs.
                               7348                 :              */
 1488 rhaas                    7349 GIC         725 :             tab->verify_new_notnull |= colDef->is_not_null;
                               7350                 :         }
                               7351                 :     }
 5463 tgl                      7352 ECB             : 
 7653                          7353                 :     /*
 6877 tgl                      7354 EUB             :      * Add needed dependency entries for the new column.
                               7355                 :      */
 4370 tgl                      7356 GIC        1115 :     add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
 4370 tgl                      7357 CBC        1115 :     add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
                               7358                 : 
 4389 rhaas                    7359 ECB             :     /*
                               7360                 :      * Propagate to children as appropriate.  Unlike most other ALTER
                               7361                 :      * routines, we have to do this one level of recursion at a time; we can't
                               7362                 :      * use find_all_inheritors to do it in one pass.
                               7363                 :      */
                               7364                 :     children =
  711 alvherre                 7365 GIC        1115 :         find_inheritance_children(RelationGetRelid(rel), lockmode);
 4389 rhaas                    7366 ECB             : 
                               7367                 :     /*
                               7368                 :      * If we are told not to recurse, there had better not be any child
                               7369                 :      * tables; else the addition would put them out of step.
                               7370                 :      */
 4389 rhaas                    7371 GIC        1115 :     if (children && !recurse)
 4389 rhaas                    7372 CBC           6 :         ereport(ERROR,
                               7373                 :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 4389 rhaas                    7374 ECB             :                  errmsg("column must be added to child tables too")));
                               7375                 : 
                               7376                 :     /* Children should see column as singly inherited */
 4389 rhaas                    7377 GIC        1109 :     if (!recursing)
                               7378                 :     {
 1180 tgl                      7379             830 :         childcmd = copyObject(*cmd);
                               7380             830 :         colDef = castNode(ColumnDef, childcmd->def);
 4389 rhaas                    7381             830 :         colDef->inhcount = 1;
                               7382             830 :         colDef->is_local = false;
                               7383                 :     }
                               7384                 :     else
 1180 tgl                      7385             279 :         childcmd = *cmd;        /* no need to copy again */
                               7386                 : 
 4389 rhaas                    7387            1400 :     foreach(child, children)
                               7388                 :     {
 4389 rhaas                    7389 CBC         291 :         Oid         childrelid = lfirst_oid(child);
                               7390                 :         Relation    childrel;
 4389 rhaas                    7391 ECB             :         AlteredTableInfo *childtab;
                               7392                 : 
                               7393                 :         /* find_inheritance_children already got lock */
 1539 andres                   7394 CBC         291 :         childrel = table_open(childrelid, NoLock);
 4389 rhaas                    7395 GIC         291 :         CheckTableNotInUse(childrel, "ALTER TABLE");
                               7396                 : 
                               7397                 :         /* Find or create work queue entry for this table */
                               7398             291 :         childtab = ATGetQueueEntry(wqueue, childrel);
                               7399                 : 
                               7400                 :         /* Recurse to child; return value is ignored */
 4389 rhaas                    7401 CBC         291 :         ATExecAddColumn(wqueue, childtab, childrel,
 1180 tgl                      7402 ECB             :                         &childcmd, recurse, true,
                               7403                 :                         lockmode, cur_pass, context);
 4389 rhaas                    7404                 : 
 1539 andres                   7405 GIC         291 :         table_close(childrel, NoLock);
                               7406                 :     }
                               7407                 : 
 2937 alvherre                 7408 CBC        1109 :     ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
 2937 alvherre                 7409 GIC        1109 :     return address;
 6913 tgl                      7410 ECB             : }
 7664                          7411                 : 
 4091 rhaas                    7412 EUB             : /*
 4091 rhaas                    7413 ECB             :  * If a new or renamed column will collide with the name of an existing
                               7414                 :  * column and if_not_exists is false then error out, else do nothing.
                               7415                 :  */
 2811 andrew                   7416                 : static bool
 2811 andrew                   7417 CBC        1403 : check_for_column_name_collision(Relation rel, const char *colname,
 2811 andrew                   7418 EUB             :                                 bool if_not_exists)
                               7419                 : {
                               7420                 :     HeapTuple   attTuple;
                               7421                 :     int         attnum;
                               7422                 : 
 4091 rhaas                    7423 ECB             :     /*
                               7424                 :      * this test is deliberately not attisdropped-aware, since if one tries to
                               7425                 :      * add a column matching a dropped column name, it's gonna fail anyway.
                               7426                 :      */
 4091 rhaas                    7427 CBC        1403 :     attTuple = SearchSysCache2(ATTNAME,
 4091 rhaas                    7428 ECB             :                                ObjectIdGetDatum(RelationGetRelid(rel)),
                               7429                 :                                PointerGetDatum(colname));
 4091 rhaas                    7430 GIC        1403 :     if (!HeapTupleIsValid(attTuple))
 2811 andrew                   7431 CBC        1355 :         return true;
                               7432                 : 
 3955 bruce                    7433 GIC          48 :     attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
 4091 rhaas                    7434 CBC          48 :     ReleaseSysCache(attTuple);
 4091 rhaas                    7435 ECB             : 
                               7436                 :     /*
                               7437                 :      * We throw a different error message for conflicts with system column
                               7438                 :      * names, since they are normally not shown and the user might otherwise
                               7439                 :      * be confused about the reason for the conflict.
                               7440                 :      */
 3955 bruce                    7441 GIC          48 :     if (attnum <= 0)
 3955 bruce                    7442 CBC           6 :         ereport(ERROR,
 3955 bruce                    7443 ECB             :                 (errcode(ERRCODE_DUPLICATE_COLUMN),
 2118 tgl                      7444                 :                  errmsg("column name \"%s\" conflicts with a system column name",
                               7445                 :                         colname)));
 3955 bruce                    7446                 :     else
 2811 andrew                   7447                 :     {
 2811 andrew                   7448 CBC          42 :         if (if_not_exists)
 2811 andrew                   7449 EUB             :         {
 2811 andrew                   7450 GIC          27 :             ereport(NOTICE,
                               7451                 :                     (errcode(ERRCODE_DUPLICATE_COLUMN),
 2811 andrew                   7452 ECB             :                      errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
                               7453                 :                             colname, RelationGetRelationName(rel))));
 2811 andrew                   7454 CBC          27 :             return false;
 2811 andrew                   7455 ECB             :         }
                               7456                 : 
 3955 bruce                    7457 GBC          15 :         ereport(ERROR,
                               7458                 :                 (errcode(ERRCODE_DUPLICATE_COLUMN),
 3955 bruce                    7459 ECB             :                  errmsg("column \"%s\" of relation \"%s\" already exists",
                               7460                 :                         colname, RelationGetRelationName(rel))));
                               7461                 :     }
 2811 andrew                   7462                 : 
                               7463                 :     return true;
 4091 rhaas                    7464                 : }
                               7465                 : 
 6913 tgl                      7466                 : /*
                               7467                 :  * Install a column's dependency on its datatype.
                               7468                 :  */
                               7469                 : static void
 4370 tgl                      7470 CBC        1560 : add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
                               7471                 : {
 6913 tgl                      7472 ECB             :     ObjectAddress myself,
                               7473                 :                 referenced;
                               7474                 : 
 6569 tgl                      7475 GIC        1560 :     myself.classId = RelationRelationId;
 6913 tgl                      7476 CBC        1560 :     myself.objectId = relid;
 6913 tgl                      7477 GIC        1560 :     myself.objectSubId = attnum;
 6569 tgl                      7478 CBC        1560 :     referenced.classId = TypeRelationId;
 6913 tgl                      7479 GIC        1560 :     referenced.objectId = typid;
                               7480            1560 :     referenced.objectSubId = 0;
                               7481            1560 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 4370                          7482            1560 : }
 4370 tgl                      7483 ECB             : 
                               7484                 : /*
                               7485                 :  * Install a column's dependency on its collation.
                               7486                 :  */
                               7487                 : static void
 4370 tgl                      7488 GIC        1560 : add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
                               7489                 : {
 4370 tgl                      7490 ECB             :     ObjectAddress myself,
                               7491                 :                 referenced;
 4439 peter_e                  7492                 : 
                               7493                 :     /* We know the default collation is pinned, so don't bother recording it */
 4370 tgl                      7494 GIC        1560 :     if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
 4439 peter_e                  7495 ECB             :     {
 4370 tgl                      7496 GIC           9 :         myself.classId = RelationRelationId;
                               7497               9 :         myself.objectId = relid;
                               7498               9 :         myself.objectSubId = attnum;
 4439 peter_e                  7499               9 :         referenced.classId = CollationRelationId;
 4439 peter_e                  7500 CBC           9 :         referenced.objectId = collid;
 4439 peter_e                  7501 GIC           9 :         referenced.objectSubId = 0;
                               7502               9 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
                               7503                 :     }
 6913 tgl                      7504 CBC        1560 : }
 6913 tgl                      7505 ECB             : 
                               7506                 : /*
                               7507                 :  * ALTER TABLE ALTER COLUMN DROP NOT NULL
                               7508                 :  *
 1447                          7509                 :  * Return the address of the modified column.  If the column was already
                               7510                 :  * nullable, InvalidObjectAddress is returned.
                               7511                 :  */
                               7512                 : static ObjectAddress
    2 alvherre                 7513 GNC         107 : ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
                               7514                 :                   LOCKMODE lockmode)
                               7515                 : {
                               7516                 :     HeapTuple   tuple;
                               7517                 :     HeapTuple   conTup;
                               7518                 :     Form_pg_attribute attTup;
                               7519                 :     AttrNumber  attnum;
                               7520                 :     Relation    attr_rel;
                               7521                 :     ObjectAddress address;
                               7522                 : 
                               7523                 :     /*
                               7524                 :      * lookup the attribute
                               7525                 :      */
 1539 andres                   7526 GIC         107 :     attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
                               7527                 : 
 6913 tgl                      7528             107 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               7529             107 :     if (!HeapTupleIsValid(tuple))
                               7530               9 :         ereport(ERROR,
                               7531                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               7532                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               7533                 :                         colName, RelationGetRelationName(rel))));
 1629 peter_e                  7534              98 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               7535              98 :     attnum = attTup->attnum;
    2 alvherre                 7536 GNC          98 :     ObjectAddressSubSet(address, RelationRelationId,
                               7537                 :                         RelationGetRelid(rel), attnum);
                               7538                 : 
                               7539                 :     /* If the column is already nullable there's nothing to do. */
                               7540              98 :     if (!attTup->attnotnull)
                               7541                 :     {
                               7542               3 :         table_close(attr_rel, RowExclusiveLock);
                               7543               3 :         return InvalidObjectAddress;
                               7544                 :     }
                               7545                 : 
                               7546                 :     /* Prevent them from altering a system attribute */
 6913 tgl                      7547 GIC          95 :     if (attnum <= 0)
 6913 tgl                      7548 UIC           0 :         ereport(ERROR,
                               7549                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               7550                 :                  errmsg("cannot alter system column \"%s\"",
                               7551                 :                         colName)));
                               7552                 : 
 1629 peter_e                  7553 GIC          95 :     if (attTup->attidentity)
 2194                          7554               3 :         ereport(ERROR,
 2194 peter_e                  7555 ECB             :                 (errcode(ERRCODE_SYNTAX_ERROR),
                               7556                 :                  errmsg("column \"%s\" of relation \"%s\" is an identity column",
                               7557                 :                         colName, RelationGetRelationName(rel))));
                               7558                 : 
                               7559                 :     /*
                               7560                 :      * It's not OK to remove a constraint only for the parent and leave it in
                               7561                 :      * the children, so disallow that.
                               7562                 :      */
    2 alvherre                 7563 GNC          92 :     if (!recurse)
                               7564                 :     {
                               7565               6 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    2 alvherre                 7566 ECB             :         {
                               7567                 :             PartitionDesc partdesc;
                               7568                 : 
    2 alvherre                 7569 GNC           6 :             partdesc = RelationGetPartitionDesc(rel, true);
                               7570                 : 
                               7571               6 :             if (partdesc->nparts > 0)
                               7572               3 :                 ereport(ERROR,
                               7573                 :                         errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7574                 :                         errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
                               7575                 :                         errhint("Do not specify the ONLY keyword."));
                               7576                 :         }
    2 alvherre                 7577 UNC           0 :         else if (rel->rd_rel->relhassubclass &&
                               7578               0 :                  find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
                               7579                 :         {
                               7580               0 :             ereport(ERROR,
                               7581                 :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7582                 :                     errmsg("NOT NULL constraint on column \"%s\" must be removed in child tables too",
                               7583                 :                            colName),
                               7584                 :                     errhint("Do not specify the ONLY keyword."));
                               7585                 :         }
 7664 tgl                      7586 ECB             :     }
                               7587                 : 
                               7588                 :     /*
                               7589                 :      * If rel is partition, shouldn't drop NOT NULL if parent has the same.
                               7590                 :      */
 2314 rhaas                    7591 GIC          89 :     if (rel->rd_rel->relispartition)
                               7592                 :     {
    2 alvherre                 7593 GNC           9 :         Oid         parentId = get_partition_parent(RelationGetRelid(rel), false);
                               7594               9 :         Relation    parent = table_open(parentId, AccessShareLock);
                               7595               9 :         TupleDesc   tupDesc = RelationGetDescr(parent);
                               7596                 :         AttrNumber  parent_attnum;
                               7597                 : 
 2314 rhaas                    7598 GIC           9 :         parent_attnum = get_attnum(parentId, colName);
 2058 andres                   7599               9 :         if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
 2314 rhaas                    7600               9 :             ereport(ERROR,
 2314 rhaas                    7601 ECB             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 2118 tgl                      7602                 :                      errmsg("column \"%s\" is marked NOT NULL in parent table",
                               7603                 :                             colName)));
 1539 andres                   7604 UIC           0 :         table_close(parent, AccessShareLock);
                               7605                 :     }
                               7606                 : 
                               7607                 :     /*
                               7608                 :      * Find the constraint that makes this column NOT NULL.
                               7609                 :      */
    2 alvherre                 7610 GNC          80 :     conTup = findNotNullConstraint(rel, colName);
                               7611              80 :     if (conTup == NULL)
                               7612                 :     {
                               7613                 :         Bitmapset  *pkcols;
                               7614                 : 
                               7615                 :         /*
                               7616                 :          * There's no NOT NULL constraint, so throw an error.  If the column
                               7617                 :          * is in a primary key, we can throw a specific error.  Otherwise,
                               7618                 :          * this is unexpected.
                               7619                 :          */
                               7620               3 :         pkcols = RelationGetIndexAttrBitmap(rel, INDEX_ATTR_BITMAP_PRIMARY_KEY);
                               7621               3 :         if (bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
                               7622                 :                           pkcols))
                               7623               3 :             ereport(ERROR,
                               7624                 :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7625                 :                     errmsg("column \"%s\" is in a primary key", colName));
                               7626                 : 
                               7627                 :         /* this shouldn't happen */
    2 alvherre                 7628 UNC           0 :         elog(ERROR, "no NOT NULL constraint found to drop");
                               7629                 :     }
                               7630                 : 
    2 alvherre                 7631 GNC          77 :     dropconstraint_internal(rel, conTup, DROP_RESTRICT, recurse, false,
                               7632                 :                             false, NULL, lockmode);
                               7633                 : 
                               7634              62 :     heap_freetuple(conTup);
 3675 rhaas                    7635 ECB             : 
 1539 andres                   7636 CBC          62 :     table_close(attr_rel, RowExclusiveLock);
 2937 alvherre                 7637 ECB             : 
 2937 alvherre                 7638 CBC          62 :     return address;
                               7639                 : }
                               7640                 : 
 6913 tgl                      7641 ECB             : /*
                               7642                 :  * Helper to set pg_attribute.attnotnull if it isn't set, and to tell phase 3
                               7643                 :  * to verify it; recurses to apply the same to children.
                               7644                 :  *
                               7645                 :  * When called to alter an existing table, 'wqueue' must be given so that we can
                               7646                 :  * queue a check that existing tuples pass the constraint.  When called from
                               7647                 :  * table creation, 'wqueue' should be passed as NULL.
                               7648                 :  */
 2314 rhaas                    7649                 : static void
    2 alvherre                 7650 GNC       32180 : set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse,
                               7651                 :                LOCKMODE lockmode)
                               7652                 : {
                               7653                 :     HeapTuple   tuple;
                               7654                 :     Form_pg_attribute attForm;
                               7655                 :     List       *children;
                               7656                 :     ListCell   *lc;
                               7657                 : 
                               7658           32180 :     tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), attnum);
                               7659           32180 :     if (!HeapTupleIsValid(tuple))
    2 alvherre                 7660 UNC           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
                               7661                 :              attnum, RelationGetRelid(rel));
    2 alvherre                 7662 GNC       32180 :     attForm = (Form_pg_attribute) GETSTRUCT(tuple);
                               7663           32180 :     if (!attForm->attnotnull)
                               7664                 :     {
                               7665                 :         Relation    attr_rel;
                               7666                 : 
                               7667             556 :         attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
                               7668                 : 
                               7669             556 :         attForm->attnotnull = true;
                               7670             556 :         CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
                               7671                 : 
                               7672             556 :         table_close(attr_rel, RowExclusiveLock);
                               7673                 : 
                               7674                 :         /*
                               7675                 :          * And set up for existing values to be checked, unless another constraint
                               7676                 :          * already proves this.
                               7677                 :          */
                               7678             556 :         if (wqueue && !NotNullImpliedByRelConstraints(rel, attForm))
                               7679                 :         {
                               7680                 :             AlteredTableInfo *tab;
                               7681                 : 
                               7682             528 :             tab = ATGetQueueEntry(wqueue, rel);
                               7683             528 :             tab->verify_new_notnull = true;
                               7684                 :         }
                               7685                 :     }
                               7686                 : 
                               7687                 :     /* if no recursion is desired, we're done */
                               7688           32180 :     if (!recurse)
    2 alvherre                 7689 GIC       31839 :         return;
                               7690                 : 
    2 alvherre                 7691 GNC         341 :     children = find_inheritance_children(RelationGetRelid(rel), lockmode);
                               7692             386 :     foreach(lc, children)
 2175 sfrost                   7693 ECB             :     {
    2 alvherre                 7694 GNC          45 :         Oid         childrelid = lfirst_oid(lc);
                               7695                 :         Relation    childrel;
                               7696                 :         AttrNumber  childattno;
                               7697                 : 
                               7698                 :         /* find_inheritance_children already got lock */
                               7699              45 :         childrel = table_open(childrelid, NoLock);
                               7700              45 :         CheckTableNotInUse(childrel, "ALTER TABLE");
                               7701                 : 
                               7702              45 :         childattno = get_attnum(RelationGetRelid(childrel),
                               7703              45 :                                 get_attname(RelationGetRelid(rel), attnum,
                               7704                 :                                             false));
                               7705              45 :         set_attnotnull(wqueue, childrel, childattno,
                               7706                 :                        recurse, lockmode);
                               7707              45 :         table_close(childrel, NoLock);
 2175 sfrost                   7708 ECB             :     }
                               7709                 : }
                               7710                 : 
 1877 peter_e                  7711                 : /*
                               7712                 :  * ALTER TABLE ALTER COLUMN SET NOT NULL
                               7713                 :  *
                               7714                 :  * Add a NOT NULL constraint to a single table and its children.  Returns
                               7715                 :  * the address of the constraint added to the parent relation, if one gets
                               7716                 :  * added, or InvalidObjectAddress otherwise.
                               7717                 :  *
                               7718                 :  * We must recurse to child tables during execution, rather than using
                               7719                 :  * ALTER TABLE's normal prep-time recursion.
                               7720                 :  */
                               7721                 : static ObjectAddress
    2 alvherre                 7722 GNC         221 : ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName,
                               7723                 :                  bool recurse, bool recursing, List **readyRels,
                               7724                 :                  LOCKMODE lockmode)
                               7725                 : {
                               7726                 :     HeapTuple   tuple;
                               7727                 :     Relation    constr_rel;
                               7728                 :     ScanKeyData skey;
                               7729                 :     SysScanDesc conscan;
                               7730                 :     AttrNumber  attnum;
                               7731                 :     ObjectAddress address;
                               7732                 :     Constraint *constraint;
                               7733                 :     CookedConstraint *ccon;
                               7734                 :     List       *cooked;
                               7735             221 :     List       *ready = NIL;
                               7736                 : 
                               7737                 :     /*
                               7738                 :      * In cases of multiple inheritance, we might visit the same child more
                               7739                 :      * than once.  In the topmost call, set up a list that we fill with all
                               7740                 :      * visited relations, to skip those.
                               7741                 :      */
                               7742             221 :     if (readyRels == NULL)
                               7743             159 :         readyRels = &ready;
                               7744             221 :     if (list_member_oid(*readyRels, RelationGetRelid(rel)))
                               7745               3 :         return InvalidObjectAddress;
                               7746             218 :     *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
                               7747                 : 
                               7748                 :     /* At top level, permission check was done in ATPrepCmd, else do it */
                               7749             218 :     if (recursing)
                               7750                 :     {
                               7751              59 :         ATSimplePermissions(AT_AddConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               7752              59 :         Assert(conName != NULL);
                               7753                 :     }
                               7754                 : 
                               7755             218 :     attnum = get_attnum(RelationGetRelid(rel), colName);
                               7756             218 :     if (attnum == InvalidAttrNumber)
 7203 tgl                      7757 CBC           9 :         ereport(ERROR,
 7203 tgl                      7758 ECB             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
 6913                          7759                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               7760                 :                         colName, RelationGetRelationName(rel))));
 7653                          7761                 : 
 6913                          7762                 :     /* Prevent them from altering a system attribute */
 6913 tgl                      7763 GIC         209 :     if (attnum <= 0)
 7203 tgl                      7764 UIC           0 :         ereport(ERROR,
                               7765                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               7766                 :                  errmsg("cannot alter system column \"%s\"",
                               7767                 :                         colName)));
 7522 bruce                    7768 ECB             : 
                               7769                 :     /* See if there's already a constraint */
    2 alvherre                 7770 GNC         209 :     constr_rel = table_open(ConstraintRelationId, RowExclusiveLock);
                               7771             209 :     ScanKeyInit(&skey,
                               7772                 :                 Anum_pg_constraint_conrelid,
                               7773                 :                 BTEqualStrategyNumber, F_OIDEQ,
                               7774                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                               7775             209 :     conscan = systable_beginscan(constr_rel, ConstraintRelidTypidNameIndexId, true,
                               7776                 :                                  NULL, 1, &skey);
                               7777                 : 
                               7778             401 :     while (HeapTupleIsValid(tuple = systable_getnext(conscan)))
                               7779                 :     {
                               7780             202 :         Form_pg_constraint conForm = (Form_pg_constraint) GETSTRUCT(tuple);
                               7781             202 :         bool        changed = false;
                               7782                 :         HeapTuple   copytup;
                               7783                 : 
                               7784             202 :         if (conForm->contype != CONSTRAINT_NOTNULL)
                               7785              97 :             continue;
                               7786                 : 
                               7787             105 :         if (extractNotNullColumn(tuple) != attnum)
                               7788              95 :             continue;
                               7789                 : 
                               7790              10 :         copytup = heap_copytuple(tuple);
                               7791              10 :         conForm = (Form_pg_constraint) GETSTRUCT(copytup);
 7653 tgl                      7792 ECB             : 
 1488 rhaas                    7793                 :         /*
                               7794                 :          * If we find an appropriate constraint, we're almost done, but just
                               7795                 :          * need to change some properties on it: if we're recursing, increment
                               7796                 :          * coninhcount; if not, set conislocal if not already set.
                               7797                 :          */
    2 alvherre                 7798 GNC          10 :         if (recursing)
                               7799                 :         {
                               7800               3 :             conForm->coninhcount++;
                               7801               3 :             changed = true;
                               7802                 :         }
                               7803               7 :         else if (!conForm->conislocal)
                               7804                 :         {
    2 alvherre                 7805 UNC           0 :             conForm->conislocal = true;
                               7806               0 :             changed = true;
                               7807                 :         }
                               7808                 : 
    2 alvherre                 7809 GNC          10 :         if (changed)
                               7810                 :         {
                               7811               3 :             CatalogTupleUpdate(constr_rel, &copytup->t_self, copytup);
                               7812               3 :             ObjectAddressSet(address, ConstraintRelationId, conForm->oid);
                               7813                 :         }
                               7814                 : 
                               7815              10 :         systable_endscan(conscan);
                               7816              10 :         table_close(constr_rel, RowExclusiveLock);
                               7817                 : 
                               7818              10 :         if (changed)
                               7819               3 :             return address;
                               7820                 :         else
                               7821               7 :             return InvalidObjectAddress;
 6913 tgl                      7822 ECB             :     }
                               7823                 : 
    2 alvherre                 7824 GNC         199 :     systable_endscan(conscan);
                               7825             199 :     table_close(constr_rel, RowExclusiveLock);
                               7826                 : 
                               7827                 :     /*
                               7828                 :      * If we're asked not to recurse, and children exist, raise an error.
                               7829                 :      */
                               7830             208 :     if (!recurse &&
                               7831               9 :         find_inheritance_children(RelationGetRelid(rel),
                               7832                 :                                   NoLock) != NIL)
                               7833                 :     {
                               7834               6 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               7835               3 :             ereport(ERROR,
                               7836                 :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7837                 :                     errmsg("cannot add constraint to only the partitioned table when partitions exist"),
                               7838                 :                     errhint("Do not specify the ONLY keyword."));
                               7839                 :         else
                               7840               3 :             ereport(ERROR,
                               7841                 :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7842                 :                     errmsg("cannot add constraint only to table with inheritance children"),
                               7843                 :                     errhint("Do not specify the ONLY keyword."));
                               7844                 :     }
                               7845                 : 
                               7846                 :     /*
                               7847                 :      * No constraint exists; we must add one.  First determine a name to use,
                               7848                 :      * if we haven't already.
                               7849                 :      */
                               7850             193 :     if (!recursing)
                               7851                 :     {
                               7852             137 :         Assert(conName == NULL);
                               7853             137 :         conName = ChooseConstraintName(RelationGetRelationName(rel),
                               7854                 :                                        colName, "not_null",
                               7855             137 :                                        RelationGetNamespace(rel),
                               7856                 :                                        NIL);
                               7857                 :     }
                               7858             193 :     constraint = makeNode(Constraint);
                               7859             193 :     constraint->contype = CONSTR_NOTNULL;
                               7860             193 :     constraint->conname = conName;
                               7861             193 :     constraint->deferrable = false;
                               7862             193 :     constraint->initdeferred = false;
                               7863             193 :     constraint->location = -1;
                               7864             193 :     constraint->colname = colName;
                               7865             193 :     constraint->skip_validation = false;
                               7866             193 :     constraint->initially_valid = true;
                               7867                 : 
                               7868                 :     /* and do it */
                               7869             193 :     cooked = AddRelationNewConstraints(rel, NIL, list_make1(constraint),
                               7870             193 :                                        false, !recursing, false, NULL);
                               7871             193 :     ccon = linitial(cooked);
                               7872             193 :     ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
                               7873                 : 
                               7874                 :     /*
                               7875                 :      * Mark pg_attribute.attnotnull for the column. Tell that function not to
                               7876                 :      * recurse, because we're going to do it here.
                               7877                 :      */
                               7878             193 :     set_attnotnull(wqueue, rel, attnum, false, lockmode);
                               7879                 : 
                               7880                 :     /*
                               7881                 :      * Recurse to propagate the constraint to children that don't have one.
                               7882                 :      */
                               7883             193 :     if (recurse)
                               7884                 :     {
                               7885                 :         List       *children;
                               7886                 :         ListCell   *lc;
                               7887                 : 
                               7888             190 :         children = find_inheritance_children(RelationGetRelid(rel),
                               7889                 :                                              lockmode);
                               7890                 : 
                               7891             252 :         foreach(lc, children)
                               7892                 :         {
                               7893                 :             Relation    childrel;
                               7894                 : 
                               7895              62 :             childrel = table_open(lfirst_oid(lc), NoLock);
                               7896                 : 
                               7897              62 :             ATExecSetNotNull(wqueue, childrel,
                               7898                 :                              conName, colName, recurse, true,
                               7899                 :                              readyRels, lockmode);
                               7900                 : 
                               7901              62 :             table_close(childrel, NoLock);
                               7902                 :         }
                               7903                 :     }
                               7904                 : 
 2937 alvherre                 7905 GIC         193 :     return address;
                               7906                 : }
                               7907                 : 
                               7908                 : /*
                               7909                 :  * ALTER TABLE ALTER COLUMN SET ATTNOTNULL
                               7910                 :  *
                               7911                 :  * This doesn't exist in the grammar; it's used when creating a
                               7912                 :  * primary key and the column is not already marked attnotnull.
                               7913                 :  */
                               7914                 : static void
    2 alvherre                 7915 GNC       28396 : ATExecSetAttNotNull(List **wqueue, Relation rel,
                               7916                 :                     const char *colName, LOCKMODE lockmode)
                               7917                 : {
                               7918                 :     AttrNumber  attnum;
                               7919                 : 
                               7920           28396 :     attnum = get_attnum(RelationGetRelid(rel), colName);
                               7921           28396 :     if (attnum == InvalidAttrNumber)    /* XXX should not happen .. elog? */
                               7922               9 :         ereport(ERROR,
                               7923                 :                 errcode(ERRCODE_UNDEFINED_COLUMN),
                               7924                 :                 errmsg("column \"%s\" of relation \"%s\" does not exist",
                               7925                 :                        colName, RelationGetRelationName(rel)));
                               7926                 : 
                               7927           28387 :     set_attnotnull(wqueue, rel, attnum, false, lockmode);
                               7928           28387 : }
                               7929                 : 
                               7930                 : /*
 1447 tgl                      7931 ECB             :  * ALTER TABLE ALTER COLUMN CHECK NOT NULL
                               7932                 :  *
                               7933                 :  * This doesn't exist in the grammar, but we generate AT_CheckNotNull
                               7934                 :  * commands against the partitions of a partitioned table if the user
                               7935                 :  * writes ALTER TABLE ONLY ... SET NOT NULL on the partitioned table,
                               7936                 :  * or tries to create a primary key on it (which internally creates
                               7937                 :  * AT_SetNotNull on the partitioned table).   Such a command doesn't
                               7938                 :  * allow us to actually modify any partition, but we want to let it
                               7939                 :  * go through if the partitions are already properly marked.
                               7940                 :  *
                               7941                 :  * In future, this might need to adjust the child table's state, likely
                               7942                 :  * by incrementing an inheritance count for the attnotnull constraint.
                               7943                 :  * For now we need only check for the presence of the flag.
                               7944                 :  */
                               7945                 : static void
 1447 tgl                      7946 UIC           0 : ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
 1447 tgl                      7947 ECB             :                    const char *colName, LOCKMODE lockmode)
                               7948                 : {
                               7949                 :     HeapTuple   tuple;
                               7950                 : 
 1447 tgl                      7951 UIC           0 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
 1447 tgl                      7952 ECB             : 
 1447 tgl                      7953 UBC           0 :     if (!HeapTupleIsValid(tuple))
 1447 tgl                      7954 UIC           0 :         ereport(ERROR,
                               7955                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               7956                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               7957                 :                         colName, RelationGetRelationName(rel))));
 1447 tgl                      7958 ECB             : 
 1447 tgl                      7959 LBC           0 :     if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
 1447 tgl                      7960 UIC           0 :         ereport(ERROR,
                               7961                 :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7962                 :                  errmsg("constraint must be added to child tables too"),
                               7963                 :                  errdetail("Column \"%s\" of relation \"%s\" is not already NOT NULL.",
                               7964                 :                            colName, RelationGetRelationName(rel)),
                               7965                 :                  errhint("Do not specify the ONLY keyword.")));
                               7966                 : 
                               7967               0 :     ReleaseSysCache(tuple);
 1447 tgl                      7968 LBC           0 : }
                               7969                 : 
 1488 rhaas                    7970 ECB             : /*
                               7971                 :  * NotNullImpliedByRelConstraints
                               7972                 :  *      Does rel's existing constraints imply NOT NULL for the given attribute?
                               7973                 :  */
                               7974                 : static bool
 1488 rhaas                    7975 GIC         553 : NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
 1488 rhaas                    7976 ECB             : {
 1488 rhaas                    7977 CBC         553 :     NullTest   *nnulltest = makeNode(NullTest);
                               7978                 : 
 1488 rhaas                    7979 GIC        1106 :     nnulltest->arg = (Expr *) makeVar(1,
                               7980             553 :                                       attr->attnum,
                               7981                 :                                       attr->atttypid,
 1488 rhaas                    7982 EUB             :                                       attr->atttypmod,
                               7983                 :                                       attr->attcollation,
                               7984                 :                                       0);
 1488 rhaas                    7985 GBC         553 :     nnulltest->nulltesttype = IS_NOT_NULL;
                               7986                 : 
                               7987                 :     /*
                               7988                 :      * argisrow = false is correct even for a composite column, because
                               7989                 :      * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
                               7990                 :      * case, just IS DISTINCT FROM NULL.
                               7991                 :      */
 1488 rhaas                    7992 GIC         553 :     nnulltest->argisrow = false;
                               7993             553 :     nnulltest->location = -1;
                               7994                 : 
                               7995             553 :     if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
 1488 rhaas                    7996 ECB             :     {
 1488 rhaas                    7997 GIC          25 :         ereport(DEBUG1,
  781 peter                    7998 ECB             :                 (errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
  697 tgl                      7999                 :                                  RelationGetRelationName(rel), NameStr(attr->attname))));
 1488 rhaas                    8000 CBC          25 :         return true;
                               8001                 :     }
                               8002                 : 
                               8003             528 :     return false;
 1488 rhaas                    8004 ECB             : }
                               8005                 : 
                               8006                 : /*
                               8007                 :  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
                               8008                 :  *
 2937 alvherre                 8009 EUB             :  * Return the address of the affected column.
                               8010                 :  */
                               8011                 : static ObjectAddress
 6913 tgl                      8012 GIC         266 : ATExecColumnDefault(Relation rel, const char *colName,
                               8013                 :                     Node *newDefault, LOCKMODE lockmode)
                               8014                 : {
 1629 peter_e                  8015 CBC         266 :     TupleDesc   tupdesc = RelationGetDescr(rel);
 6913 tgl                      8016 ECB             :     AttrNumber  attnum;
                               8017                 :     ObjectAddress address;
                               8018                 : 
                               8019                 :     /*
                               8020                 :      * get the number of the attribute
                               8021                 :      */
 6913 tgl                      8022 GIC         266 :     attnum = get_attnum(RelationGetRelid(rel), colName);
                               8023             266 :     if (attnum == InvalidAttrNumber)
                               8024              15 :         ereport(ERROR,
 6913 tgl                      8025 ECB             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
 6797 bruce                    8026                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8027                 :                         colName, RelationGetRelationName(rel))));
 7360                          8028                 : 
                               8029                 :     /* Prevent them from altering a system attribute */
 6913 tgl                      8030 GIC         251 :     if (attnum <= 0)
 7203 tgl                      8031 UIC           0 :         ereport(ERROR,
                               8032                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 6913 tgl                      8033 EUB             :                  errmsg("cannot alter system column \"%s\"",
                               8034                 :                         colName)));
                               8035                 : 
 1629 peter_e                  8036 CBC         251 :     if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
 2194 peter_e                  8037 GIC           3 :         ereport(ERROR,
                               8038                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
 2118 tgl                      8039 ECB             :                  errmsg("column \"%s\" of relation \"%s\" is an identity column",
                               8040                 :                         colName, RelationGetRelationName(rel)),
 2194 peter_e                  8041                 :                  newDefault ? 0 : errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.")));
                               8042                 : 
 1471 peter                    8043 CBC         248 :     if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
 1471 peter                    8044 GIC           3 :         ereport(ERROR,
                               8045                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
                               8046                 :                  errmsg("column \"%s\" of relation \"%s\" is a generated column",
                               8047                 :                         colName, RelationGetRelationName(rel)),
                               8048                 :                  newDefault || TupleDescAttr(tupdesc, attnum - 1)->attgenerated != ATTRIBUTE_GENERATED_STORED ? 0 :
                               8049                 :                  errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION instead.")));
                               8050                 : 
                               8051                 :     /*
                               8052                 :      * Remove any old default for the column.  We use RESTRICT here for
                               8053                 :      * safety, but at present we do not expect anything to depend on the
                               8054                 :      * default.
 4091 rhaas                    8055 ECB             :      *
                               8056                 :      * We treat removing the existing default as an internal operation when it
                               8057                 :      * is preparatory to adding a new default, but as a user-initiated
                               8058                 :      * operation when the user asked for a drop.
                               8059                 :      */
 4091 rhaas                    8060 GIC         245 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
                               8061                 :                       newDefault != NULL);
                               8062                 : 
 6913 tgl                      8063 CBC         245 :     if (newDefault)
 7360 bruce                    8064 ECB             :     {
 6913 tgl                      8065 EUB             :         /* SET DEFAULT */
                               8066                 :         RawColumnDefault *rawEnt;
 6913 tgl                      8067 ECB             : 
 6913 tgl                      8068 CBC         158 :         rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
 6913 tgl                      8069 GIC         158 :         rawEnt->attnum = attnum;
                               8070             158 :         rawEnt->raw_default = newDefault;
 1838 andrew                   8071             158 :         rawEnt->missingMode = false;
 1471 peter                    8072 CBC         158 :         rawEnt->generated = '\0';
                               8073                 : 
 6913 tgl                      8074 ECB             :         /*
                               8075                 :          * This function is intended for CREATE TABLE, so it processes a
                               8076                 :          * _list_ of defaults, but we just do one.
                               8077                 :          */
 3675 rhaas                    8078 GIC         158 :         AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
                               8079                 :                                   false, true, false, NULL);
                               8080                 :     }
                               8081                 : 
 2937 alvherre                 8082             242 :     ObjectAddressSubSet(address, RelationRelationId,
 2937 alvherre                 8083 ECB             :                         RelationGetRelid(rel), attnum);
 2937 alvherre                 8084 GIC         242 :     return address;
                               8085                 : }
                               8086                 : 
  961 tgl                      8087 ECB             : /*
                               8088                 :  * Add a pre-cooked default expression.
                               8089                 :  *
                               8090                 :  * Return the address of the affected column.
                               8091                 :  */
                               8092                 : static ObjectAddress
  961 tgl                      8093 CBC          28 : ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
  961 tgl                      8094 ECB             :                           Node *newDefault)
                               8095                 : {
                               8096                 :     ObjectAddress address;
                               8097                 : 
                               8098                 :     /* We assume no checking is required */
                               8099                 : 
                               8100                 :     /*
                               8101                 :      * Remove any old default for the column.  We use RESTRICT here for
                               8102                 :      * safety, but at present we do not expect anything to depend on the
                               8103                 :      * default.  (In ordinary cases, there could not be a default in place
                               8104                 :      * anyway, but it's possible when combining LIKE with inheritance.)
                               8105                 :      */
  961 tgl                      8106 GIC          28 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
  961 tgl                      8107 ECB             :                       true);
                               8108                 : 
  961 tgl                      8109 GIC          28 :     (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
  961 tgl                      8110 ECB             : 
  961 tgl                      8111 GIC          28 :     ObjectAddressSubSet(address, RelationRelationId,
  961 tgl                      8112 ECB             :                         RelationGetRelid(rel), attnum);
  961 tgl                      8113 GIC          28 :     return address;
                               8114                 : }
                               8115                 : 
                               8116                 : /*
                               8117                 :  * ALTER TABLE ALTER COLUMN ADD IDENTITY
                               8118                 :  *
                               8119                 :  * Return the address of the affected column.
                               8120                 :  */
                               8121                 : static ObjectAddress
 2194 peter_e                  8122              48 : ATExecAddIdentity(Relation rel, const char *colName,
                               8123                 :                   Node *def, LOCKMODE lockmode)
                               8124                 : {
                               8125                 :     Relation    attrelation;
                               8126                 :     HeapTuple   tuple;
 2194 peter_e                  8127 ECB             :     Form_pg_attribute attTup;
                               8128                 :     AttrNumber  attnum;
                               8129                 :     ObjectAddress address;
 2194 peter_e                  8130 GIC          48 :     ColumnDef  *cdef = castNode(ColumnDef, def);
                               8131                 : 
 1539 andres                   8132              48 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               8133                 : 
 2194 peter_e                  8134              48 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               8135              48 :     if (!HeapTupleIsValid(tuple))
 2194 peter_e                  8136 UIC           0 :         ereport(ERROR,
                               8137                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8138                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8139                 :                         colName, RelationGetRelationName(rel))));
 2194 peter_e                  8140 CBC          48 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
 2194 peter_e                  8141 GIC          48 :     attnum = attTup->attnum;
                               8142                 : 
                               8143                 :     /* Can't alter a system attribute */
                               8144              48 :     if (attnum <= 0)
 2194 peter_e                  8145 UIC           0 :         ereport(ERROR,
                               8146                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 2194 peter_e                  8147 ECB             :                  errmsg("cannot alter system column \"%s\"",
                               8148                 :                         colName)));
                               8149                 : 
                               8150                 :     /*
                               8151                 :      * Creating a column as identity implies NOT NULL, so adding the identity
                               8152                 :      * to an existing column that is not NOT NULL would create a state that
                               8153                 :      * cannot be reproduced without contortions.
                               8154                 :      */
 2194 peter_e                  8155 GIC          48 :     if (!attTup->attnotnull)
 2194 peter_e                  8156 CBC           3 :         ereport(ERROR,
 2194 peter_e                  8157 ECB             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8158                 :                  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
                               8159                 :                         colName, RelationGetRelationName(rel))));
                               8160                 : 
 2194 peter_e                  8161 CBC          45 :     if (attTup->attidentity)
                               8162               6 :         ereport(ERROR,
                               8163                 :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8164                 :                  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
                               8165                 :                         colName, RelationGetRelationName(rel))));
                               8166                 : 
 2194 peter_e                  8167 GIC          39 :     if (attTup->atthasdef)
 2194 peter_e                  8168 CBC           3 :         ereport(ERROR,
 2194 peter_e                  8169 EUB             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8170                 :                  errmsg("column \"%s\" of relation \"%s\" already has a default value",
                               8171                 :                         colName, RelationGetRelationName(rel))));
                               8172                 : 
 2194 peter_e                  8173 GIC          36 :     attTup->attidentity = cdef->identity;
                               8174              36 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
 2194 peter_e                  8175 ECB             : 
 2194 peter_e                  8176 CBC          36 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8177                 :                               RelationGetRelid(rel),
                               8178                 :                               attTup->attnum);
 2194 peter_e                  8179 GIC          36 :     ObjectAddressSubSet(address, RelationRelationId,
 2194 peter_e                  8180 ECB             :                         RelationGetRelid(rel), attnum);
 2194 peter_e                  8181 GIC          36 :     heap_freetuple(tuple);
                               8182                 : 
 1539 andres                   8183 CBC          36 :     table_close(attrelation, RowExclusiveLock);
                               8184                 : 
 2194 peter_e                  8185              36 :     return address;
 2194 peter_e                  8186 ECB             : }
                               8187                 : 
                               8188                 : /*
                               8189                 :  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
                               8190                 :  *
                               8191                 :  * Return the address of the affected column.
                               8192                 :  */
                               8193                 : static ObjectAddress
 2194 peter_e                  8194 GIC          19 : ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
 2194 peter_e                  8195 ECB             : {
                               8196                 :     ListCell   *option;
 2153 bruce                    8197 GIC          19 :     DefElem    *generatedEl = NULL;
                               8198                 :     HeapTuple   tuple;
                               8199                 :     Form_pg_attribute attTup;
                               8200                 :     AttrNumber  attnum;
                               8201                 :     Relation    attrelation;
                               8202                 :     ObjectAddress address;
 2194 peter_e                  8203 ECB             : 
 2194 peter_e                  8204 GIC          32 :     foreach(option, castNode(List, def))
 2194 peter_e                  8205 ECB             :     {
 2153 bruce                    8206 CBC          13 :         DefElem    *defel = lfirst_node(DefElem, option);
                               8207                 : 
 2194 peter_e                  8208              13 :         if (strcmp(defel->defname, "generated") == 0)
                               8209                 :         {
 2194 peter_e                  8210 GBC          13 :             if (generatedEl)
 2194 peter_e                  8211 UBC           0 :                 ereport(ERROR,
                               8212                 :                         (errcode(ERRCODE_SYNTAX_ERROR),
                               8213                 :                          errmsg("conflicting or redundant options")));
 2194 peter_e                  8214 CBC          13 :             generatedEl = defel;
                               8215                 :         }
 2194 peter_e                  8216 ECB             :         else
 2194 peter_e                  8217 LBC           0 :             elog(ERROR, "option \"%s\" not recognized",
                               8218                 :                  defel->defname);
                               8219                 :     }
 2194 peter_e                  8220 ECB             : 
                               8221                 :     /*
                               8222                 :      * Even if there is nothing to change here, we run all the checks.  There
                               8223                 :      * will be a subsequent ALTER SEQUENCE that relies on everything being
                               8224                 :      * there.
                               8225                 :      */
                               8226                 : 
 1539 andres                   8227 GIC          19 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
 2194 peter_e                  8228              19 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
 2194 peter_e                  8229 CBC          19 :     if (!HeapTupleIsValid(tuple))
 2194 peter_e                  8230 LBC           0 :         ereport(ERROR,
                               8231                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8232                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8233                 :                         colName, RelationGetRelationName(rel))));
                               8234                 : 
 2194 peter_e                  8235 CBC          19 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8236              19 :     attnum = attTup->attnum;
                               8237                 : 
 2194 peter_e                  8238 GIC          19 :     if (attnum <= 0)
 2194 peter_e                  8239 LBC           0 :         ereport(ERROR,
 2194 peter_e                  8240 ECB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8241                 :                  errmsg("cannot alter system column \"%s\"",
                               8242                 :                         colName)));
                               8243                 : 
 2194 peter_e                  8244 GIC          19 :     if (!attTup->attidentity)
 2194 peter_e                  8245 CBC           3 :         ereport(ERROR,
                               8246                 :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8247                 :                  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
                               8248                 :                         colName, RelationGetRelationName(rel))));
                               8249                 : 
 2194 peter_e                  8250 GIC          16 :     if (generatedEl)
                               8251                 :     {
                               8252              13 :         attTup->attidentity = defGetInt32(generatedEl);
                               8253              13 :         CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8254                 : 
 2194 peter_e                  8255 CBC          13 :         InvokeObjectPostAlterHook(RelationRelationId,
                               8256                 :                                   RelationGetRelid(rel),
 2194 peter_e                  8257 ECB             :                                   attTup->attnum);
 2194 peter_e                  8258 CBC          13 :         ObjectAddressSubSet(address, RelationRelationId,
                               8259                 :                             RelationGetRelid(rel), attnum);
 2194 peter_e                  8260 ECB             :     }
                               8261                 :     else
 2194 peter_e                  8262 GIC           3 :         address = InvalidObjectAddress;
 2194 peter_e                  8263 ECB             : 
 2194 peter_e                  8264 CBC          16 :     heap_freetuple(tuple);
 1539 andres                   8265              16 :     table_close(attrelation, RowExclusiveLock);
 2194 peter_e                  8266 ECB             : 
 2194 peter_e                  8267 CBC          16 :     return address;
 2194 peter_e                  8268 ECB             : }
                               8269                 : 
                               8270                 : /*
                               8271                 :  * ALTER TABLE ALTER COLUMN DROP IDENTITY
                               8272                 :  *
                               8273                 :  * Return the address of the affected column.
                               8274                 :  */
                               8275                 : static ObjectAddress
 2194 peter_e                  8276 CBC          19 : ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
 2194 peter_e                  8277 ECB             : {
                               8278                 :     HeapTuple   tuple;
                               8279                 :     Form_pg_attribute attTup;
                               8280                 :     AttrNumber  attnum;
                               8281                 :     Relation    attrelation;
                               8282                 :     ObjectAddress address;
                               8283                 :     Oid         seqid;
                               8284                 :     ObjectAddress seqaddress;
                               8285                 : 
 1539 andres                   8286 GIC          19 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
 2194 peter_e                  8287              19 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
 2194 peter_e                  8288 CBC          19 :     if (!HeapTupleIsValid(tuple))
 2194 peter_e                  8289 UIC           0 :         ereport(ERROR,
                               8290                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8291                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8292                 :                         colName, RelationGetRelationName(rel))));
 2194 peter_e                  8293 ECB             : 
 2194 peter_e                  8294 GIC          19 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8295              19 :     attnum = attTup->attnum;
 2194 peter_e                  8296 ECB             : 
 2194 peter_e                  8297 GIC          19 :     if (attnum <= 0)
 2194 peter_e                  8298 UIC           0 :         ereport(ERROR,
                               8299                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 2194 peter_e                  8300 ECB             :                  errmsg("cannot alter system column \"%s\"",
                               8301                 :                         colName)));
                               8302                 : 
 2194 peter_e                  8303 GIC          19 :     if (!attTup->attidentity)
                               8304                 :     {
                               8305               6 :         if (!missing_ok)
 2194 peter_e                  8306 CBC           3 :             ereport(ERROR,
                               8307                 :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8308                 :                      errmsg("column \"%s\" of relation \"%s\" is not an identity column",
                               8309                 :                             colName, RelationGetRelationName(rel))));
 2194 peter_e                  8310 ECB             :         else
                               8311                 :         {
 2194 peter_e                  8312 GIC           3 :             ereport(NOTICE,
                               8313                 :                     (errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
                               8314                 :                             colName, RelationGetRelationName(rel))));
                               8315               3 :             heap_freetuple(tuple);
 1539 andres                   8316               3 :             table_close(attrelation, RowExclusiveLock);
 2194 peter_e                  8317               3 :             return InvalidObjectAddress;
                               8318                 :         }
                               8319                 :     }
 2194 peter_e                  8320 ECB             : 
 2194 peter_e                  8321 GIC          13 :     attTup->attidentity = '\0';
                               8322              13 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8323                 : 
                               8324              13 :     InvokeObjectPostAlterHook(RelationRelationId,
 2194 peter_e                  8325 ECB             :                               RelationGetRelid(rel),
                               8326                 :                               attTup->attnum);
 2194 peter_e                  8327 CBC          13 :     ObjectAddressSubSet(address, RelationRelationId,
                               8328                 :                         RelationGetRelid(rel), attnum);
 2194 peter_e                  8329 GIC          13 :     heap_freetuple(tuple);
                               8330                 : 
 1539 andres                   8331              13 :     table_close(attrelation, RowExclusiveLock);
 2194 peter_e                  8332 ECB             : 
                               8333                 :     /* drop the internal sequence */
 1357 peter                    8334 GIC          13 :     seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
 2194 peter_e                  8335              13 :     deleteDependencyRecordsForClass(RelationRelationId, seqid,
                               8336                 :                                     RelationRelationId, DEPENDENCY_INTERNAL);
                               8337              13 :     CommandCounterIncrement();
                               8338              13 :     seqaddress.classId = RelationRelationId;
                               8339              13 :     seqaddress.objectId = seqid;
                               8340              13 :     seqaddress.objectSubId = 0;
                               8341              13 :     performDeletion(&seqaddress, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
                               8342                 : 
                               8343              13 :     return address;
                               8344                 : }
                               8345                 : 
                               8346                 : /*
                               8347                 :  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
                               8348                 :  */
                               8349                 : static void
  887 peter                    8350              22 : ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 1181 peter                    8351 EUB             : {
                               8352                 :     /*
                               8353                 :      * Reject ONLY if there are child tables.  We could implement this, but it
                               8354                 :      * is a bit complicated.  GENERATED clauses must be attached to the column
                               8355                 :      * definition and cannot be added later like DEFAULT, so if a child table
  887                          8356                 :      * has a generation expression that the parent does not have, the child
                               8357                 :      * column will necessarily be an attlocal column.  So to implement ONLY
                               8358                 :      * here, we'd need extra code to update attislocal of the direct child
                               8359                 :      * tables, somewhat similar to how DROP COLUMN does it, so that the
                               8360                 :      * resulting state can be properly dumped and restored.
                               8361                 :      */
  887 peter                    8362 GIC          28 :     if (!recurse &&
  711 alvherre                 8363               6 :         find_inheritance_children(RelationGetRelid(rel), lockmode))
  887 peter                    8364 GBC           3 :         ereport(ERROR,
  887 peter                    8365 EUB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8366                 :                  errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
                               8367                 : 
                               8368                 :     /*
                               8369                 :      * Cannot drop generation expression from inherited columns.
                               8370                 :      */
 1181 peter                    8371 GIC          19 :     if (!recursing)
 1181 peter                    8372 EUB             :     {
                               8373                 :         HeapTuple   tuple;
                               8374                 :         Form_pg_attribute attTup;
                               8375                 : 
 1181 peter                    8376 GIC          16 :         tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
                               8377              16 :         if (!HeapTupleIsValid(tuple))
 1181 peter                    8378 UIC           0 :             ereport(ERROR,
                               8379                 :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
 1181 peter                    8380 ECB             :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8381                 :                             cmd->name, RelationGetRelationName(rel))));
                               8382                 : 
 1181 peter                    8383 GIC          16 :         attTup = (Form_pg_attribute) GETSTRUCT(tuple);
 1181 peter                    8384 ECB             : 
 1181 peter                    8385 CBC          16 :         if (attTup->attinhcount > 0)
 1181 peter                    8386 GIC           3 :             ereport(ERROR,
                               8387                 :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8388                 :                      errmsg("cannot drop generation expression from inherited column")));
                               8389                 :     }
 1181 peter                    8390 CBC          16 : }
                               8391                 : 
                               8392                 : /*
                               8393                 :  * Return the address of the affected column.
                               8394                 :  */
                               8395                 : static ObjectAddress
 1181 peter                    8396 GIC          16 : ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
 1181 peter                    8397 ECB             : {
                               8398                 :     HeapTuple   tuple;
                               8399                 :     Form_pg_attribute attTup;
                               8400                 :     AttrNumber  attnum;
                               8401                 :     Relation    attrelation;
  384 tgl                      8402                 :     Oid         attrdefoid;
                               8403                 :     ObjectAddress address;
                               8404                 : 
 1181 peter                    8405 CBC          16 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
 1181 peter                    8406 GIC          16 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               8407              16 :     if (!HeapTupleIsValid(tuple))
 1181 peter                    8408 LBC           0 :         ereport(ERROR,
                               8409                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8410                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8411                 :                         colName, RelationGetRelationName(rel))));
                               8412                 : 
 1181 peter                    8413 GIC          16 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8414              16 :     attnum = attTup->attnum;
                               8415                 : 
                               8416              16 :     if (attnum <= 0)
 1181 peter                    8417 LBC           0 :         ereport(ERROR,
                               8418                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8419                 :                  errmsg("cannot alter system column \"%s\"",
 1181 peter                    8420 ECB             :                         colName)));
                               8421                 : 
 1181 peter                    8422 GIC          16 :     if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
                               8423                 :     {
                               8424               6 :         if (!missing_ok)
                               8425               3 :             ereport(ERROR,
                               8426                 :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 1181 peter                    8427 ECB             :                      errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
                               8428                 :                             colName, RelationGetRelationName(rel))));
                               8429                 :         else
                               8430                 :         {
 1181 peter                    8431 GIC           3 :             ereport(NOTICE,
                               8432                 :                     (errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
                               8433                 :                             colName, RelationGetRelationName(rel))));
                               8434               3 :             heap_freetuple(tuple);
 1181 peter                    8435 CBC           3 :             table_close(attrelation, RowExclusiveLock);
 1181 peter                    8436 GBC           3 :             return InvalidObjectAddress;
                               8437                 :         }
                               8438                 :     }
                               8439                 : 
                               8440                 :     /*
  384 tgl                      8441 ECB             :      * Mark the column as no longer generated.  (The atthasdef flag needs to
                               8442                 :      * get cleared too, but RemoveAttrDefault will handle that.)
                               8443                 :      */
 1181 peter                    8444 GIC          10 :     attTup->attgenerated = '\0';
                               8445              10 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8446                 : 
                               8447              10 :     InvokeObjectPostAlterHook(RelationRelationId,
 1181 peter                    8448 ECB             :                               RelationGetRelid(rel),
  384 tgl                      8449                 :                               attnum);
 1181 peter                    8450 GIC          10 :     heap_freetuple(tuple);
                               8451                 : 
                               8452              10 :     table_close(attrelation, RowExclusiveLock);
                               8453                 : 
                               8454                 :     /*
                               8455                 :      * Drop the dependency records of the GENERATED expression, in particular
                               8456                 :      * its INTERNAL dependency on the column, which would otherwise cause
                               8457                 :      * dependency.c to refuse to perform the deletion.
                               8458                 :      */
  384 tgl                      8459              10 :     attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
                               8460              10 :     if (!OidIsValid(attrdefoid))
  384 tgl                      8461 UIC           0 :         elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
                               8462                 :              RelationGetRelid(rel), attnum);
  384 tgl                      8463 GIC          10 :     (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
                               8464                 : 
  384 tgl                      8465 ECB             :     /* Make above changes visible */
  384 tgl                      8466 GIC          10 :     CommandCounterIncrement();
                               8467                 : 
  384 tgl                      8468 ECB             :     /*
                               8469                 :      * Get rid of the GENERATED expression itself.  We use RESTRICT here for
                               8470                 :      * safety, but at present we do not expect anything to depend on the
                               8471                 :      * default.
                               8472                 :      */
  384 tgl                      8473 CBC          10 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT,
  384 tgl                      8474 ECB             :                       false, false);
 1181 peter                    8475                 : 
  384 tgl                      8476 CBC          10 :     ObjectAddressSubSet(address, RelationRelationId,
  384 tgl                      8477 ECB             :                         RelationGetRelid(rel), attnum);
 1181 peter                    8478 GIC          10 :     return address;
                               8479                 : }
                               8480                 : 
                               8481                 : /*
                               8482                 :  * ALTER TABLE ALTER COLUMN SET STATISTICS
 1215 peter                    8483 ECB             :  *
                               8484                 :  * Return value is the address of the modified column
                               8485                 :  */
                               8486                 : static ObjectAddress
 1215 peter                    8487 CBC          82 : ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
                               8488                 : {
 1215 peter                    8489 ECB             :     int         newtarget;
                               8490                 :     Relation    attrelation;
                               8491                 :     HeapTuple   tuple;
                               8492                 :     Form_pg_attribute attrtuple;
                               8493                 :     AttrNumber  attnum;
                               8494                 :     ObjectAddress address;
                               8495                 : 
                               8496                 :     /*
                               8497                 :      * We allow referencing columns by numbers only for indexes, since table
 1991 tgl                      8498                 :      * column numbers could contain gaps if columns are later dropped.
                               8499                 :      */
 1906 alvherre                 8500 GIC          82 :     if (rel->rd_rel->relkind != RELKIND_INDEX &&
                               8501              50 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
                               8502                 :         !colName)
 2041 simon                    8503 UIC           0 :         ereport(ERROR,
                               8504                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8505                 :                  errmsg("cannot refer to non-index column by number")));
                               8506                 : 
 6913 tgl                      8507 GIC          82 :     Assert(IsA(newValue, Integer));
                               8508              82 :     newtarget = intVal(newValue);
                               8509                 : 
                               8510                 :     /*
 6913 tgl                      8511 ECB             :      * Limit target to a sane range
                               8512                 :      */
 6913 tgl                      8513 GIC          82 :     if (newtarget < -1)
 6913 tgl                      8514 ECB             :     {
 7203 tgl                      8515 UIC           0 :         ereport(ERROR,
 6913 tgl                      8516 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               8517                 :                  errmsg("statistics target %d is too low",
                               8518                 :                         newtarget)));
                               8519                 :     }
 5230 tgl                      8520 GIC          82 :     else if (newtarget > 10000)
                               8521                 :     {
 5230 tgl                      8522 UIC           0 :         newtarget = 10000;
 6913                          8523               0 :         ereport(WARNING,
                               8524                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               8525                 :                  errmsg("lowering statistics target to %d",
                               8526                 :                         newtarget)));
 6913 tgl                      8527 ECB             :     }
                               8528                 : 
 1539 andres                   8529 GIC          82 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               8530                 : 
 2041 simon                    8531              82 :     if (colName)
                               8532                 :     {
                               8533              50 :         tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               8534                 : 
 2041 simon                    8535 CBC          50 :         if (!HeapTupleIsValid(tuple))
 2041 simon                    8536 GIC           6 :             ereport(ERROR,
 2041 simon                    8537 ECB             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8538                 :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8539                 :                             colName, RelationGetRelationName(rel))));
                               8540                 :     }
 2041 simon                    8541 EUB             :     else
                               8542                 :     {
 2041 simon                    8543 GIC          32 :         tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), colNum);
                               8544                 : 
 2041 simon                    8545 CBC          32 :         if (!HeapTupleIsValid(tuple))
                               8546               6 :             ereport(ERROR,
                               8547                 :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8548                 :                      errmsg("column number %d of relation \"%s\" does not exist",
 2041 simon                    8549 ECB             :                             colNum, RelationGetRelationName(rel))));
 2041 simon                    8550 EUB             :     }
                               8551                 : 
 6913 tgl                      8552 GIC          70 :     attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
                               8553                 : 
 2937 alvherre                 8554              70 :     attnum = attrtuple->attnum;
                               8555              70 :     if (attnum <= 0)
 7203 tgl                      8556 UIC           0 :         ereport(ERROR,
                               8557                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8558                 :                  errmsg("cannot alter system column \"%s\"",
                               8559                 :                         colName)));
 7527 tgl                      8560 ECB             : 
 1728 alvherre                 8561 CBC          70 :     if (rel->rd_rel->relkind == RELKIND_INDEX ||
 1728 alvherre                 8562 GIC          44 :         rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
                               8563                 :     {
                               8564              26 :         if (attnum > rel->rd_index->indnkeyatts)
                               8565               3 :             ereport(ERROR,
 1728 alvherre                 8566 ECB             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8567                 :                      errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
                               8568                 :                             NameStr(attrtuple->attname), RelationGetRelationName(rel))));
 1728 alvherre                 8569 GIC          23 :         else if (rel->rd_index->indkey.values[attnum - 1] != 0)
                               8570               9 :             ereport(ERROR,
                               8571                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 1728 alvherre                 8572 ECB             :                      errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
                               8573                 :                             NameStr(attrtuple->attname), RelationGetRelationName(rel)),
                               8574                 :                      errhint("Alter statistics on table column instead.")));
                               8575                 :     }
                               8576                 : 
 6913 tgl                      8577 GIC          58 :     attrtuple->attstattarget = newtarget;
 6956 tgl                      8578 ECB             : 
 2259 alvherre                 8579 CBC          58 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8580                 : 
 3675 rhaas                    8581              58 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8582                 :                               RelationGetRelid(rel),
                               8583                 :                               attrtuple->attnum);
 2937 alvherre                 8584              58 :     ObjectAddressSubSet(address, RelationRelationId,
                               8585                 :                         RelationGetRelid(rel), attnum);
 6913 tgl                      8586              58 :     heap_freetuple(tuple);
                               8587                 : 
 1539 andres                   8588              58 :     table_close(attrelation, RowExclusiveLock);
                               8589                 : 
 2937 alvherre                 8590              58 :     return address;
                               8591                 : }
                               8592                 : 
                               8593                 : /*
                               8594                 :  * Return value is the address of the modified column
                               8595                 :  */
                               8596                 : static ObjectAddress
 4825 rhaas                    8597 GIC          16 : ATExecSetOptions(Relation rel, const char *colName, Node *options,
                               8598                 :                  bool isReset, LOCKMODE lockmode)
 4998 tgl                      8599 ECB             : {
                               8600                 :     Relation    attrelation;
                               8601                 :     HeapTuple   tuple,
 4825 rhaas                    8602                 :                 newtuple;
                               8603                 :     Form_pg_attribute attrtuple;
                               8604                 :     AttrNumber  attnum;
                               8605                 :     Datum       datum,
                               8606                 :                 newOptions;
                               8607                 :     bool        isnull;
                               8608                 :     ObjectAddress address;
                               8609                 :     Datum       repl_val[Natts_pg_attribute];
                               8610                 :     bool        repl_null[Natts_pg_attribute];
                               8611                 :     bool        repl_repl[Natts_pg_attribute];
                               8612                 : 
 1539 andres                   8613 CBC          16 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               8614                 : 
 4825 rhaas                    8615              16 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
 4998 tgl                      8616 EUB             : 
 4998 tgl                      8617 GIC          16 :     if (!HeapTupleIsValid(tuple))
 4998 tgl                      8618 UIC           0 :         ereport(ERROR,
 4998 tgl                      8619 ECB             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8620                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8621                 :                         colName, RelationGetRelationName(rel))));
 4998 tgl                      8622 GBC          16 :     attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
                               8623                 : 
 2937 alvherre                 8624 GIC          16 :     attnum = attrtuple->attnum;
                               8625              16 :     if (attnum <= 0)
 4998 tgl                      8626 UIC           0 :         ereport(ERROR,
                               8627                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8628                 :                  errmsg("cannot alter system column \"%s\"",
                               8629                 :                         colName)));
                               8630                 : 
                               8631                 :     /* Generate new proposed attoptions (text array) */
 4825 rhaas                    8632 CBC          16 :     datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
 4790 bruce                    8633 ECB             :                             &isnull);
 4825 rhaas                    8634 CBC          16 :     newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
 2264 andres                   8635 GBC          16 :                                      castNode(List, options), NULL, NULL,
                               8636                 :                                      false, isReset);
                               8637                 :     /* Validate new options */
 4825 rhaas                    8638 GIC          16 :     (void) attribute_reloptions(newOptions, true);
                               8639                 : 
 4825 rhaas                    8640 ECB             :     /* Build new tuple. */
 4825 rhaas                    8641 CBC          16 :     memset(repl_null, false, sizeof(repl_null));
 4825 rhaas                    8642 GIC          16 :     memset(repl_repl, false, sizeof(repl_repl));
 4825 rhaas                    8643 CBC          16 :     if (newOptions != (Datum) 0)
 4825 rhaas                    8644 GBC          16 :         repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
                               8645                 :     else
 4825 rhaas                    8646 UIC           0 :         repl_null[Anum_pg_attribute_attoptions - 1] = true;
 4825 rhaas                    8647 GIC          16 :     repl_repl[Anum_pg_attribute_attoptions - 1] = true;
                               8648              16 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
 4825 rhaas                    8649 ECB             :                                  repl_val, repl_null, repl_repl);
                               8650                 : 
                               8651                 :     /* Update system catalog. */
 2259 alvherre                 8652 GIC          16 :     CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
                               8653                 : 
 3675 rhaas                    8654              16 :     InvokeObjectPostAlterHook(RelationRelationId,
 3675 rhaas                    8655 ECB             :                               RelationGetRelid(rel),
                               8656                 :                               attrtuple->attnum);
 2937 alvherre                 8657 CBC          16 :     ObjectAddressSubSet(address, RelationRelationId,
 2937 alvherre                 8658 ECB             :                         RelationGetRelid(rel), attnum);
                               8659                 : 
 4825 rhaas                    8660 CBC          16 :     heap_freetuple(newtuple);
                               8661                 : 
 3675 rhaas                    8662 GIC          16 :     ReleaseSysCache(tuple);
 3675 rhaas                    8663 ECB             : 
 1539 andres                   8664 GIC          16 :     table_close(attrelation, RowExclusiveLock);
                               8665                 : 
 2937 alvherre                 8666              16 :     return address;
 6913 tgl                      8667 ECB             : }
                               8668                 : 
  751 rhaas                    8669                 : /*
                               8670                 :  * Helper function for ATExecSetStorage and ATExecSetCompression
                               8671                 :  *
  682 tgl                      8672                 :  * Set the attstorage and/or attcompression fields for index columns
                               8673                 :  * associated with the specified table column.
                               8674                 :  */
                               8675                 : static void
  751 rhaas                    8676 GIC         139 : SetIndexStorageProperties(Relation rel, Relation attrelation,
                               8677                 :                           AttrNumber attnum,
                               8678                 :                           bool setstorage, char newstorage,
                               8679                 :                           bool setcompression, char newcompression,
                               8680                 :                           LOCKMODE lockmode)
  751 rhaas                    8681 ECB             : {
                               8682                 :     ListCell   *lc;
                               8683                 : 
  751 rhaas                    8684 GIC         174 :     foreach(lc, RelationGetIndexList(rel))
                               8685                 :     {
                               8686              35 :         Oid         indexoid = lfirst_oid(lc);
                               8687                 :         Relation    indrel;
                               8688              35 :         AttrNumber  indattnum = 0;
                               8689                 :         HeapTuple   tuple;
                               8690                 : 
  751 rhaas                    8691 CBC          35 :         indrel = index_open(indexoid, lockmode);
  751 rhaas                    8692 ECB             : 
  751 rhaas                    8693 CBC          59 :         for (int i = 0; i < indrel->rd_index->indnatts; i++)
  751 rhaas                    8694 EUB             :         {
  751 rhaas                    8695 GIC          38 :             if (indrel->rd_index->indkey.values[i] == attnum)
                               8696                 :             {
                               8697              14 :                 indattnum = i + 1;
                               8698              14 :                 break;
  751 rhaas                    8699 ECB             :             }
                               8700                 :         }
                               8701                 : 
  751 rhaas                    8702 CBC          35 :         if (indattnum == 0)
  751 rhaas                    8703 EUB             :         {
  751 rhaas                    8704 GIC          21 :             index_close(indrel, lockmode);
                               8705              21 :             continue;
                               8706                 :         }
                               8707                 : 
  751 rhaas                    8708 CBC          14 :         tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
                               8709                 : 
                               8710              14 :         if (HeapTupleIsValid(tuple))
  751 rhaas                    8711 ECB             :         {
  682 tgl                      8712 GIC          14 :             Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
                               8713                 : 
                               8714              14 :             if (setstorage)
  751 rhaas                    8715              11 :                 attrtuple->attstorage = newstorage;
                               8716                 : 
  682 tgl                      8717 CBC          14 :             if (setcompression)
  682 tgl                      8718 GIC           3 :                 attrtuple->attcompression = newcompression;
                               8719                 : 
  751 rhaas                    8720 CBC          14 :             CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
  751 rhaas                    8721 ECB             : 
  751 rhaas                    8722 CBC          14 :             InvokeObjectPostAlterHook(RelationRelationId,
                               8723                 :                                       RelationGetRelid(rel),
                               8724                 :                                       attrtuple->attnum);
                               8725                 : 
                               8726              14 :             heap_freetuple(tuple);
  751 rhaas                    8727 ECB             :         }
                               8728                 : 
  751 rhaas                    8729 CBC          14 :         index_close(indrel, lockmode);
                               8730                 :     }
  751 rhaas                    8731 GIC         139 : }
  748 rhaas                    8732 ECB             : 
                               8733                 : /*
 6913 tgl                      8734                 :  * ALTER TABLE ALTER COLUMN SET STORAGE
                               8735                 :  *
 2937 alvherre                 8736                 :  * Return value is the address of the modified column
                               8737                 :  */
                               8738                 : static ObjectAddress
 4638 simon                    8739 CBC         115 : ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
 6913 tgl                      8740 ECB             : {
                               8741                 :     Relation    attrelation;
                               8742                 :     HeapTuple   tuple;
                               8743                 :     Form_pg_attribute attrtuple;
 2937 alvherre                 8744                 :     AttrNumber  attnum;
                               8745                 :     ObjectAddress address;
 7527 tgl                      8746                 : 
 1539 andres                   8747 CBC         115 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               8748                 : 
 6913 tgl                      8749 GIC         115 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               8750                 : 
                               8751             115 :     if (!HeapTupleIsValid(tuple))
                               8752               6 :         ereport(ERROR,
                               8753                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
 6797 bruce                    8754 ECB             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8755                 :                         colName, RelationGetRelationName(rel))));
 6913 tgl                      8756 GIC         109 :     attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
                               8757                 : 
 2937 alvherre                 8758             109 :     attnum = attrtuple->attnum;
 2937 alvherre                 8759 CBC         109 :     if (attnum <= 0)
 6913 tgl                      8760 LBC           0 :         ereport(ERROR,
 6913 tgl                      8761 EUB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8762                 :                  errmsg("cannot alter system column \"%s\"",
                               8763                 :                         colName)));
                               8764                 : 
  270 peter                    8765 GNC         109 :     attrtuple->attstorage = GetAttributeStorage(attrtuple->atttypid, strVal(newValue));
                               8766                 : 
 2259 alvherre                 8767 GIC         109 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8768                 : 
 3675 rhaas                    8769 CBC         109 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8770                 :                               RelationGetRelid(rel),
                               8771                 :                               attrtuple->attnum);
                               8772                 : 
                               8773                 :     /*
                               8774                 :      * Apply the change to indexes as well (only for simple index columns,
                               8775                 :      * matching behavior of index.c ConstructTupleDescriptor()).
 1095 peter                    8776 ECB             :      */
  751 rhaas                    8777 CBC         109 :     SetIndexStorageProperties(rel, attrelation, attnum,
  270 peter                    8778 GNC         109 :                               true, attrtuple->attstorage,
  682 tgl                      8779 EUB             :                               false, 0,
                               8780                 :                               lockmode);
                               8781                 : 
  270 peter                    8782 GNC         109 :     heap_freetuple(tuple);
                               8783                 : 
 1539 andres                   8784 GIC         109 :     table_close(attrelation, RowExclusiveLock);
                               8785                 : 
 2937 alvherre                 8786 CBC         109 :     ObjectAddressSubSet(address, RelationRelationId,
 2937 alvherre                 8787 ECB             :                         RelationGetRelid(rel), attnum);
 2937 alvherre                 8788 GIC         109 :     return address;
 6913 tgl                      8789 ECB             : }
 6913 tgl                      8790 EUB             : 
                               8791                 : 
                               8792                 : /*
                               8793                 :  * ALTER TABLE DROP COLUMN
                               8794                 :  *
 6913 tgl                      8795 ECB             :  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
                               8796                 :  * because we have to decide at runtime whether to recurse or not depending
 3260 bruce                    8797                 :  * on whether attinhcount goes to zero or not.  (We can't check this in a
 6913 tgl                      8798                 :  * static pre-pass because it won't handle multiple inheritance situations
                               8799                 :  * correctly.)
                               8800                 :  */
                               8801                 : static void
 4520 peter_e                  8802 GIC         778 : ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                               8803                 :                  AlterTableCmd *cmd, LOCKMODE lockmode,
 1180 tgl                      8804 ECB             :                  AlterTableUtilityContext *context)
                               8805                 : {
 4520 peter_e                  8806 GIC         778 :     if (rel->rd_rel->reloftype && !recursing)
 4643 peter_e                  8807 CBC           3 :         ereport(ERROR,
 4643 peter_e                  8808 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               8809                 :                  errmsg("cannot drop column from typed table")));
                               8810                 : 
 4578 peter_e                  8811 GIC         775 :     if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
 1180 tgl                      8812              41 :         ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
                               8813                 : 
 4643 peter_e                  8814             772 :     if (recurse)
  118 alvherre                 8815 GNC         638 :         cmd->recurse = true;
 4643 peter_e                  8816 GIC         772 : }
 4643 peter_e                  8817 ECB             : 
 2937 alvherre                 8818                 : /*
                               8819                 :  * Drops column 'colName' from relation 'rel' and returns the address of the
 1274 michael                  8820                 :  * dropped column.  The column is also dropped (or marked as no longer
                               8821                 :  * inherited from relation) from the relation's inheritance children, if any.
                               8822                 :  *
                               8823                 :  * In the recursive invocations for inheritance child relations, instead of
                               8824                 :  * dropping the column directly (if to be dropped at all), its object address
                               8825                 :  * is added to 'addrs', which must be non-NULL in such invocations.  All
                               8826                 :  * columns are dropped at the same time after all the children have been
                               8827                 :  * checked recursively.
                               8828                 :  */
                               8829                 : static ObjectAddress
 5170 tgl                      8830 GIC        1050 : ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
                               8831                 :                  DropBehavior behavior,
 5011 andrew                   8832 ECB             :                  bool recurse, bool recursing,
 1274 michael                  8833                 :                  bool missing_ok, LOCKMODE lockmode,
 1274 michael                  8834 EUB             :                  ObjectAddresses *addrs)
                               8835                 : {
 6913 tgl                      8836 ECB             :     HeapTuple   tuple;
                               8837                 :     Form_pg_attribute targetatt;
                               8838                 :     AttrNumber  attnum;
                               8839                 :     List       *children;
                               8840                 :     ObjectAddress object;
                               8841                 :     bool        is_expr;
                               8842                 : 
                               8843                 :     /* At top level, permission check was done in ATPrepCmd, else do it */
 6913 tgl                      8844 GIC        1050 :     if (recursing)
  640 peter                    8845             278 :         ATSimplePermissions(AT_DropColumn, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 6913 tgl                      8846 ECB             : 
                               8847                 :     /* Initialize addrs on the first invocation */
 1274 michael                  8848 GIC        1050 :     Assert(!recursing || addrs != NULL);
 1274 michael                  8849 CBC        1050 :     if (!recursing)
 1274 michael                  8850 GIC         772 :         addrs = new_object_addresses();
 1274 michael                  8851 ECB             : 
                               8852                 :     /*
                               8853                 :      * get the number of the attribute
                               8854                 :      */
 6913 tgl                      8855 GIC        1050 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
 4790 bruce                    8856            1050 :     if (!HeapTupleIsValid(tuple))
                               8857                 :     {
                               8858              27 :         if (!missing_ok)
                               8859                 :         {
 5011 andrew                   8860 CBC          18 :             ereport(ERROR,
                               8861                 :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8862                 :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8863                 :                             colName, RelationGetRelationName(rel))));
                               8864                 :         }
                               8865                 :         else
                               8866                 :         {
 5011 andrew                   8867 GIC           9 :             ereport(NOTICE,
                               8868                 :                     (errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
                               8869                 :                             colName, RelationGetRelationName(rel))));
 2937 alvherre                 8870               9 :             return InvalidObjectAddress;
                               8871                 :         }
                               8872                 :     }
 6913 tgl                      8873 CBC        1023 :     targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
 6913 tgl                      8874 ECB             : 
 6913 tgl                      8875 GIC        1023 :     attnum = targetatt->attnum;
 6913 tgl                      8876 EUB             : 
                               8877                 :     /* Can't drop a system attribute */
 1601 andres                   8878 GIC        1023 :     if (attnum <= 0)
 6913 tgl                      8879               3 :         ereport(ERROR,
 6913 tgl                      8880 ECB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8881                 :                  errmsg("cannot drop system column \"%s\"",
                               8882                 :                         colName)));
                               8883                 : 
                               8884                 :     /*
                               8885                 :      * Don't drop inherited columns, unless recursing (presumably from a drop
 1357                          8886                 :      * of the parent column)
                               8887                 :      */
 6913 tgl                      8888 GBC        1020 :     if (targetatt->attinhcount > 0 && !recursing)
 6913 tgl                      8889 GIC          24 :         ereport(ERROR,
                               8890                 :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8891                 :                  errmsg("cannot drop inherited column \"%s\"",
                               8892                 :                         colName)));
 6913 tgl                      8893 ECB             : 
                               8894                 :     /*
 1357 tgl                      8895 EUB             :      * Don't drop columns used in the partition key, either.  (If we let this
                               8896                 :      * go through, the key column's dependencies would cause a cascaded drop
                               8897                 :      * of the whole table, which is surely not what the user expected.)
                               8898                 :      */
 1921 rhaas                    8899 GIC         996 :     if (has_partition_attrs(rel,
                               8900                 :                             bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
                               8901                 :                             &is_expr))
 1357 tgl                      8902 CBC          15 :         ereport(ERROR,
                               8903                 :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 1357 tgl                      8904 ECB             :                  errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
                               8905                 :                         colName, RelationGetRelationName(rel))));
 2314 rhaas                    8906                 : 
 6913 tgl                      8907 GIC         981 :     ReleaseSysCache(tuple);
 7527 tgl                      8908 ECB             : 
 7555                          8909                 :     /*
                               8910                 :      * Propagate to children as appropriate.  Unlike most other ALTER
                               8911                 :      * routines, we have to do this one level of recursion at a time; we can't
                               8912                 :      * use find_all_inheritors to do it in one pass.
                               8913                 :      */
                               8914                 :     children =
  711 alvherre                 8915 GIC         981 :         find_inheritance_children(RelationGetRelid(rel), lockmode);
 6913 tgl                      8916 ECB             : 
 6913 tgl                      8917 GIC         981 :     if (children)
 7555 tgl                      8918 ECB             :     {
 7504                          8919                 :         Relation    attr_rel;
                               8920                 :         ListCell   *child;
                               8921                 : 
                               8922                 :         /*
                               8923                 :          * In case of a partitioned table, the column must be dropped from the
                               8924                 :          * partitions as well.
 2314 rhaas                    8925                 :          */
 2314 rhaas                    8926 GIC         151 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
 2314 rhaas                    8927 CBC           3 :             ereport(ERROR,
 2314 rhaas                    8928 ECB             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 2175 sfrost                   8929 EUB             :                      errmsg("cannot drop column from only the partitioned table when partitions exist"),
                               8930                 :                      errhint("Do not specify the ONLY keyword.")));
                               8931                 : 
 1539 andres                   8932 GIC         148 :         attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
 7555 tgl                      8933             441 :         foreach(child, children)
 7555 tgl                      8934 ECB             :         {
 6892 neilc                    8935 CBC         296 :             Oid         childrelid = lfirst_oid(child);
                               8936                 :             Relation    childrel;
 7504 tgl                      8937 ECB             :             Form_pg_attribute childatt;
 7555                          8938                 : 
                               8939                 :             /* find_inheritance_children already got lock */
 1539 andres                   8940 GIC         296 :             childrel = table_open(childrelid, NoLock);
 5548 tgl                      8941             296 :             CheckTableNotInUse(childrel, "ALTER TABLE");
 7504 tgl                      8942 ECB             : 
 7504 tgl                      8943 CBC         296 :             tuple = SearchSysCacheCopyAttName(childrelid, colName);
 2118 tgl                      8944 GIC         296 :             if (!HeapTupleIsValid(tuple))   /* shouldn't happen */
 7203 tgl                      8945 UIC           0 :                 elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
                               8946                 :                      colName, childrelid);
 7504 tgl                      8947 GIC         296 :             childatt = (Form_pg_attribute) GETSTRUCT(tuple);
                               8948                 : 
 2118                          8949             296 :             if (childatt->attinhcount <= 0) /* shouldn't happen */
 7203 tgl                      8950 LBC           0 :                 elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
                               8951                 :                      childrelid, colName);
 7504 tgl                      8952 ECB             : 
 6913 tgl                      8953 GIC         296 :             if (recurse)
 7504 tgl                      8954 ECB             :             {
                               8955                 :                 /*
                               8956                 :                  * If the child column has other definition sources, just
 6385 bruce                    8957                 :                  * decrement its inheritance count; if not, recurse to delete
                               8958                 :                  * it.
 6913 tgl                      8959                 :                  */
 6913 tgl                      8960 GIC         284 :                 if (childatt->attinhcount == 1 && !childatt->attislocal)
 6913 tgl                      8961 ECB             :                 {
                               8962                 :                     /* Time to delete this child column, too */
 5170 tgl                      8963 CBC         278 :                     ATExecDropColumn(wqueue, childrel, colName,
                               8964                 :                                      behavior, true, true,
                               8965                 :                                      false, lockmode, addrs);
                               8966                 :                 }
                               8967                 :                 else
                               8968                 :                 {
                               8969                 :                     /* Child column must survive my deletion */
 6913                          8970               6 :                     childatt->attinhcount--;
                               8971                 : 
 2259 alvherre                 8972 GIC           6 :                     CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
                               8973                 : 
                               8974                 :                     /* Make update visible */
 6913 tgl                      8975               6 :                     CommandCounterIncrement();
                               8976                 :                 }
                               8977                 :             }
                               8978                 :             else
                               8979                 :             {
                               8980                 :                 /*
                               8981                 :                  * If we were told to drop ONLY in this table (no recursion),
                               8982                 :                  * we need to mark the inheritors' attributes as locally
                               8983                 :                  * defined rather than inherited.
                               8984                 :                  */
 7504                          8985              12 :                 childatt->attinhcount--;
 6913 tgl                      8986 CBC          12 :                 childatt->attislocal = true;
                               8987                 : 
 2259 alvherre                 8988              12 :                 CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
                               8989                 : 
 6913 tgl                      8990 ECB             :                 /* Make update visible */
 6913 tgl                      8991 GBC          12 :                 CommandCounterIncrement();
                               8992                 :             }
                               8993                 : 
 7504 tgl                      8994 GIC         293 :             heap_freetuple(tuple);
 7504 tgl                      8995 ECB             : 
 1539 andres                   8996 GIC         293 :             table_close(childrel, NoLock);
 7555 tgl                      8997 ECB             :         }
 1539 andres                   8998 CBC         145 :         table_close(attr_rel, RowExclusiveLock);
 7555 tgl                      8999 EUB             :     }
                               9000                 : 
                               9001                 :     /* Add object to delete */
 6569 tgl                      9002 GIC         975 :     object.classId = RelationRelationId;
 6913                          9003             975 :     object.objectId = RelationGetRelid(rel);
 7555                          9004             975 :     object.objectSubId = attnum;
 1274 michael                  9005 CBC         975 :     add_exact_object_address(&object, addrs);
                               9006                 : 
                               9007             975 :     if (!recursing)
 1274 michael                  9008 ECB             :     {
                               9009                 :         /* Recursion has ended, drop everything that was collected */
 1274 michael                  9010 GIC         700 :         performMultipleDeletions(addrs, behavior, 0);
 1274 michael                  9011 CBC         679 :         free_object_addresses(addrs);
                               9012                 :     }
                               9013                 : 
 2937 alvherre                 9014             954 :     return object;
 7664 tgl                      9015 ECB             : }
                               9016                 : 
 6913                          9017                 : /*
                               9018                 :  * ALTER TABLE ADD INDEX
 6913 tgl                      9019 EUB             :  *
 5769 tgl                      9020 ECB             :  * There is no such command in the grammar, but parse_utilcmd.c converts
                               9021                 :  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands.  This lets
                               9022                 :  * us schedule creation of the index at the appropriate time during ALTER.
                               9023                 :  *
                               9024                 :  * Return value is the address of the new index.
 6913                          9025                 :  */
                               9026                 : static ObjectAddress
 6913 tgl                      9027 CBC         634 : ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
                               9028                 :                IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
                               9029                 : {
 6797 bruce                    9030 ECB             :     bool        check_rights;
                               9031                 :     bool        skip_build;
                               9032                 :     bool        quiet;
 2959 alvherre                 9033                 :     ObjectAddress address;
                               9034                 : 
 6913 tgl                      9035 CBC         634 :     Assert(IsA(stmt, IndexStmt));
 3919 tgl                      9036 GIC         634 :     Assert(!stmt->concurrent);
 6913 tgl                      9037 ECB             : 
                               9038                 :     /* The IndexStmt has already been through transformIndexStmt */
 2968 tgl                      9039 CBC         634 :     Assert(stmt->transformed);
                               9040                 : 
                               9041                 :     /* suppress schema rights check when rebuilding existing index */
 6913 tgl                      9042 GIC         634 :     check_rights = !is_rebuild;
                               9043                 :     /* skip index build if phase 3 will do it or we're reusing an old one */
  277 rhaas                    9044 GNC         634 :     skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
                               9045                 :     /* suppress notices when rebuilding existing index */
 6913 tgl                      9046 GIC         634 :     quiet = is_rebuild;
                               9047                 : 
 2959 alvherre                 9048             634 :     address = DefineIndex(RelationGetRelid(rel),
 2959 alvherre                 9049 ECB             :                           stmt,
                               9050                 :                           InvalidOid,   /* no predefined OID */
                               9051                 :                           InvalidOid,   /* no parent index */
                               9052                 :                           InvalidOid,   /* no parent constraint */
                               9053                 :                           -1,   /* total_parts unknown */
                               9054                 :                           true, /* is_alter_table */
                               9055                 :                           check_rights,
                               9056                 :                           false,    /* check_not_in_use - we did it already */
                               9057                 :                           skip_build,
                               9058                 :                           quiet);
                               9059                 : 
 4283 rhaas                    9060                 :     /*
                               9061                 :      * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
                               9062                 :      * new index instead of building from scratch.  Restore associated fields.
                               9063                 :      * This may store InvalidSubTransactionId in both fields, in which case
                               9064                 :      * relcache.c will assume it can rebuild the relcache entry.  Hence, do
 1100 noah                     9065                 :      * this after the CCI that made catalog rows visible to any rebuild.  The
                               9066                 :      * DROP of the old edition of this index will have scheduled the storage
                               9067                 :      * for deletion at commit, so cancel that pending deletion.
                               9068                 :      */
  277 rhaas                    9069 GNC         582 :     if (RelFileNumberIsValid(stmt->oldNumber))
                               9070                 :     {
 2959 alvherre                 9071 CBC          36 :         Relation    irel = index_open(address.objectId, NoLock);
 3955 bruce                    9072 ECB             : 
 1100 noah                     9073 GIC          36 :         irel->rd_createSubid = stmt->oldCreateSubid;
  277 rhaas                    9074 GNC          36 :         irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
                               9075              36 :         RelationPreserveStorage(irel->rd_locator, true);
 4283 rhaas                    9076 CBC          36 :         index_close(irel, NoLock);
                               9077                 :     }
 2937 alvherre                 9078 ECB             : 
 2937 alvherre                 9079 CBC         582 :     return address;
                               9080                 : }
                               9081                 : 
  744 tomas.vondra             9082 ECB             : /*
                               9083                 :  * ALTER TABLE ADD STATISTICS
                               9084                 :  *
                               9085                 :  * This is no such command in the grammar, but we use this internally to add
                               9086                 :  * AT_ReAddStatistics subcommands to rebuild extended statistics after a table
                               9087                 :  * column type change.
                               9088                 :  */
                               9089                 : static ObjectAddress
  744 tomas.vondra             9090 GIC           7 : ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
  744 tomas.vondra             9091 ECB             :                     CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
                               9092                 : {
                               9093                 :     ObjectAddress address;
                               9094                 : 
  744 tomas.vondra             9095 GIC           7 :     Assert(IsA(stmt, CreateStatsStmt));
  744 tomas.vondra             9096 ECB             : 
                               9097                 :     /* The CreateStatsStmt has already been through transformStatsStmt */
  744 tomas.vondra             9098 GIC           7 :     Assert(stmt->transformed);
                               9099                 : 
  744 tomas.vondra             9100 CBC           7 :     address = CreateStatistics(stmt);
                               9101                 : 
  744 tomas.vondra             9102 GIC           7 :     return address;
  744 tomas.vondra             9103 ECB             : }
                               9104                 : 
 4457 tgl                      9105                 : /*
                               9106                 :  * ALTER TABLE ADD CONSTRAINT USING INDEX
                               9107                 :  *
                               9108                 :  * Returns the address of the new constraint.
                               9109                 :  */
                               9110                 : static ObjectAddress
 4457 tgl                      9111 GIC       33361 : ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
                               9112                 :                          IndexStmt *stmt, LOCKMODE lockmode)
 4457 tgl                      9113 ECB             : {
 4457 tgl                      9114 GIC       33361 :     Oid         index_oid = stmt->indexOid;
                               9115                 :     Relation    indexRel;
                               9116                 :     char       *indexName;
                               9117                 :     IndexInfo  *indexInfo;
                               9118                 :     char       *constraintName;
                               9119                 :     char        constraintType;
                               9120                 :     ObjectAddress address;
 1972 alvherre                 9121 ECB             :     bits16      flags;
                               9122                 : 
 4457 tgl                      9123 CBC       33361 :     Assert(IsA(stmt, IndexStmt));
 4457 tgl                      9124 GIC       33361 :     Assert(OidIsValid(index_oid));
 4457 tgl                      9125 CBC       33361 :     Assert(stmt->isconstraint);
 4457 tgl                      9126 ECB             : 
                               9127                 :     /*
                               9128                 :      * Doing this on partitioned tables is not a simple feature to implement,
                               9129                 :      * so let's punt for now.
 1875 alvherre                 9130                 :      */
 1875 alvherre                 9131 GIC       33361 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
 1875 alvherre                 9132 CBC           3 :         ereport(ERROR,
 1875 alvherre                 9133 ECB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 1875 alvherre                 9134 EUB             :                  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
                               9135                 : 
 4457 tgl                      9136 GIC       33358 :     indexRel = index_open(index_oid, AccessShareLock);
                               9137                 : 
                               9138           33358 :     indexName = pstrdup(RelationGetRelationName(indexRel));
 4457 tgl                      9139 ECB             : 
 4457 tgl                      9140 GIC       33358 :     indexInfo = BuildIndexInfo(indexRel);
 4457 tgl                      9141 ECB             : 
                               9142                 :     /* this should have been checked at parse time */
 4457 tgl                      9143 CBC       33358 :     if (!indexInfo->ii_Unique)
 4457 tgl                      9144 UIC           0 :         elog(ERROR, "index \"%s\" is not unique", indexName);
                               9145                 : 
                               9146                 :     /*
                               9147                 :      * Determine name to assign to constraint.  We require a constraint to
                               9148                 :      * have the same name as the underlying index; therefore, use the index's
                               9149                 :      * existing name as the default constraint name, and if the user
                               9150                 :      * explicitly gives some other name for the constraint, rename the index
 4382 bruce                    9151 ECB             :      * to match.
 4457 tgl                      9152                 :      */
 4457 tgl                      9153 GIC       33358 :     constraintName = stmt->idxname;
                               9154           33358 :     if (constraintName == NULL)
                               9155           33351 :         constraintName = indexName;
 4457 tgl                      9156 CBC           7 :     else if (strcmp(constraintName, indexName) != 0)
                               9157                 :     {
                               9158               4 :         ereport(NOTICE,
                               9159                 :                 (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
 4457 tgl                      9160 ECB             :                         indexName, constraintName)));
 1627 peter_e                  9161 GIC           4 :         RenameRelationInternal(index_oid, constraintName, false, true);
 4457 tgl                      9162 ECB             :     }
                               9163                 : 
                               9164                 :     /* Extra checks needed if making primary key */
 4457 tgl                      9165 GIC       33358 :     if (stmt->primary)
 1646 alvherre                 9166           18810 :         index_check_primary_key(rel, indexInfo, true, stmt);
                               9167                 : 
                               9168                 :     /* Note we currently don't support EXCLUSION constraints here */
 4457 tgl                      9169           33355 :     if (stmt->primary)
                               9170           18807 :         constraintType = CONSTRAINT_PRIMARY;
                               9171                 :     else
                               9172           14548 :         constraintType = CONSTRAINT_UNIQUE;
                               9173                 : 
                               9174                 :     /* Create the catalog entries for the constraint */
 1972 alvherre                 9175           33355 :     flags = INDEX_CONSTR_CREATE_UPDATE_INDEX |
 1972 alvherre                 9176 ECB             :         INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS |
 1972 alvherre                 9177 GIC       66710 :         (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
                               9178           33355 :         (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
                               9179           33355 :         (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
 1972 alvherre                 9180 ECB             : 
 2937 alvherre                 9181 CBC       33355 :     address = index_constraint_create(rel,
                               9182                 :                                       index_oid,
                               9183                 :                                       InvalidOid,
                               9184                 :                                       indexInfo,
 2937 alvherre                 9185 ECB             :                                       constraintName,
                               9186                 :                                       constraintType,
                               9187                 :                                       flags,
                               9188                 :                                       allowSystemTableMods,
 2878 bruce                    9189                 :                                       false);   /* is_internal */
 4457 tgl                      9190                 : 
 4457 tgl                      9191 GIC       33355 :     index_close(indexRel, NoLock);
                               9192                 : 
 2937 alvherre                 9193           33355 :     return address;
                               9194                 : }
                               9195                 : 
                               9196                 : /*
                               9197                 :  * ALTER TABLE ADD CONSTRAINT
                               9198                 :  *
                               9199                 :  * Return value is the address of the new constraint; if no constraint was
                               9200                 :  * added, InvalidObjectAddress is returned.
                               9201                 :  */
                               9202                 : static ObjectAddress
 5448 tgl                      9203            1626 : ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 3807 tgl                      9204 ECB             :                     Constraint *newConstraint, bool recurse, bool is_readd,
                               9205                 :                     LOCKMODE lockmode)
                               9206                 : {
 2937 alvherre                 9207 GIC        1626 :     ObjectAddress address = InvalidObjectAddress;
                               9208                 : 
 5001 tgl                      9209            1626 :     Assert(IsA(newConstraint, Constraint));
                               9210                 : 
                               9211                 :     /*
                               9212                 :      * Currently, we only expect to see CONSTR_CHECK, CONSTR_NOTNULL and
                               9213                 :      * CONSTR_FOREIGN nodes arriving here (see the preprocessing done in
                               9214                 :      * parse_utilcmd.c).
                               9215                 :      */
                               9216            1626 :     switch (newConstraint->contype)
                               9217                 :     {
 5001 tgl                      9218 CBC         593 :         case CONSTR_CHECK:
                               9219                 :         case CONSTR_NOTNULL:
 2937 alvherre                 9220 ECB             :             address =
 2937 alvherre                 9221 GIC         593 :                 ATAddCheckConstraint(wqueue, tab, rel,
                               9222                 :                                      newConstraint, recurse, false, is_readd,
 2937 alvherre                 9223 ECB             :                                      lockmode);
 5001 tgl                      9224 CBC         560 :             break;
 7504 tgl                      9225 ECB             : 
 5001 tgl                      9226 GIC        1033 :         case CONSTR_FOREIGN:
                               9227                 : 
                               9228                 :             /*
                               9229                 :              * Assign or validate constraint name
 5001 tgl                      9230 ECB             :              */
 5001 tgl                      9231 CBC        1033 :             if (newConstraint->conname)
                               9232                 :             {
                               9233             392 :                 if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
                               9234                 :                                          RelationGetRelid(rel),
                               9235             392 :                                          newConstraint->conname))
 5001 tgl                      9236 UIC           0 :                     ereport(ERROR,
                               9237                 :                             (errcode(ERRCODE_DUPLICATE_OBJECT),
                               9238                 :                              errmsg("constraint \"%s\" for relation \"%s\" already exists",
                               9239                 :                                     newConstraint->conname,
                               9240                 :                                     RelationGetRelationName(rel))));
                               9241                 :             }
 5001 tgl                      9242 ECB             :             else
 5001 tgl                      9243 GIC         641 :                 newConstraint->conname =
                               9244             641 :                     ChooseConstraintName(RelationGetRelationName(rel),
 1488 peter                    9245 CBC         641 :                                          ChooseForeignKeyConstraintNameAddition(newConstraint->fk_attrs),
                               9246                 :                                          "fkey",
 5001 tgl                      9247 GIC         641 :                                          RelationGetNamespace(rel),
 5001 tgl                      9248 ECB             :                                          NIL);
                               9249                 : 
 1831 alvherre                 9250 CBC        1033 :             address = ATAddForeignKeyConstraint(wqueue, tab, rel,
                               9251                 :                                                 newConstraint,
                               9252                 :                                                 recurse, false,
 2937 alvherre                 9253 ECB             :                                                 lockmode);
 5001 tgl                      9254 CBC         873 :             break;
                               9255                 : 
 6913 tgl                      9256 UIC           0 :         default:
 5001                          9257               0 :             elog(ERROR, "unrecognized constraint type: %d",
                               9258                 :                  (int) newConstraint->contype);
                               9259                 :     }
                               9260                 : 
 2937 alvherre                 9261 GIC        1433 :     return address;
                               9262                 : }
 7653 tgl                      9263 ECB             : 
 1488 peter                    9264                 : /*
                               9265                 :  * Generate the column-name portion of the constraint name for a new foreign
                               9266                 :  * key given the list of column names that reference the referenced
                               9267                 :  * table.  This will be passed to ChooseConstraintName along with the parent
                               9268                 :  * table name and the "fkey" suffix.
                               9269                 :  *
                               9270                 :  * We know that less than NAMEDATALEN characters will actually be used, so we
                               9271                 :  * can truncate the result once we've generated that many.
                               9272                 :  *
                               9273                 :  * XXX see also ChooseExtendedStatisticNameAddition and
                               9274                 :  * ChooseIndexNameAddition.
                               9275                 :  */
                               9276                 : static char *
 1488 peter                    9277 CBC         973 : ChooseForeignKeyConstraintNameAddition(List *colnames)
                               9278                 : {
                               9279                 :     char        buf[NAMEDATALEN * 2];
 1488 peter                    9280 GIC         973 :     int         buflen = 0;
                               9281                 :     ListCell   *lc;
 1488 peter                    9282 ECB             : 
 1488 peter                    9283 GIC         973 :     buf[0] = '\0';
                               9284            2145 :     foreach(lc, colnames)
                               9285                 :     {
                               9286            1172 :         const char *name = strVal(lfirst(lc));
                               9287                 : 
                               9288            1172 :         if (buflen > 0)
                               9289             199 :             buf[buflen++] = '_';    /* insert _ between names */
 1488 peter                    9290 ECB             : 
                               9291                 :         /*
                               9292                 :          * At this point we have buflen <= NAMEDATALEN.  name should be less
                               9293                 :          * than NAMEDATALEN already, but use strlcpy for paranoia.
                               9294                 :          */
 1488 peter                    9295 GIC        1172 :         strlcpy(buf + buflen, name, NAMEDATALEN);
                               9296            1172 :         buflen += strlen(buf + buflen);
                               9297            1172 :         if (buflen >= NAMEDATALEN)
 1488 peter                    9298 UIC           0 :             break;
                               9299                 :     }
 1488 peter                    9300 GIC         973 :     return pstrdup(buf);
 1488 peter                    9301 ECB             : }
                               9302                 : 
                               9303                 : /*
                               9304                 :  * Add a check or NOT NULL constraint to a single table and its children.
                               9305                 :  * Returns the address of the constraint added to the parent relation,
                               9306                 :  * if one gets added, or InvalidObjectAddress otherwise.
 5448 tgl                      9307                 :  *
                               9308                 :  * Subroutine for ATExecAddConstraint.
                               9309                 :  *
                               9310                 :  * We must recurse to child tables during execution, rather than using
                               9311                 :  * ALTER TABLE's normal prep-time recursion.  The reason is that all the
                               9312                 :  * constraints *must* be given the same name, else they won't be seen as
                               9313                 :  * related later.  If the user didn't explicitly specify a name, then
                               9314                 :  * AddRelationNewConstraints would normally assign different names to the
                               9315                 :  * child constraints.  To fix that, we must capture the name assigned at
                               9316                 :  * the parent table and pass that down.
                               9317                 :  */
 2937 alvherre                 9318                 : static ObjectAddress
 5448 tgl                      9319 CBC         876 : ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 4638 simon                    9320 EUB             :                      Constraint *constr, bool recurse, bool recursing,
                               9321                 :                      bool is_readd, LOCKMODE lockmode)
 5448 tgl                      9322 ECB             : {
                               9323                 :     List       *newcons;
                               9324                 :     ListCell   *lcon;
 5448 tgl                      9325 EUB             :     List       *children;
                               9326                 :     ListCell   *child;
 2937 alvherre                 9327 GIC         876 :     ObjectAddress address = InvalidObjectAddress;
 5448 tgl                      9328 ECB             : 
                               9329                 :     /* At top level, permission check was done in ATPrepCmd, else do it */
 5448 tgl                      9330 GIC         876 :     if (recursing)
  640 peter                    9331             216 :         ATSimplePermissions(AT_AddConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               9332                 : 
                               9333                 :     /*
                               9334                 :      * Call AddRelationNewConstraints to do the work, making sure it works on
 5050 bruce                    9335 ECB             :      * a copy of the Constraint so transformExpr can't modify the original. It
                               9336                 :      * returns a list of cooked constraints.
                               9337                 :      *
 5448 tgl                      9338                 :      * If the constraint ends up getting merged with a pre-existing one, it's
                               9339                 :      * omitted from the returned list, which is what we want: we do not need
                               9340                 :      * to do any validation work.  That can only happen at child tables,
                               9341                 :      * though, since we disallow merging at the top level.
                               9342                 :      */
 5448 tgl                      9343 GIC         876 :     newcons = AddRelationNewConstraints(rel, NIL,
                               9344             876 :                                         list_make1(copyObject(constr)),
  108 michael                  9345 GNC         876 :                                         recursing || is_readd,  /* allow_merge */
 2118 tgl                      9346 GIC         876 :                                         !recursing, /* is_local */
 1691 peter_e                  9347 ECB             :                                         is_readd,   /* is_internal */
 1681 tgl                      9348 GIC         876 :                                         NULL);  /* queryString not available
                               9349                 :                                                  * here */
 5448 tgl                      9350 ECB             : 
                               9351                 :     /* we don't expect more than one constraint here */
 2937 alvherre                 9352 GIC         846 :     Assert(list_length(newcons) <= 1);
                               9353                 : 
                               9354                 :     /* Add each to-be-validated constraint to Phase 3's queue */
 5448 tgl                      9355            1663 :     foreach(lcon, newcons)
                               9356                 :     {
                               9357             817 :         CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
                               9358                 : 
    2 alvherre                 9359 GNC         817 :         if (!ccon->skip_validation && ccon->contype != CONSTR_NOTNULL)
 4330 alvherre                 9360 ECB             :         {
                               9361                 :             NewConstraint *newcon;
                               9362                 : 
 4330 alvherre                 9363 CBC         392 :             newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
 4330 alvherre                 9364 GIC         392 :             newcon->name = ccon->name;
                               9365             392 :             newcon->contype = ccon->contype;
 2217 andres                   9366 CBC         392 :             newcon->qual = ccon->expr;
                               9367                 : 
 4330 alvherre                 9368 GIC         392 :             tab->constraints = lappend(tab->constraints, newcon);
 4330 alvherre                 9369 ECB             :         }
                               9370                 : 
 5448 tgl                      9371                 :         /* Save the actually assigned name if it was defaulted */
 5001 tgl                      9372 GIC         817 :         if (constr->conname == NULL)
 5001 tgl                      9373 CBC         243 :             constr->conname = ccon->name;
                               9374                 : 
                               9375                 :         /*
                               9376                 :          * If adding a NOT NULL constraint, set the pg_attribute flag and
                               9377                 :          * tell phase 3 to verify existing rows, if needed.
                               9378                 :          */
    2 alvherre                 9379 GNC         817 :         if (constr->contype == CONSTR_NOTNULL)
                               9380             237 :             set_attnotnull(wqueue, rel, ccon->attnum,
                               9381             237 :                            !ccon->is_no_inherit, lockmode);
                               9382                 : 
 2937 alvherre                 9383 GIC         817 :         ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
                               9384                 :     }
 5448 tgl                      9385 ECB             : 
                               9386                 :     /* At this point we must have a locked-down name to use */
 5001 tgl                      9387 CBC         846 :     Assert(constr->conname != NULL);
 5448 tgl                      9388 ECB             : 
                               9389                 :     /* Advance command counter in case same table is visited multiple times */
 5448 tgl                      9390 CBC         846 :     CommandCounterIncrement();
                               9391                 : 
                               9392                 :     /*
 4632 rhaas                    9393 ECB             :      * If the constraint got merged with an existing constraint, we're done.
 4382 bruce                    9394                 :      * We mustn't recurse to child tables in this case, because they've
                               9395                 :      * already got the constraint, and visiting them again would lead to an
                               9396                 :      * incorrect value for coninhcount.
 4632 rhaas                    9397                 :      */
 4632 rhaas                    9398 GIC         846 :     if (newcons == NIL)
 2937 alvherre                 9399              29 :         return address;
                               9400                 : 
                               9401                 :     /*
                               9402                 :      * If adding a NO INHERIT constraint, no need to find our children.
                               9403                 :      */
 2697 tgl                      9404             817 :     if (constr->is_no_inherit)
 2937 alvherre                 9405              33 :         return address;
                               9406                 : 
                               9407                 :     /*
                               9408                 :      * Propagate to children as appropriate.  Unlike most other ALTER
                               9409                 :      * routines, we have to do this one level of recursion at a time; we can't
 5448 tgl                      9410 ECB             :      * use find_all_inheritors to do it in one pass.
                               9411                 :      */
                               9412                 :     children =
  711 alvherre                 9413 GIC         784 :         find_inheritance_children(RelationGetRelid(rel), lockmode);
                               9414                 : 
                               9415                 :     /*
                               9416                 :      * Check if ONLY was specified with ALTER TABLE.  If so, allow the
                               9417                 :      * constraint creation only if there are no children currently.  Error out
 4006 alvherre                 9418 ECB             :      * otherwise.
                               9419                 :      */
 4006 alvherre                 9420 GIC         784 :     if (!recurse && children != NIL)
                               9421               3 :         ereport(ERROR,
 4006 alvherre                 9422 ECB             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9423                 :                  errmsg("constraint must be added to child tables too")));
                               9424                 : 
 5448 tgl                      9425 CBC         994 :     foreach(child, children)
                               9426                 :     {
                               9427             216 :         Oid         childrelid = lfirst_oid(child);
                               9428                 :         Relation    childrel;
 5448 tgl                      9429 ECB             :         AlteredTableInfo *childtab;
                               9430                 : 
 5080                          9431                 :         /* find_inheritance_children already got lock */
 1539 andres                   9432 GIC         216 :         childrel = table_open(childrelid, NoLock);
 5448 tgl                      9433             216 :         CheckTableNotInUse(childrel, "ALTER TABLE");
                               9434                 : 
                               9435                 :         /* Find or create work queue entry for this table */
                               9436             216 :         childtab = ATGetQueueEntry(wqueue, childrel);
                               9437                 : 
                               9438                 :         /* Recurse to child */
                               9439             216 :         ATAddCheckConstraint(wqueue, childtab, childrel,
                               9440                 :                              constr, recurse, true, is_readd, lockmode);
                               9441                 : 
 1539 andres                   9442             213 :         table_close(childrel, NoLock);
                               9443                 :     }
                               9444                 : 
 2937 alvherre                 9445             778 :     return address;
                               9446                 : }
                               9447                 : 
                               9448                 : /*
                               9449                 :  * Add a foreign-key constraint to a single table; return the new constraint's
                               9450                 :  * address.
                               9451                 :  *
 3260 bruce                    9452 ECB             :  * Subroutine for ATExecAddConstraint.  Must already hold exclusive
                               9453                 :  * lock on the rel, and have done appropriate validity checks for it.
 5190 tgl                      9454                 :  * We do permissions checks here, however.
                               9455                 :  *
 1467 alvherre                 9456                 :  * When the referenced or referencing tables (or both) are partitioned,
                               9457                 :  * multiple pg_constraint rows are required -- one for each partitioned table
                               9458                 :  * and each partition on each side (fortunately, not one for every combination
                               9459                 :  * thereof).  We also need action triggers on each leaf partition on the
                               9460                 :  * referenced side, and check triggers on each leaf partition on the
                               9461                 :  * referencing side.
 7504 tgl                      9462                 :  */
                               9463                 : static ObjectAddress
 1831 alvherre                 9464 GIC        1033 : ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
                               9465                 :                           Constraint *fkconstraint,
                               9466                 :                           bool recurse, bool recursing, LOCKMODE lockmode)
                               9467                 : {
                               9468                 :     Relation    pkrel;
  267 peter                    9469 GNC        1033 :     int16       pkattnum[INDEX_MAX_KEYS] = {0};
                               9470            1033 :     int16       fkattnum[INDEX_MAX_KEYS] = {0};
                               9471            1033 :     Oid         pktypoid[INDEX_MAX_KEYS] = {0};
                               9472            1033 :     Oid         fktypoid[INDEX_MAX_KEYS] = {0};
                               9473            1033 :     Oid         opclasses[INDEX_MAX_KEYS] = {0};
                               9474            1033 :     Oid         pfeqoperators[INDEX_MAX_KEYS] = {0};
                               9475            1033 :     Oid         ppeqoperators[INDEX_MAX_KEYS] = {0};
                               9476            1033 :     Oid         ffeqoperators[INDEX_MAX_KEYS] = {0};
                               9477            1033 :     int16       fkdelsetcols[INDEX_MAX_KEYS] = {0};
 6913 tgl                      9478 ECB             :     int         i;
                               9479                 :     int         numfks,
                               9480                 :                 numpks,
  487 peter                    9481                 :                 numfkdelsetcols;
                               9482                 :     Oid         indexOid;
 4059 alvherre                 9483                 :     bool        old_check_ok;
                               9484                 :     ObjectAddress address;
 4059 alvherre                 9485 CBC        1033 :     ListCell   *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
                               9486                 : 
                               9487                 :     /*
                               9488                 :      * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
                               9489                 :      * delete rows out from under us.
                               9490                 :      */
 3338 rhaas                    9491 GIC        1033 :     if (OidIsValid(fkconstraint->old_pktable_oid))
 1539 andres                   9492              30 :         pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
                               9493                 :     else
 1539 andres                   9494 CBC        1003 :         pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
                               9495                 : 
                               9496                 :     /*
 5050 bruce                    9497 ECB             :      * Validity checks (permission checks wait till we have the column
                               9498                 :      * numbers)
                               9499                 :      */
 1831 alvherre                 9500 GIC        1033 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               9501                 :     {
                               9502             145 :         if (!recurse)
                               9503               3 :             ereport(ERROR,
                               9504                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               9505                 :                      errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
 1644 michael                  9506 ECB             :                             RelationGetRelationName(rel),
 1831 alvherre                 9507                 :                             RelationGetRelationName(pkrel))));
 1831 alvherre                 9508 CBC         142 :         if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
 1831 alvherre                 9509 GIC           3 :             ereport(ERROR,
                               9510                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               9511                 :                      errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
                               9512                 :                             RelationGetRelationName(rel),
                               9513                 :                             RelationGetRelationName(pkrel)),
 1831 alvherre                 9514 ECB             :                      errdetail("This feature is not yet supported on partitioned tables.")));
                               9515                 :     }
                               9516                 : 
 1467 alvherre                 9517 GIC        1027 :     if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
                               9518             128 :         pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 6913 tgl                      9519 LBC           0 :         ereport(ERROR,
                               9520                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 6913 tgl                      9521 ECB             :                  errmsg("referenced relation \"%s\" is not a table",
                               9522                 :                         RelationGetRelationName(pkrel))));
 7664                          9523                 : 
 6913 tgl                      9524 GIC        1027 :     if (!allowSystemTableMods && IsSystemRelation(pkrel))
 7203                          9525               1 :         ereport(ERROR,
 7203 tgl                      9526 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 7191 tgl                      9527 EUB             :                  errmsg("permission denied: \"%s\" is a system catalog",
                               9528                 :                         RelationGetRelationName(pkrel))));
                               9529                 : 
                               9530                 :     /*
                               9531                 :      * References from permanent or unlogged tables to temp tables, and from
                               9532                 :      * permanent tables to unlogged tables, are disallowed because the
                               9533                 :      * referenced data can vanish out from under us.  References from temp
                               9534                 :      * tables to any other table type are also disallowed, because other
                               9535                 :      * backends might need to run the RI triggers on the perm table, but they
 4484 rhaas                    9536 ECB             :      * can't reliably see tuples in the local buffers of other backends.
 7142 tgl                      9537                 :      */
 4500 rhaas                    9538 CBC        1026 :     switch (rel->rd_rel->relpersistence)
 7142 tgl                      9539 ECB             :     {
 4500 rhaas                    9540 GIC         871 :         case RELPERSISTENCE_PERMANENT:
  748 bruce                    9541 CBC         871 :             if (!RelationIsPermanent(pkrel))
 4500 rhaas                    9542 UIC           0 :                 ereport(ERROR,
                               9543                 :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 4500 rhaas                    9544 ECB             :                          errmsg("constraints on permanent tables may reference only permanent tables")));
 4500 rhaas                    9545 GIC         871 :             break;
 4484                          9546              16 :         case RELPERSISTENCE_UNLOGGED:
  748 bruce                    9547              16 :             if (!RelationIsPermanent(pkrel)
 4484 rhaas                    9548 CBC          16 :                 && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
 4484 rhaas                    9549 LBC           0 :                 ereport(ERROR,
                               9550                 :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9551                 :                          errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
 4484 rhaas                    9552 CBC          16 :             break;
 4500                          9553             139 :         case RELPERSISTENCE_TEMP:
 4500 rhaas                    9554 GIC         139 :             if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
 4500 rhaas                    9555 LBC           0 :                 ereport(ERROR,
                               9556                 :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9557                 :                          errmsg("constraints on temporary tables may reference only temporary tables")));
 3765 tgl                      9558 CBC         139 :             if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
 3765 tgl                      9559 UIC           0 :                 ereport(ERROR,
 3765 tgl                      9560 ECB             :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9561                 :                          errmsg("constraints on temporary tables must involve temporary tables of this session")));
 4500 rhaas                    9562 CBC         139 :             break;
                               9563                 :     }
 7504 tgl                      9564 ECB             : 
                               9565                 :     /*
                               9566                 :      * Look up the referencing attributes to make sure they exist, and record
                               9567                 :      * their attnums and type OIDs.
                               9568                 :      */
 7504 tgl                      9569 GIC        1026 :     numfks = transformColumnNameList(RelationGetRelid(rel),
                               9570                 :                                      fkconstraint->fk_attrs,
                               9571                 :                                      fkattnum, fktypoid);
                               9572                 : 
  487 peter                    9573            1011 :     numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
                               9574                 :                                               fkconstraint->fk_del_set_cols,
                               9575                 :                                               fkdelsetcols, NULL);
  487 peter                    9576 CBC        1008 :     validateFkOnDeleteSetColumns(numfks, fkattnum,
                               9577                 :                                  numfkdelsetcols, fkdelsetcols,
                               9578                 :                                  fkconstraint->fk_del_set_cols);
                               9579                 : 
 7504 tgl                      9580 ECB             :     /*
                               9581                 :      * If the attribute list for the referenced table was omitted, lookup the
 6385 bruce                    9582                 :      * definition of the primary key and use it.  Otherwise, validate the
                               9583                 :      * supplied attribute list.  In either case, discover the index OID and
                               9584                 :      * index opclasses, and the attnums and type OIDs of the attributes.
                               9585                 :      */
 7504 tgl                      9586 GIC        1005 :     if (fkconstraint->pk_attrs == NIL)
                               9587                 :     {
                               9588             458 :         numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
 7504 tgl                      9589 ECB             :                                             &fkconstraint->pk_attrs,
                               9590                 :                                             pkattnum, pktypoid,
 6966                          9591                 :                                             opclasses);
                               9592                 :     }
                               9593                 :     else
 7504                          9594                 :     {
 7504 tgl                      9595 GIC         547 :         numpks = transformColumnNameList(RelationGetRelid(pkrel),
                               9596                 :                                          fkconstraint->pk_attrs,
 7504 tgl                      9597 ECB             :                                          pkattnum, pktypoid);
                               9598                 :         /* Look for an index matching the column list */
 6966 tgl                      9599 CBC         532 :         indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
                               9600                 :                                            opclasses);
                               9601                 :     }
                               9602                 : 
                               9603                 :     /*
 5190 tgl                      9604 ECB             :      * Now we can check permissions.
                               9605                 :      */
 5190 tgl                      9606 CBC         984 :     checkFkeyPermissions(pkrel, pkattnum, numpks);
                               9607                 : 
 1471 peter                    9608 ECB             :     /*
 1471 peter                    9609 EUB             :      * Check some things for generated columns.
                               9610                 :      */
 1471 peter                    9611 GIC        2220 :     for (i = 0; i < numfks; i++)
                               9612                 :     {
                               9613            1242 :         char        attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
                               9614                 : 
                               9615            1242 :         if (attgenerated)
 1471 peter                    9616 ECB             :         {
                               9617                 :             /*
                               9618                 :              * Check restrictions on UPDATE/DELETE actions, per SQL standard
                               9619                 :              */
 1471 peter                    9620 CBC           9 :             if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
 1471 peter                    9621 GIC           9 :                 fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
                               9622               9 :                 fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
 1471 peter                    9623 CBC           3 :                 ereport(ERROR,
                               9624                 :                         (errcode(ERRCODE_SYNTAX_ERROR),
                               9625                 :                          errmsg("invalid %s action for foreign key constraint containing generated column",
                               9626                 :                                 "ON UPDATE")));
                               9627               6 :             if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
 1471 peter                    9628 GIC           3 :                 fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
 1471 peter                    9629 GBC           3 :                 ereport(ERROR,
 1471 peter                    9630 EUB             :                         (errcode(ERRCODE_SYNTAX_ERROR),
                               9631                 :                          errmsg("invalid %s action for foreign key constraint containing generated column",
                               9632                 :                                 "ON DELETE")));
                               9633                 :         }
 1471 peter                    9634 ECB             :     }
                               9635                 : 
                               9636                 :     /*
                               9637                 :      * Look up the equality operators to use in the constraint.
                               9638                 :      *
                               9639                 :      * Note that we have to be careful about the difference between the actual
                               9640                 :      * PK column type and the opclass' declared input type, which might be
                               9641                 :      * only binary-compatible with it.  The declared opcintype is the right
                               9642                 :      * thing to probe pg_amop with.
                               9643                 :      */
 7504 tgl                      9644 GIC         978 :     if (numfks != numpks)
 7203 tgl                      9645 UIC           0 :         ereport(ERROR,
                               9646                 :                 (errcode(ERRCODE_INVALID_FOREIGN_KEY),
                               9647                 :                  errmsg("number of referencing and referenced columns for foreign key disagree")));
                               9648                 : 
                               9649                 :     /*
 4059 alvherre                 9650 ECB             :      * On the strength of a previous constraint, we might avoid scanning
                               9651                 :      * tables to validate this one.  See below.
                               9652                 :      */
 4059 alvherre                 9653 CBC         978 :     old_check_ok = (fkconstraint->old_conpfeqop != NIL);
 4059 alvherre                 9654 GIC         978 :     Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
                               9655                 : 
 7504 tgl                      9656 CBC        2037 :     for (i = 0; i < numpks; i++)
 7504 tgl                      9657 ECB             :     {
 5896 tgl                      9658 GIC        1164 :         Oid         pktype = pktypoid[i];
 5896 tgl                      9659 CBC        1164 :         Oid         fktype = fktypoid[i];
                               9660                 :         Oid         fktyped;
 5898 tgl                      9661 ECB             :         HeapTuple   cla_ht;
                               9662                 :         Form_pg_opclass cla_tup;
                               9663                 :         Oid         amid;
                               9664                 :         Oid         opfamily;
                               9665                 :         Oid         opcintype;
                               9666                 :         Oid         pfeqop;
                               9667                 :         Oid         ppeqop;
                               9668                 :         Oid         ffeqop;
                               9669                 :         int16       eqstrategy;
 4059 alvherre                 9670                 :         Oid         pfeqop_right;
 5898 tgl                      9671 EUB             : 
                               9672                 :         /* We need several fields out of the pg_opclass entry */
 4802 rhaas                    9673 CBC        1164 :         cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
 5898 tgl                      9674 GIC        1164 :         if (!HeapTupleIsValid(cla_ht))
 5898 tgl                      9675 UIC           0 :             elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
 5898 tgl                      9676 GIC        1164 :         cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
                               9677            1164 :         amid = cla_tup->opcmethod;
                               9678            1164 :         opfamily = cla_tup->opcfamily;
 5896                          9679            1164 :         opcintype = cla_tup->opcintype;
 5898                          9680            1164 :         ReleaseSysCache(cla_ht);
                               9681                 : 
                               9682                 :         /*
                               9683                 :          * Check it's a btree; currently this can never fail since no other
                               9684                 :          * index AMs support unique indexes.  If we ever did have other types
                               9685                 :          * of unique indexes, we'd need a way to determine which operator
                               9686                 :          * strategy number is equality.  (Is it reasonable to insist that
                               9687                 :          * every such index AM use btree's number for equality?)
                               9688                 :          */
                               9689            1164 :         if (amid != BTREE_AM_OID)
 5898 tgl                      9690 UIC           0 :             elog(ERROR, "only b-tree indexes are supported for foreign keys");
 5898 tgl                      9691 GIC        1164 :         eqstrategy = BTEqualStrategyNumber;
 5898 tgl                      9692 ECB             : 
                               9693                 :         /*
                               9694                 :          * There had better be a primary equality operator for the index.
                               9695                 :          * We'll use it for PK = PK comparisons.
                               9696                 :          */
 5896 tgl                      9697 GIC        1164 :         ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
                               9698                 :                                      eqstrategy);
                               9699                 : 
 5898 tgl                      9700 CBC        1164 :         if (!OidIsValid(ppeqop))
 5898 tgl                      9701 UIC           0 :             elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
                               9702                 :                  eqstrategy, opcintype, opcintype, opfamily);
 5898 tgl                      9703 ECB             : 
                               9704                 :         /*
                               9705                 :          * Are there equality operators that take exactly the FK type? Assume
                               9706                 :          * we should look through any domain here.
                               9707                 :          */
 5896 tgl                      9708 GIC        1164 :         fktyped = getBaseType(fktype);
                               9709                 : 
                               9710            1164 :         pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
                               9711                 :                                      eqstrategy);
                               9712            1164 :         if (OidIsValid(pfeqop))
                               9713                 :         {
 4059 alvherre                 9714            1035 :             pfeqop_right = fktyped;
 5896 tgl                      9715            1035 :             ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
 5896 tgl                      9716 ECB             :                                          eqstrategy);
 4059 alvherre                 9717                 :         }
 5896 tgl                      9718                 :         else
 4059 alvherre                 9719                 :         {
                               9720                 :             /* keep compiler quiet */
 4059 alvherre                 9721 CBC         129 :             pfeqop_right = InvalidOid;
 4059 alvherre                 9722 GIC         129 :             ffeqop = InvalidOid;
                               9723                 :         }
                               9724                 : 
 5898 tgl                      9725 CBC        1164 :         if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
                               9726                 :         {
                               9727                 :             /*
 5624 bruce                    9728 ECB             :              * Otherwise, look for an implicit cast from the FK type to the
                               9729                 :              * opcintype, and if found, use the primary equality operator.
 5438 tgl                      9730                 :              * This is a bit tricky because opcintype might be a polymorphic
                               9731                 :              * type such as ANYARRAY or ANYENUM; so what we have to test is
                               9732                 :              * whether the two actual column types can be concurrently cast to
                               9733                 :              * that type.  (Otherwise, we'd fail to reject combinations such
                               9734                 :              * as int[] and point[].)
                               9735                 :              */
 5624 bruce                    9736                 :             Oid         input_typeids[2];
                               9737                 :             Oid         target_typeids[2];
 5896 tgl                      9738                 : 
 5896 tgl                      9739 CBC         129 :             input_typeids[0] = pktype;
 5896 tgl                      9740 GIC         129 :             input_typeids[1] = fktype;
 5896 tgl                      9741 CBC         129 :             target_typeids[0] = opcintype;
 5896 tgl                      9742 GIC         129 :             target_typeids[1] = opcintype;
                               9743             129 :             if (can_coerce_type(2, input_typeids, target_typeids,
                               9744                 :                                 COERCION_IMPLICIT))
 4059 alvherre                 9745 ECB             :             {
 5898 tgl                      9746 CBC          24 :                 pfeqop = ffeqop = ppeqop;
 4059 alvherre                 9747 GIC          24 :                 pfeqop_right = opcintype;
                               9748                 :             }
                               9749                 :         }
                               9750                 : 
 5898 tgl                      9751            1164 :         if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
 6966 tgl                      9752 CBC         105 :             ereport(ERROR,
 5898 tgl                      9753 ECB             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
 1467 alvherre                 9754                 :                      errmsg("foreign key constraint \"%s\" cannot be implemented",
                               9755                 :                             fkconstraint->conname),
 6966 tgl                      9756                 :                      errdetail("Key columns \"%s\" and \"%s\" "
                               9757                 :                                "are of incompatible types: %s and %s.",
                               9758                 :                                strVal(list_nth(fkconstraint->fk_attrs, i)),
                               9759                 :                                strVal(list_nth(fkconstraint->pk_attrs, i)),
 5896                          9760                 :                                format_type_be(fktype),
                               9761                 :                                format_type_be(pktype))));
                               9762                 : 
 4059 alvherre                 9763 CBC        1059 :         if (old_check_ok)
                               9764                 :         {
                               9765                 :             /*
                               9766                 :              * When a pfeqop changes, revalidate the constraint.  We could
                               9767                 :              * permit intra-opfamily changes, but that adds subtle complexity
                               9768                 :              * without any concrete benefit for core types.  We need not
                               9769                 :              * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
                               9770                 :              */
                               9771               3 :             old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
 1364 tgl                      9772               3 :             old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
                               9773                 :                                     old_pfeqop_item);
                               9774                 :         }
 4059 alvherre                 9775 GIC        1059 :         if (old_check_ok)
                               9776                 :         {
 4059 alvherre                 9777 ECB             :             Oid         old_fktype;
                               9778                 :             Oid         new_fktype;
                               9779                 :             CoercionPathType old_pathtype;
                               9780                 :             CoercionPathType new_pathtype;
                               9781                 :             Oid         old_castfunc;
                               9782                 :             Oid         new_castfunc;
 2058 andres                   9783 GIC           3 :             Form_pg_attribute attr = TupleDescAttr(tab->oldDesc,
                               9784                 :                                                    fkattnum[i] - 1);
                               9785                 : 
 4059 alvherre                 9786 ECB             :             /*
                               9787                 :              * Identify coercion pathways from each of the old and new FK-side
                               9788                 :              * column types to the right (foreign) operand type of the pfeqop.
                               9789                 :              * We may assume that pg_constraint.conkey is not changing.
                               9790                 :              */
 2058 andres                   9791 GIC           3 :             old_fktype = attr->atttypid;
 4059 alvherre                 9792               3 :             new_fktype = fktype;
 4059 alvherre                 9793 CBC           3 :             old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
 4059 alvherre                 9794 ECB             :                                         &old_castfunc);
 4059 alvherre                 9795 GIC           3 :             new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
                               9796                 :                                         &new_castfunc);
                               9797                 : 
 4059 alvherre                 9798 ECB             :             /*
                               9799                 :              * Upon a change to the cast from the FK column to its pfeqop
 3260 bruce                    9800                 :              * operand, revalidate the constraint.  For this evaluation, a
                               9801                 :              * binary coercion cast is equivalent to no cast at all.  While
                               9802                 :              * type implementors should design implicit casts with an eye
                               9803                 :              * toward consistency of operations like equality, we cannot
                               9804                 :              * assume here that they have done so.
 4059 alvherre                 9805                 :              *
                               9806                 :              * A function with a polymorphic argument could change behavior
                               9807                 :              * arbitrarily in response to get_fn_expr_argtype().  Therefore,
                               9808                 :              * when the cast destination is polymorphic, we only avoid
                               9809                 :              * revalidation if the input type has not changed at all.  Given
                               9810                 :              * just the core data types and operator classes, this requirement
                               9811                 :              * prevents no would-be optimizations.
                               9812                 :              *
                               9813                 :              * If the cast converts from a base type to a domain thereon, then
                               9814                 :              * that domain type must be the opcintype of the unique index.
                               9815                 :              * Necessarily, the primary key column must then be of the domain
                               9816                 :              * type.  Since the constraint was previously valid, all values on
                               9817                 :              * the foreign side necessarily exist on the primary side and in
 3260 bruce                    9818                 :              * turn conform to the domain.  Consequently, we need not treat
                               9819                 :              * domains specially here.
                               9820                 :              *
                               9821                 :              * Since we require that all collations share the same notion of
                               9822                 :              * equality (which they do, because texteq reduces to bitwise
                               9823                 :              * equality), we don't compare collation here.
                               9824                 :              *
                               9825                 :              * We need not directly consider the PK type.  It's necessarily
                               9826                 :              * binary coercible to the opcintype of the unique index column,
                               9827                 :              * and ri_triggers.c will only deal with PK datums in terms of
                               9828                 :              * that opcintype.  Changing the opcintype also changes pfeqop.
                               9829                 :              */
 4059 alvherre                 9830 GIC           3 :             old_check_ok = (new_pathtype == old_pathtype &&
                               9831               6 :                             new_castfunc == old_castfunc &&
                               9832               3 :                             (!IsPolymorphicType(pfeqop_right) ||
                               9833                 :                              new_fktype == old_fktype));
                               9834                 :         }
                               9835                 : 
 5898 tgl                      9836            1059 :         pfeqoperators[i] = pfeqop;
 5898 tgl                      9837 CBC        1059 :         ppeqoperators[i] = ppeqop;
 5898 tgl                      9838 GIC        1059 :         ffeqoperators[i] = ffeqop;
                               9839                 :     }
                               9840                 : 
                               9841                 :     /*
 1467 alvherre                 9842 ECB             :      * Create all the constraint and trigger objects, recursing to partitions
                               9843                 :      * as necessary.  First handle the referenced side.
                               9844                 :      */
 1467 alvherre                 9845 CBC         873 :     address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
 1467 alvherre                 9846 ECB             :                                      indexOid,
                               9847                 :                                      InvalidOid,    /* no parent constraint */
                               9848                 :                                      numfks,
                               9849                 :                                      pkattnum,
                               9850                 :                                      fkattnum,
                               9851                 :                                      pfeqoperators,
                               9852                 :                                      ppeqoperators,
                               9853                 :                                      ffeqoperators,
                               9854                 :                                      numfkdelsetcols,
                               9855                 :                                      fkdelsetcols,
                               9856                 :                                      old_check_ok,
                               9857                 :                                      InvalidOid, InvalidOid);
                               9858                 : 
                               9859                 :     /* Now handle the referencing side. */
 1467 alvherre                 9860 GIC         873 :     addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
                               9861                 :                             indexOid,
                               9862                 :                             address.objectId,
                               9863                 :                             numfks,
 1467 alvherre                 9864 ECB             :                             pkattnum,
                               9865                 :                             fkattnum,
                               9866                 :                             pfeqoperators,
                               9867                 :                             ppeqoperators,
                               9868                 :                             ffeqoperators,
                               9869                 :                             numfkdelsetcols,
                               9870                 :                             fkdelsetcols,
                               9871                 :                             old_check_ok,
                               9872                 :                             lockmode,
  459                          9873                 :                             InvalidOid, InvalidOid);
                               9874                 : 
 1467                          9875                 :     /*
                               9876                 :      * Done.  Close pk table, but keep lock until we've committed.
                               9877                 :      */
 1467 alvherre                 9878 GIC         873 :     table_close(pkrel, NoLock);
                               9879                 : 
                               9880             873 :     return address;
 1467 alvherre                 9881 ECB             : }
                               9882                 : 
                               9883                 : /*
                               9884                 :  * validateFkOnDeleteSetColumns
                               9885                 :  *      Verifies that columns used in ON DELETE SET NULL/DEFAULT (...)
                               9886                 :  *      column lists are valid.
                               9887                 :  */
                               9888                 : void
  487 peter                    9889 GIC        1008 : validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
  487 peter                    9890 ECB             :                              int numfksetcols, const int16 *fksetcolsattnums,
                               9891                 :                              List *fksetcols)
  487 peter                    9892 EUB             : {
  487 peter                    9893 GIC        1020 :     for (int i = 0; i < numfksetcols; i++)
                               9894                 :     {
  332 tgl                      9895              15 :         int16       setcol_attnum = fksetcolsattnums[i];
                               9896              15 :         bool        seen = false;
  487 peter                    9897 ECB             : 
  487 peter                    9898 CBC          27 :         for (int j = 0; j < numfks; j++)
                               9899                 :         {
  487 peter                    9900 GIC          24 :             if (fkattnums[j] == setcol_attnum)
                               9901                 :             {
                               9902              12 :                 seen = true;
                               9903              12 :                 break;
                               9904                 :             }
                               9905                 :         }
                               9906                 : 
                               9907              15 :         if (!seen)
                               9908                 :         {
  332 tgl                      9909               3 :             char       *col = strVal(list_nth(fksetcols, i));
                               9910                 : 
  487 peter                    9911 CBC           3 :             ereport(ERROR,
                               9912                 :                     (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
  487 peter                    9913 ECB             :                      errmsg("column \"%s\" referenced in ON DELETE SET action must be part of foreign key", col)));
                               9914                 :         }
  487 peter                    9915 EUB             :     }
  487 peter                    9916 GIC        1005 : }
                               9917                 : 
 1467 alvherre                 9918 ECB             : /*
                               9919                 :  * addFkRecurseReferenced
                               9920                 :  *      subroutine for ATAddForeignKeyConstraint; recurses on the referenced
                               9921                 :  *      side of the constraint
 1467 alvherre                 9922 EUB             :  *
                               9923                 :  * Create pg_constraint rows for the referenced side of the constraint,
                               9924                 :  * referencing the parent of the referencing side; also create action triggers
 1467 alvherre                 9925 ECB             :  * on leaf partitions.  If the table is partitioned, recurse to handle each
                               9926                 :  * partition.
                               9927                 :  *
 1467 alvherre                 9928 EUB             :  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
                               9929                 :  * of an ALTER TABLE sequence.
                               9930                 :  * fkconstraint is the constraint being added.
 1467 alvherre                 9931 ECB             :  * rel is the root referencing relation.
 1467 alvherre                 9932 EUB             :  * pkrel is the referenced relation; might be a partition, if recursing.
                               9933                 :  * indexOid is the OID of the index (on pkrel) implementing this constraint.
                               9934                 :  * parentConstr is the OID of a parent constraint; InvalidOid if this is a
 1467 alvherre                 9935 ECB             :  * top-level constraint.
                               9936                 :  * numfks is the number of columns in the foreign key
                               9937                 :  * pkattnum is the attnum array of referenced attributes.
                               9938                 :  * fkattnum is the attnum array of referencing attributes.
                               9939                 :  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
                               9940                 :  *      (...) clause
                               9941                 :  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
  123 peter                    9942                 :  *      NULL/DEFAULT clause
                               9943                 :  * pf/pp/ffeqoperators are OID array of operators between columns.
                               9944                 :  * old_check_ok signals that this constraint replaces an existing one that
                               9945                 :  * was already validated (thus this one doesn't need validation).
  459 alvherre                 9946                 :  * parentDelTrigger and parentUpdTrigger, when being recursively called on
                               9947                 :  * a partition, are the OIDs of the parent action triggers for DELETE and
                               9948                 :  * UPDATE respectively.
 1467                          9949                 :  */
                               9950                 : static ObjectAddress
 1467 alvherre                 9951 GIC        1202 : addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
                               9952                 :                        Relation pkrel, Oid indexOid, Oid parentConstr,
                               9953                 :                        int numfks,
                               9954                 :                        int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators,
                               9955                 :                        Oid *ppeqoperators, Oid *ffeqoperators,
                               9956                 :                        int numfkdelsetcols, int16 *fkdelsetcols,
                               9957                 :                        bool old_check_ok,
                               9958                 :                        Oid parentDelTrigger, Oid parentUpdTrigger)
 1467 alvherre                 9959 ECB             : {
                               9960                 :     ObjectAddress address;
                               9961                 :     Oid         constrOid;
                               9962                 :     char       *conname;
                               9963                 :     bool        conislocal;
                               9964                 :     int         coninhcount;
                               9965                 :     bool        connoinherit;
                               9966                 :     Oid         deleteTriggerOid,
                               9967                 :                 updateTriggerOid;
                               9968                 : 
                               9969                 :     /*
                               9970                 :      * Verify relkind for each referenced partition.  At the top level, this
                               9971                 :      * is redundant with a previous check, but we need it when recursing.
 1536                          9972                 :      */
 1467 alvherre                 9973 GIC        1202 :     if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
                               9974             178 :         pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 1467 alvherre                 9975 UIC           0 :         ereport(ERROR,
                               9976                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               9977                 :                  errmsg("referenced relation \"%s\" is not a table",
                               9978                 :                         RelationGetRelationName(pkrel))));
 1467 alvherre                 9979 ECB             : 
                               9980                 :     /*
                               9981                 :      * Caller supplies us with a constraint name; however, it may be used in
                               9982                 :      * this partition, so come up with a different one in that case.
                               9983                 :      */
 1467 alvherre                 9984 CBC        1202 :     if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
                               9985                 :                              RelationGetRelid(rel),
                               9986            1202 :                              fkconstraint->conname))
 1467 alvherre                 9987 GIC         329 :         conname = ChooseConstraintName(RelationGetRelationName(rel),
 1467 alvherre                 9988 CBC         329 :                                        ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
                               9989                 :                                        "fkey",
 1467 alvherre                 9990 GIC         329 :                                        RelationGetNamespace(rel), NIL);
                               9991                 :     else
                               9992             873 :         conname = fkconstraint->conname;
 1467 alvherre                 9993 ECB             : 
 1467 alvherre                 9994 CBC        1202 :     if (OidIsValid(parentConstr))
 1467 alvherre                 9995 ECB             :     {
 1467 alvherre                 9996 CBC         329 :         conislocal = false;
 1467 alvherre                 9997 GIC         329 :         coninhcount = 1;
                               9998             329 :         connoinherit = false;
                               9999                 :     }
 1467 alvherre                10000 ECB             :     else
                              10001                 :     {
 1467 alvherre                10002 CBC         873 :         conislocal = true;
 1467 alvherre                10003 GIC         873 :         coninhcount = 0;
                              10004                 : 
                              10005                 :         /*
                              10006                 :          * always inherit for partitioned tables, never for legacy inheritance
                              10007                 :          */
                              10008             873 :         connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
                              10009                 :     }
                              10010                 : 
                              10011                 :     /*
                              10012                 :      * Record the FK constraint in pg_constraint.
                              10013                 :      */
                              10014            1202 :     constrOid = CreateConstraintEntry(conname,
 7504 tgl                     10015            1202 :                                       RelationGetNamespace(rel),
                              10016                 :                                       CONSTRAINT_FOREIGN,
 7504 tgl                     10017 CBC        1202 :                                       fkconstraint->deferrable,
 7504 tgl                     10018 GBC        1202 :                                       fkconstraint->initdeferred,
 4401 simon                   10019 GIC        1202 :                                       fkconstraint->initially_valid,
                              10020                 :                                       parentConstr,
                              10021                 :                                       RelationGetRelid(rel),
                              10022                 :                                       fkattnum,
                              10023                 :                                       numfks,
                              10024                 :                                       numfks,
                              10025                 :                                       InvalidOid,   /* not a domain constraint */
 5003 tgl                     10026 ECB             :                                       indexOid,
 7504                         10027                 :                                       RelationGetRelid(pkrel),
                              10028                 :                                       pkattnum,
 5898                         10029                 :                                       pfeqoperators,
                              10030                 :                                       ppeqoperators,
                              10031                 :                                       ffeqoperators,
 1467 alvherre                10032                 :                                       numfks,
 7504 tgl                     10033 GIC        1202 :                                       fkconstraint->fk_upd_action,
                              10034            1202 :                                       fkconstraint->fk_del_action,
                              10035                 :                                       fkdelsetcols,
                              10036                 :                                       numfkdelsetcols,
                              10037            1202 :                                       fkconstraint->fk_matchtype,
                              10038                 :                                       NULL, /* no exclusion constraint */
                              10039                 :                                       NULL, /* no check constraint */
                              10040                 :                                       NULL,
                              10041                 :                                       conislocal,   /* islocal */
                              10042                 :                                       coninhcount,  /* inhcount */
                              10043                 :                                       connoinherit, /* conNoInherit */
                              10044                 :                                       false);   /* is_internal */
                              10045                 : 
 2937 alvherre                10046 CBC        1202 :     ObjectAddressSet(address, ConstraintRelationId, constrOid);
 7504 tgl                     10047 ECB             : 
 7504 tgl                     10048 EUB             :     /*
 1467 alvherre                10049 ECB             :      * Mark the child constraint as part of the parent constraint; it must not
                              10050                 :      * be dropped on its own.  (This constraint is deleted when the partition
                              10051                 :      * is detached, but a special check needs to occur that the partition
                              10052                 :      * contains no referenced values.)
 7504 tgl                     10053                 :      */
 1467 alvherre                10054 GIC        1202 :     if (OidIsValid(parentConstr))
                              10055                 :     {
                              10056                 :         ObjectAddress referenced;
                              10057                 : 
                              10058             329 :         ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
                              10059             329 :         recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
                              10060                 :     }
                              10061                 : 
 1467 alvherre                10062 ECB             :     /* make new constraint visible, in case we add more */
 1467 alvherre                10063 GBC        1202 :     CommandCounterIncrement();
 7504 tgl                     10064 ECB             : 
                              10065                 :     /*
                              10066                 :      * Create the action triggers that enforce the constraint.
                              10067                 :      */
  459 alvherre                10068 GIC        1202 :     createForeignKeyActionTriggers(rel, RelationGetRelid(pkrel),
                              10069                 :                                    fkconstraint,
  459 alvherre                10070 ECB             :                                    constrOid, indexOid,
                              10071                 :                                    parentDelTrigger, parentUpdTrigger,
                              10072                 :                                    &deleteTriggerOid, &updateTriggerOid);
 5898 tgl                     10073                 : 
 1831 alvherre                10074 EUB             :     /*
                              10075                 :      * If the referenced table is partitioned, recurse on ourselves to handle
                              10076                 :      * each partition.  We need one pg_constraint row created for each
                              10077                 :      * partition in addition to the pg_constraint row for the parent table.
                              10078                 :      */
 1467 alvherre                10079 GIC        1202 :     if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              10080                 :     {
  717 alvherre                10081 CBC         178 :         PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
                              10082                 : 
 1467                         10083             447 :         for (int i = 0; i < pd->nparts; i++)
                              10084                 :         {
 1467 alvherre                10085 ECB             :             Relation    partRel;
                              10086                 :             AttrMap    *map;
                              10087                 :             AttrNumber *mapped_pkattnum;
                              10088                 :             Oid         partIndexId;
                              10089                 : 
 1467 alvherre                10090 GIC         269 :             partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
                              10091                 : 
                              10092                 :             /*
                              10093                 :              * Map the attribute numbers in the referenced side of the FK
 1467 alvherre                10094 ECB             :              * definition to match the partition's column layout.
                              10095                 :              */
 1208 michael                 10096 GIC         269 :             map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
                              10097                 :                                                RelationGetDescr(pkrel),
                              10098                 :                                                false);
 1467 alvherre                10099 CBC         269 :             if (map)
                              10100                 :             {
 1467 alvherre                10101 GIC          23 :                 mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
                              10102              46 :                 for (int j = 0; j < numfks; j++)
 1208 michael                 10103              23 :                     mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
                              10104                 :             }
                              10105                 :             else
 1467 alvherre                10106             246 :                 mapped_pkattnum = pkattnum;
                              10107                 : 
                              10108                 :             /* do the deed */
                              10109             269 :             partIndexId = index_get_partition(partRel, indexOid);
                              10110             269 :             if (!OidIsValid(partIndexId))
 1467 alvherre                10111 UIC           0 :                 elog(ERROR, "index for %u not found in partition %s",
                              10112                 :                      indexOid, RelationGetRelationName(partRel));
 1467 alvherre                10113 CBC         269 :             addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
 1467 alvherre                10114 ECB             :                                    partIndexId, constrOid, numfks,
                              10115                 :                                    mapped_pkattnum, fkattnum,
                              10116                 :                                    pfeqoperators, ppeqoperators, ffeqoperators,
  487 peter                   10117                 :                                    numfkdelsetcols, fkdelsetcols,
                              10118                 :                                    old_check_ok,
                              10119                 :                                    deleteTriggerOid, updateTriggerOid);
 1467 alvherre                10120                 : 
                              10121                 :             /* Done -- clean up (but keep the lock) */
 1467 alvherre                10122 GIC         269 :             table_close(partRel, NoLock);
                              10123             269 :             if (map)
                              10124                 :             {
 1467 alvherre                10125 CBC          23 :                 pfree(mapped_pkattnum);
 1208 michael                 10126              23 :                 free_attrmap(map);
                              10127                 :             }
                              10128                 :         }
                              10129                 :     }
                              10130                 : 
 1467 alvherre                10131 GIC        1202 :     return address;
                              10132                 : }
                              10133                 : 
                              10134                 : /*
                              10135                 :  * addFkRecurseReferencing
                              10136                 :  *      subroutine for ATAddForeignKeyConstraint and CloneFkReferencing
 1467 alvherre                10137 ECB             :  *
                              10138                 :  * If the referencing relation is a plain relation, create the necessary check
                              10139                 :  * triggers that implement the constraint, and set up for Phase 3 constraint
                              10140                 :  * verification.  If the referencing relation is a partitioned table, then
                              10141                 :  * we create a pg_constraint row for it and recurse on this routine for each
                              10142                 :  * partition.
                              10143                 :  *
                              10144                 :  * We assume that the referenced relation is locked against concurrent
                              10145                 :  * deletions.  If it's a partitioned relation, every partition must be so
                              10146                 :  * locked.
                              10147                 :  *
                              10148                 :  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
                              10149                 :  * of an ALTER TABLE sequence.
                              10150                 :  * fkconstraint is the constraint being added.
                              10151                 :  * rel is the referencing relation; might be a partition, if recursing.
                              10152                 :  * pkrel is the root referenced relation.
                              10153                 :  * indexOid is the OID of the index (on pkrel) implementing this constraint.
                              10154                 :  * parentConstr is the OID of the parent constraint (there is always one).
                              10155                 :  * numfks is the number of columns in the foreign key
                              10156                 :  * pkattnum is the attnum array of referenced attributes.
                              10157                 :  * fkattnum is the attnum array of referencing attributes.
                              10158                 :  * pf/pp/ffeqoperators are OID array of operators between columns.
                              10159                 :  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
                              10160                 :  *      (...) clause
                              10161                 :  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
                              10162                 :  *      NULL/DEFAULT clause
                              10163                 :  * old_check_ok signals that this constraint replaces an existing one that
                              10164                 :  *      was already validated (thus this one doesn't need validation).
                              10165                 :  * lockmode is the lockmode to acquire on partitions when recursing.
  459                         10166                 :  * parentInsTrigger and parentUpdTrigger, when being recursively called on
                              10167                 :  * a partition, are the OIDs of the parent check triggers for INSERT and
                              10168                 :  * UPDATE respectively.
 1467                         10169                 :  */
                              10170                 : static void
 1467 alvherre                10171 GIC        1224 : addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
                              10172                 :                         Relation pkrel, Oid indexOid, Oid parentConstr,
                              10173                 :                         int numfks, int16 *pkattnum, int16 *fkattnum,
                              10174                 :                         Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
                              10175                 :                         int numfkdelsetcols, int16 *fkdelsetcols,
                              10176                 :                         bool old_check_ok, LOCKMODE lockmode,
                              10177                 :                         Oid parentInsTrigger, Oid parentUpdTrigger)
                              10178                 : {
                              10179                 :     Oid         insertTriggerOid,
                              10180                 :                 updateTriggerOid;
                              10181                 : 
  163 peter                   10182 GNC        1224 :     Assert(OidIsValid(parentConstr));
                              10183                 : 
 1467 alvherre                10184 GIC        1224 :     if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
 1467 alvherre                10185 UIC           0 :         ereport(ERROR,
                              10186                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              10187                 :                  errmsg("foreign key constraints are not supported on foreign tables")));
                              10188                 : 
                              10189                 :     /*
                              10190                 :      * Add the check triggers to it and, if necessary, schedule it to be
                              10191                 :      * checked in Phase 3.
                              10192                 :      *
                              10193                 :      * If the relation is partitioned, drill down to do it to its partitions.
                              10194                 :      */
  459 alvherre                10195 GIC        1224 :     createForeignKeyCheckTriggers(RelationGetRelid(rel),
                              10196                 :                                   RelationGetRelid(pkrel),
                              10197                 :                                   fkconstraint,
                              10198                 :                                   parentConstr,
                              10199                 :                                   indexOid,
                              10200                 :                                   parentInsTrigger, parentUpdTrigger,
                              10201                 :                                   &insertTriggerOid, &updateTriggerOid);
                              10202                 : 
 1467                         10203            1224 :     if (rel->rd_rel->relkind == RELKIND_RELATION)
 1467 alvherre                10204 ECB             :     {
                              10205                 :         /*
                              10206                 :          * Tell Phase 3 to check that the constraint is satisfied by existing
                              10207                 :          * rows. We can skip this during table creation, when requested
                              10208                 :          * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
                              10209                 :          * and when we're recreating a constraint following a SET DATA TYPE
                              10210                 :          * operation that did not impugn its validity.
                              10211                 :          */
 1467 alvherre                10212 CBC        1029 :         if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
                              10213                 :         {
                              10214                 :             NewConstraint *newcon;
                              10215                 :             AlteredTableInfo *tab;
                              10216                 : 
 1467 alvherre                10217 GIC         320 :             tab = ATGetQueueEntry(wqueue, rel);
                              10218                 : 
 1542 alvherre                10219 CBC         320 :             newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
 1467 alvherre                10220 GIC         320 :             newcon->name = get_constraint_name(parentConstr);
 1542                         10221             320 :             newcon->contype = CONSTR_FOREIGN;
 1467                         10222             320 :             newcon->refrelid = RelationGetRelid(pkrel);
                              10223             320 :             newcon->refindid = indexOid;
                              10224             320 :             newcon->conid = parentConstr;
 1542                         10225             320 :             newcon->qual = (Node *) fkconstraint;
                              10226                 : 
 1467                         10227             320 :             tab->constraints = lappend(tab->constraints, newcon);
                              10228                 :         }
                              10229                 :     }
                              10230             195 :     else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              10231                 :     {
  717                         10232             195 :         PartitionDesc pd = RelationGetPartitionDesc(rel, true);
                              10233                 :         Relation    trigrel;
  459 alvherre                10234 ECB             : 
                              10235                 :         /*
                              10236                 :          * Triggers of the foreign keys will be manipulated a bunch of times
                              10237                 :          * in the loop below.  To avoid repeatedly opening/closing the trigger
                              10238                 :          * catalog relation, we open it here and pass it to the subroutines
                              10239                 :          * called below.
                              10240                 :          */
  459 alvherre                10241 GIC         195 :         trigrel = table_open(TriggerRelationId, RowExclusiveLock);
                              10242                 : 
                              10243                 :         /*
                              10244                 :          * Recurse to take appropriate action on each partition; either we
                              10245                 :          * find an existing constraint to reparent to ours, or we create a new
                              10246                 :          * one.
                              10247                 :          */
 1467                         10248             377 :         for (int i = 0; i < pd->nparts; i++)
                              10249                 :         {
                              10250             182 :             Oid         partitionId = pd->oids[i];
                              10251             182 :             Relation    partition = table_open(partitionId, lockmode);
 1467 alvherre                10252 ECB             :             List       *partFKs;
                              10253                 :             AttrMap    *attmap;
                              10254                 :             AttrNumber  mapped_fkattnum[INDEX_MAX_KEYS];
                              10255                 :             bool        attached;
                              10256                 :             char       *conname;
                              10257                 :             Oid         constrOid;
                              10258                 :             ObjectAddress address,
                              10259                 :                         referenced;
                              10260                 :             ListCell   *cell;
                              10261                 : 
 1467 alvherre                10262 GIC         182 :             CheckTableNotInUse(partition, "ALTER TABLE");
 1467 alvherre                10263 ECB             : 
 1208 michael                 10264 GIC         182 :             attmap = build_attrmap_by_name(RelationGetDescr(partition),
                              10265                 :                                            RelationGetDescr(rel),
                              10266                 :                                            false);
 1467 alvherre                10267             466 :             for (int j = 0; j < numfks; j++)
 1208 michael                 10268 CBC         284 :                 mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
                              10269                 : 
 1467 alvherre                10270 ECB             :             /* Check whether an existing constraint can be repurposed */
 1467 alvherre                10271 CBC         182 :             partFKs = copyObject(RelationGetFKeyList(partition));
 1467 alvherre                10272 GIC         182 :             attached = false;
 1467 alvherre                10273 CBC         191 :             foreach(cell, partFKs)
                              10274                 :             {
 1467 alvherre                10275 ECB             :                 ForeignKeyCacheInfo *fk;
                              10276                 : 
 1467 alvherre                10277 CBC          15 :                 fk = lfirst_node(ForeignKeyCacheInfo, cell);
                              10278              15 :                 if (tryAttachPartitionForeignKey(fk,
                              10279                 :                                                  partitionId,
                              10280                 :                                                  parentConstr,
                              10281                 :                                                  numfks,
 1467 alvherre                10282 ECB             :                                                  mapped_fkattnum,
                              10283                 :                                                  pkattnum,
  459                         10284                 :                                                  pfeqoperators,
                              10285                 :                                                  insertTriggerOid,
                              10286                 :                                                  updateTriggerOid,
                              10287                 :                                                  trigrel))
                              10288                 :                 {
 1467 alvherre                10289 GIC           6 :                     attached = true;
                              10290               6 :                     break;
 1467 alvherre                10291 ECB             :                 }
                              10292                 :             }
 1467 alvherre                10293 GIC         182 :             if (attached)
                              10294                 :             {
                              10295               6 :                 table_close(partition, NoLock);
                              10296               6 :                 continue;
                              10297                 :             }
                              10298                 : 
                              10299                 :             /*
                              10300                 :              * No luck finding a good constraint to reuse; create our own.
                              10301                 :              */
                              10302             176 :             if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
                              10303                 :                                      RelationGetRelid(partition),
                              10304             176 :                                      fkconstraint->conname))
 1467 alvherre                10305 UIC           0 :                 conname = ChooseConstraintName(RelationGetRelationName(partition),
                              10306               0 :                                                ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
                              10307                 :                                                "fkey",
                              10308               0 :                                                RelationGetNamespace(partition), NIL);
                              10309                 :             else
 1467 alvherre                10310 GIC         176 :                 conname = fkconstraint->conname;
                              10311                 :             constrOid =
                              10312             176 :                 CreateConstraintEntry(conname,
                              10313             176 :                                       RelationGetNamespace(partition),
                              10314                 :                                       CONSTRAINT_FOREIGN,
                              10315             176 :                                       fkconstraint->deferrable,
                              10316             176 :                                       fkconstraint->initdeferred,
                              10317             176 :                                       fkconstraint->initially_valid,
                              10318                 :                                       parentConstr,
                              10319                 :                                       partitionId,
                              10320                 :                                       mapped_fkattnum,
                              10321                 :                                       numfks,
                              10322                 :                                       numfks,
                              10323                 :                                       InvalidOid,
                              10324                 :                                       indexOid,
                              10325                 :                                       RelationGetRelid(pkrel),
 1467 alvherre                10326 ECB             :                                       pkattnum,
                              10327                 :                                       pfeqoperators,
                              10328                 :                                       ppeqoperators,
                              10329                 :                                       ffeqoperators,
                              10330                 :                                       numfks,
 1467 alvherre                10331 GIC         176 :                                       fkconstraint->fk_upd_action,
                              10332             176 :                                       fkconstraint->fk_del_action,
                              10333                 :                                       fkdelsetcols,
                              10334                 :                                       numfkdelsetcols,
                              10335             176 :                                       fkconstraint->fk_matchtype,
                              10336                 :                                       NULL,
                              10337                 :                                       NULL,
                              10338                 :                                       NULL,
                              10339                 :                                       false,
                              10340                 :                                       1,
                              10341                 :                                       false,
                              10342                 :                                       false);
                              10343                 : 
                              10344                 :             /*
                              10345                 :              * Give this constraint partition-type dependencies on the parent
                              10346                 :              * constraint as well as the table.
                              10347                 :              */
 1467 alvherre                10348 CBC         176 :             ObjectAddressSet(address, ConstraintRelationId, constrOid);
                              10349             176 :             ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
 1467 alvherre                10350 GBC         176 :             recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
 1467 alvherre                10351 GIC         176 :             ObjectAddressSet(referenced, RelationRelationId, partitionId);
                              10352             176 :             recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
                              10353                 : 
                              10354                 :             /* Make all this visible before recursing */
                              10355             176 :             CommandCounterIncrement();
                              10356                 : 
                              10357                 :             /* call ourselves to finalize the creation and we're done */
                              10358             176 :             addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
 1467 alvherre                10359 ECB             :                                     indexOid,
                              10360                 :                                     constrOid,
                              10361                 :                                     numfks,
                              10362                 :                                     pkattnum,
                              10363                 :                                     mapped_fkattnum,
                              10364                 :                                     pfeqoperators,
                              10365                 :                                     ppeqoperators,
                              10366                 :                                     ffeqoperators,
  487 peter                   10367                 :                                     numfkdelsetcols,
                              10368                 :                                     fkdelsetcols,
 1467 alvherre                10369                 :                                     old_check_ok,
                              10370                 :                                     lockmode,
  459                         10371                 :                                     insertTriggerOid,
                              10372                 :                                     updateTriggerOid);
 1467                         10373                 : 
 1467 alvherre                10374 GIC         176 :             table_close(partition, NoLock);
                              10375                 :         }
                              10376                 : 
  459 alvherre                10377 CBC         195 :         table_close(trigrel, RowExclusiveLock);
 1467 alvherre                10378 ECB             :     }
 7504 tgl                     10379 GIC        1224 : }
                              10380                 : 
                              10381                 : /*
                              10382                 :  * CloneForeignKeyConstraints
 1542 alvherre                10383 ECB             :  *      Clone foreign keys from a partitioned table to a newly acquired
                              10384                 :  *      partition.
                              10385                 :  *
                              10386                 :  * partitionRel is a partition of parentRel, so we can be certain that it has
                              10387                 :  * the same columns with the same datatypes.  The columns may be in different
                              10388                 :  * order, though.
                              10389                 :  *
 1467                         10390                 :  * wqueue must be passed to set up phase 3 constraint checking, unless the
                              10391                 :  * referencing-side partition is known to be empty (such as in CREATE TABLE /
                              10392                 :  * PARTITION OF).
 1542                         10393                 :  */
                              10394                 : static void
 1467 alvherre                10395 GIC        4312 : CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
                              10396                 :                            Relation partitionRel)
                              10397                 : {
                              10398                 :     /* This only works for declarative partitioning */
                              10399            4312 :     Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                              10400                 : 
                              10401                 :     /*
                              10402                 :      * Clone constraints for which the parent is on the referenced side.
                              10403                 :      */
                              10404            4312 :     CloneFkReferenced(parentRel, partitionRel);
                              10405                 : 
                              10406                 :     /*
                              10407                 :      * Now clone constraints where the parent is on the referencing side.
 1467 alvherre                10408 ECB             :      */
 1467 alvherre                10409 CBC        4312 :     CloneFkReferencing(wqueue, parentRel, partitionRel);
 1467 alvherre                10410 GIC        4312 : }
                              10411                 : 
 1467 alvherre                10412 ECB             : /*
                              10413                 :  * CloneFkReferenced
                              10414                 :  *      Subroutine for CloneForeignKeyConstraints
                              10415                 :  *
                              10416                 :  * Find all the FKs that have the parent relation on the referenced side;
                              10417                 :  * clone those constraints to the given partition.  This is to be called
                              10418                 :  * when the partition is being created or attached.
                              10419                 :  *
                              10420                 :  * This ignores self-referencing FKs; those are handled by CloneFkReferencing.
  184                         10421                 :  *
                              10422                 :  * This recurses to partitions, if the relation being attached is partitioned.
                              10423                 :  * Recursion is done by calling addFkRecurseReferenced.
                              10424                 :  */
                              10425                 : static void
 1467 alvherre                10426 GIC        4312 : CloneFkReferenced(Relation parentRel, Relation partitionRel)
                              10427                 : {
                              10428                 :     Relation    pg_constraint;
 1208 michael                 10429 ECB             :     AttrMap    *attmap;
                              10430                 :     ListCell   *cell;
                              10431                 :     SysScanDesc scan;
                              10432                 :     ScanKeyData key[2];
 1542 alvherre                10433                 :     HeapTuple   tuple;
 1542 alvherre                10434 CBC        4312 :     List       *clone = NIL;
                              10435                 :     Relation    trigrel;
                              10436                 : 
                              10437                 :     /*
 1157 alvherre                10438 ECB             :      * Search for any constraints where this partition's parent is in the
                              10439                 :      * referenced side.  However, we must not clone any constraint whose
                              10440                 :      * parent constraint is also going to be cloned, to avoid duplicates.  So
                              10441                 :      * do it in two steps: first construct the list of constraints to clone,
                              10442                 :      * then go over that list cloning those whose parents are not in the list.
                              10443                 :      * (We must not rely on the parent being seen first, since the catalog
                              10444                 :      * scan could return children first.)
                              10445                 :      */
 1539 andres                  10446 GIC        4312 :     pg_constraint = table_open(ConstraintRelationId, RowShareLock);
 1467 alvherre                10447            4312 :     ScanKeyInit(&key[0],
                              10448                 :                 Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
                              10449                 :                 F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel)));
                              10450            4312 :     ScanKeyInit(&key[1],
                              10451                 :                 Anum_pg_constraint_contype, BTEqualStrategyNumber,
                              10452                 :                 F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
                              10453                 :     /* This is a seqscan, as we don't have a usable index ... */
 1467 alvherre                10454 CBC        4312 :     scan = systable_beginscan(pg_constraint, InvalidOid, true,
                              10455                 :                               NULL, 2, key);
 1542                         10456            4462 :     while ((tuple = systable_getnext(scan)) != NULL)
                              10457                 :     {
 1467                         10458             150 :         Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              10459                 : 
 1467 alvherre                10460 GIC         150 :         clone = lappend_oid(clone, constrForm->oid);
                              10461                 :     }
 1542                         10462            4312 :     systable_endscan(scan);
 1467                         10463            4312 :     table_close(pg_constraint, RowShareLock);
                              10464                 : 
  459 alvherre                10465 ECB             :     /*
                              10466                 :      * Triggers of the foreign keys will be manipulated a bunch of times in
                              10467                 :      * the loop below.  To avoid repeatedly opening/closing the trigger
                              10468                 :      * catalog relation, we open it here and pass it to the subroutines called
                              10469                 :      * below.
                              10470                 :      */
  459 alvherre                10471 CBC        4312 :     trigrel = table_open(TriggerRelationId, RowExclusiveLock);
                              10472                 : 
 1208 michael                 10473 GIC        4312 :     attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
                              10474                 :                                    RelationGetDescr(parentRel),
                              10475                 :                                    false);
 1467 alvherre                10476            4462 :     foreach(cell, clone)
 1467 alvherre                10477 ECB             :     {
 1467 alvherre                10478 CBC         150 :         Oid         constrOid = lfirst_oid(cell);
 1467 alvherre                10479 ECB             :         Form_pg_constraint constrForm;
                              10480                 :         Relation    fkRel;
                              10481                 :         Oid         indexOid;
                              10482                 :         Oid         partIndexId;
                              10483                 :         int         numfks;
                              10484                 :         AttrNumber  conkey[INDEX_MAX_KEYS];
                              10485                 :         AttrNumber  mapped_confkey[INDEX_MAX_KEYS];
                              10486                 :         AttrNumber  confkey[INDEX_MAX_KEYS];
 1467 alvherre                10487 EUB             :         Oid         conpfeqop[INDEX_MAX_KEYS];
                              10488                 :         Oid         conppeqop[INDEX_MAX_KEYS];
 1467 alvherre                10489 ECB             :         Oid         conffeqop[INDEX_MAX_KEYS];
                              10490                 :         int         numfkdelsetcols;
                              10491                 :         AttrNumber  confdelsetcols[INDEX_MAX_KEYS];
                              10492                 :         Constraint *fkconstraint;
                              10493                 :         Oid         deleteTriggerOid,
                              10494                 :                     updateTriggerOid;
                              10495                 : 
 1467 alvherre                10496 GIC         150 :         tuple = SearchSysCache1(CONSTROID, constrOid);
                              10497             150 :         if (!HeapTupleIsValid(tuple))
 1467 alvherre                10498 LBC           0 :             elog(ERROR, "cache lookup failed for constraint %u", constrOid);
 1467 alvherre                10499 CBC         150 :         constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              10500                 : 
 1157 alvherre                10501 ECB             :         /*
                              10502                 :          * As explained above: don't try to clone a constraint for which we're
                              10503                 :          * going to clone the parent.
                              10504                 :          */
 1157 alvherre                10505 GIC         150 :         if (list_member_oid(clone, constrForm->conparentid))
                              10506                 :         {
 1157 alvherre                10507 CBC          63 :             ReleaseSysCache(tuple);
  184 alvherre                10508 GIC          90 :             continue;
                              10509                 :         }
                              10510                 : 
                              10511                 :         /*
                              10512                 :          * Don't clone self-referencing foreign keys, which can be in the
                              10513                 :          * partitioned table or in the partition-to-be.
                              10514                 :          */
                              10515              87 :         if (constrForm->conrelid == RelationGetRelid(parentRel) ||
                              10516              66 :             constrForm->conrelid == RelationGetRelid(partitionRel))
                              10517                 :         {
                              10518              27 :             ReleaseSysCache(tuple);
 1157                         10519              27 :             continue;
                              10520                 :         }
                              10521                 : 
                              10522                 :         /*
                              10523                 :          * Because we're only expanding the key space at the referenced side,
                              10524                 :          * we don't need to prevent any operation in the referencing table, so
                              10525                 :          * AccessShareLock suffices (assumes that dropping the constraint
                              10526                 :          * acquires AEL).
                              10527                 :          */
 1467                         10528              60 :         fkRel = table_open(constrForm->conrelid, AccessShareLock);
                              10529                 : 
                              10530              60 :         indexOid = constrForm->conindid;
                              10531              60 :         DeconstructFkConstraintRow(tuple,
                              10532                 :                                    &numfks,
                              10533                 :                                    conkey,
                              10534                 :                                    confkey,
                              10535                 :                                    conpfeqop,
                              10536                 :                                    conppeqop,
                              10537                 :                                    conffeqop,
                              10538                 :                                    &numfkdelsetcols,
                              10539                 :                                    confdelsetcols);
                              10540                 : 
                              10541             120 :         for (int i = 0; i < numfks; i++)
 1208 michael                 10542              60 :             mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
                              10543                 : 
 1467 alvherre                10544              60 :         fkconstraint = makeNode(Constraint);
  157                         10545              60 :         fkconstraint->contype = CONSTRAINT_FOREIGN;
 1467                         10546              60 :         fkconstraint->conname = NameStr(constrForm->conname);
 1467 alvherre                10547 CBC          60 :         fkconstraint->deferrable = constrForm->condeferrable;
 1467 alvherre                10548 GIC          60 :         fkconstraint->initdeferred = constrForm->condeferred;
  157                         10549              60 :         fkconstraint->location = -1;
                              10550              60 :         fkconstraint->pktable = NULL;
                              10551                 :         /* ->fk_attrs determined below */
                              10552              60 :         fkconstraint->pk_attrs = NIL;
 1467                         10553              60 :         fkconstraint->fk_matchtype = constrForm->confmatchtype;
  157                         10554              60 :         fkconstraint->fk_upd_action = constrForm->confupdtype;
                              10555              60 :         fkconstraint->fk_del_action = constrForm->confdeltype;
                              10556              60 :         fkconstraint->fk_del_set_cols = NIL;
                              10557              60 :         fkconstraint->old_conpfeqop = NIL;
  157 alvherre                10558 CBC          60 :         fkconstraint->old_pktable_oid = InvalidOid;
  157 alvherre                10559 GIC          60 :         fkconstraint->skip_validation = false;
  157 alvherre                10560 CBC          60 :         fkconstraint->initially_valid = true;
 1467 alvherre                10561 EUB             : 
                              10562                 :         /* set up colnames that are used to generate the constraint name */
 1467 alvherre                10563 GIC         120 :         for (int i = 0; i < numfks; i++)
                              10564                 :         {
                              10565                 :             Form_pg_attribute att;
                              10566                 : 
                              10567              60 :             att = TupleDescAttr(RelationGetDescr(fkRel),
                              10568                 :                                 conkey[i] - 1);
                              10569              60 :             fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
                              10570              60 :                                              makeString(NameStr(att->attname)));
 1467 alvherre                10571 ECB             :         }
                              10572                 : 
                              10573                 :         /*
                              10574                 :          * Add the new foreign key constraint pointing to the new partition.
                              10575                 :          * Because this new partition appears in the referenced side of the
                              10576                 :          * constraint, we don't need to set up for Phase 3 check.
                              10577                 :          */
 1467 alvherre                10578 GIC          60 :         partIndexId = index_get_partition(partitionRel, indexOid);
 1467 alvherre                10579 CBC          60 :         if (!OidIsValid(partIndexId))
 1467 alvherre                10580 UIC           0 :             elog(ERROR, "index for %u not found in partition %s",
                              10581                 :                  indexOid, RelationGetRelationName(partitionRel));
                              10582                 : 
                              10583                 :         /*
                              10584                 :          * Get the "action" triggers belonging to the constraint to pass as
                              10585                 :          * parent OIDs for similar triggers that will be created on the
                              10586                 :          * partition in addFkRecurseReferenced().
                              10587                 :          */
  459 alvherre                10588 CBC          60 :         GetForeignKeyActionTriggers(trigrel, constrOid,
                              10589                 :                                     constrForm->confrelid, constrForm->conrelid,
                              10590                 :                                     &deleteTriggerOid, &updateTriggerOid);
                              10591                 : 
 1467 alvherre                10592 GIC          60 :         addFkRecurseReferenced(NULL,
 1467 alvherre                10593 ECB             :                                fkconstraint,
                              10594                 :                                fkRel,
                              10595                 :                                partitionRel,
                              10596                 :                                partIndexId,
                              10597                 :                                constrOid,
                              10598                 :                                numfks,
                              10599                 :                                mapped_confkey,
                              10600                 :                                conkey,
                              10601                 :                                conpfeqop,
                              10602                 :                                conppeqop,
                              10603                 :                                conffeqop,
                              10604                 :                                numfkdelsetcols,
                              10605                 :                                confdelsetcols,
  459                         10606                 :                                true,
                              10607                 :                                deleteTriggerOid,
                              10608                 :                                updateTriggerOid);
                              10609                 : 
 1467 alvherre                10610 GIC          60 :         table_close(fkRel, NoLock);
                              10611              60 :         ReleaseSysCache(tuple);
                              10612                 :     }
                              10613                 : 
  459                         10614            4312 :     table_close(trigrel, RowExclusiveLock);
 1542                         10615            4312 : }
                              10616                 : 
 1542 alvherre                10617 ECB             : /*
                              10618                 :  * CloneFkReferencing
                              10619                 :  *      Subroutine for CloneForeignKeyConstraints
                              10620                 :  *
                              10621                 :  * For each FK constraint of the parent relation in the given list, find an
                              10622                 :  * equivalent constraint in its partition relation that can be reparented;
                              10623                 :  * if one cannot be found, create a new constraint in the partition as its
 1467                         10624                 :  * child.
                              10625                 :  *
                              10626                 :  * If wqueue is given, it is used to set up phase-3 verification for each
                              10627                 :  * cloned constraint; if omitted, we assume that such verification is not
                              10628                 :  * needed (example: the partition is being created anew).
                              10629                 :  */
                              10630                 : static void
 1467 alvherre                10631 GIC        4312 : CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
                              10632                 : {
                              10633                 :     AttrMap    *attmap;
                              10634                 :     List       *partFKs;
                              10635            4312 :     List       *clone = NIL;
                              10636                 :     ListCell   *cell;
                              10637                 :     Relation    trigrel;
 1542 alvherre                10638 ECB             : 
                              10639                 :     /* obtain a list of constraints that we need to clone */
 1467 alvherre                10640 CBC        4720 :     foreach(cell, RelationGetFKeyList(parentRel))
                              10641                 :     {
 1467 alvherre                10642 GIC         408 :         ForeignKeyCacheInfo *fk = lfirst(cell);
 1467 alvherre                10643 ECB             : 
 1467 alvherre                10644 CBC         408 :         clone = lappend_oid(clone, fk->conoid);
                              10645                 :     }
                              10646                 : 
 1467 alvherre                10647 ECB             :     /*
                              10648                 :      * Silently do nothing if there's nothing to do.  In particular, this
                              10649                 :      * avoids throwing a spurious error for foreign tables.
                              10650                 :      */
 1467 alvherre                10651 GIC        4312 :     if (clone == NIL)
                              10652            4116 :         return;
 1467 alvherre                10653 ECB             : 
 1467 alvherre                10654 CBC         196 :     if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
 1467 alvherre                10655 UIC           0 :         ereport(ERROR,
                              10656                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              10657                 :                  errmsg("foreign key constraints are not supported on foreign tables")));
                              10658                 : 
                              10659                 :     /*
                              10660                 :      * Triggers of the foreign keys will be manipulated a bunch of times in
                              10661                 :      * the loop below.  To avoid repeatedly opening/closing the trigger
                              10662                 :      * catalog relation, we open it here and pass it to the subroutines called
                              10663                 :      * below.
                              10664                 :      */
  459 alvherre                10665 CBC         196 :     trigrel = table_open(TriggerRelationId, RowExclusiveLock);
  459 alvherre                10666 ECB             : 
                              10667                 :     /*
                              10668                 :      * The constraint key may differ, if the columns in the partition are
 1542                         10669                 :      * different.  This map is used to convert them.
                              10670                 :      */
 1208 michael                 10671 CBC         196 :     attmap = build_attrmap_by_name(RelationGetDescr(partRel),
                              10672                 :                                    RelationGetDescr(parentRel),
                              10673                 :                                    false);
                              10674                 : 
 1542 alvherre                10675 GIC         196 :     partFKs = copyObject(RelationGetFKeyList(partRel));
                              10676                 : 
                              10677             604 :     foreach(cell, clone)
                              10678                 :     {
 1542 alvherre                10679 CBC         408 :         Oid         parentConstrOid = lfirst_oid(cell);
                              10680                 :         Form_pg_constraint constrForm;
 1467 alvherre                10681 ECB             :         Relation    pkrel;
 1542 alvherre                10682 EUB             :         HeapTuple   tuple;
                              10683                 :         int         numfks;
                              10684                 :         AttrNumber  conkey[INDEX_MAX_KEYS];
                              10685                 :         AttrNumber  mapped_conkey[INDEX_MAX_KEYS];
                              10686                 :         AttrNumber  confkey[INDEX_MAX_KEYS];
 1542 alvherre                10687 ECB             :         Oid         conpfeqop[INDEX_MAX_KEYS];
                              10688                 :         Oid         conppeqop[INDEX_MAX_KEYS];
                              10689                 :         Oid         conffeqop[INDEX_MAX_KEYS];
  487 peter                   10690                 :         int         numfkdelsetcols;
                              10691                 :         AttrNumber  confdelsetcols[INDEX_MAX_KEYS];
 1542 alvherre                10692                 :         Constraint *fkconstraint;
 1467                         10693                 :         bool        attached;
                              10694                 :         Oid         indexOid;
                              10695                 :         Oid         constrOid;
                              10696                 :         ObjectAddress address,
                              10697                 :                     referenced;
                              10698                 :         ListCell   *lc;
                              10699                 :         Oid         insertTriggerOid,
                              10700                 :                     updateTriggerOid;
                              10701                 : 
 1542 alvherre                10702 GIC         408 :         tuple = SearchSysCache1(CONSTROID, parentConstrOid);
 1435 tgl                     10703             408 :         if (!HeapTupleIsValid(tuple))
 1542 alvherre                10704 UIC           0 :             elog(ERROR, "cache lookup failed for constraint %u",
                              10705                 :                  parentConstrOid);
 1542 alvherre                10706 GIC         408 :         constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              10707                 : 
 1467 alvherre                10708 ECB             :         /* Don't clone constraints whose parents are being cloned */
 1467 alvherre                10709 CBC         408 :         if (list_member_oid(clone, constrForm->conparentid))
                              10710                 :         {
 1542 alvherre                10711 GIC         200 :             ReleaseSysCache(tuple);
 1542 alvherre                10712 CBC         233 :             continue;
                              10713                 :         }
                              10714                 : 
                              10715                 :         /*
                              10716                 :          * Need to prevent concurrent deletions.  If pkrel is a partitioned
                              10717                 :          * relation, that means to lock all partitions.
                              10718                 :          */
 1467 alvherre                10719 GIC         208 :         pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
                              10720             208 :         if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              10721              86 :             (void) find_all_inheritors(RelationGetRelid(pkrel),
                              10722                 :                                        ShareRowExclusiveLock, NULL);
                              10723                 : 
 1542                         10724             208 :         DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
  487 peter                   10725 ECB             :                                    conpfeqop, conppeqop, conffeqop,
                              10726                 :                                    &numfkdelsetcols, confdelsetcols);
 1467 alvherre                10727 CBC         479 :         for (int i = 0; i < numfks; i++)
 1208 michael                 10728             271 :             mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
 1542 alvherre                10729 ECB             : 
                              10730                 :         /*
                              10731                 :          * Get the "check" triggers belonging to the constraint to pass as
  459                         10732                 :          * parent OIDs for similar triggers that will be created on the
                              10733                 :          * partition in addFkRecurseReferencing().  They are also passed to
                              10734                 :          * tryAttachPartitionForeignKey() below to simply assign as parents to
                              10735                 :          * the partition's existing "check" triggers, that is, if the
                              10736                 :          * corresponding constraints is deemed attachable to the parent
                              10737                 :          * constraint.
                              10738                 :          */
  459 alvherre                10739 GIC         208 :         GetForeignKeyCheckTriggers(trigrel, constrForm->oid,
                              10740                 :                                    constrForm->confrelid, constrForm->conrelid,
                              10741                 :                                    &insertTriggerOid, &updateTriggerOid);
                              10742                 : 
                              10743                 :         /*
                              10744                 :          * Before creating a new constraint, see whether any existing FKs are
                              10745                 :          * fit for the purpose.  If one is, attach the parent constraint to
                              10746                 :          * it, and don't clone anything.  This way we avoid the expensive
                              10747                 :          * verification step and don't end up with a duplicate FK, and we
                              10748                 :          * don't need to recurse to partitions for this constraint.
                              10749                 :          */
 1467                         10750             208 :         attached = false;
  186 drowley                 10751 GNC         250 :         foreach(lc, partFKs)
                              10752                 :         {
                              10753              75 :             ForeignKeyCacheInfo *fk = lfirst_node(ForeignKeyCacheInfo, lc);
 1542 alvherre                10754 ECB             : 
 1467 alvherre                10755 GIC          75 :             if (tryAttachPartitionForeignKey(fk,
 1467 alvherre                10756 ECB             :                                              RelationGetRelid(partRel),
                              10757                 :                                              parentConstrOid,
                              10758                 :                                              numfks,
                              10759                 :                                              mapped_conkey,
                              10760                 :                                              confkey,
                              10761                 :                                              conpfeqop,
                              10762                 :                                              insertTriggerOid,
                              10763                 :                                              updateTriggerOid,
                              10764                 :                                              trigrel))
                              10765                 :             {
 1467 alvherre                10766 GIC          33 :                 attached = true;
                              10767              33 :                 table_close(pkrel, NoLock);
                              10768              33 :                 break;
                              10769                 :             }
                              10770                 :         }
                              10771             208 :         if (attached)
 1542 alvherre                10772 ECB             :         {
 1542 alvherre                10773 GIC          33 :             ReleaseSysCache(tuple);
                              10774              33 :             continue;
                              10775                 :         }
 1542 alvherre                10776 ECB             : 
                              10777                 :         /* No dice.  Set up to create our own constraint */
 1467 alvherre                10778 GIC         175 :         fkconstraint = makeNode(Constraint);
  157                         10779             175 :         fkconstraint->contype = CONSTRAINT_FOREIGN;
                              10780                 :         /* ->conname determined below */
 1467 alvherre                10781 CBC         175 :         fkconstraint->deferrable = constrForm->condeferrable;
 1467 alvherre                10782 GIC         175 :         fkconstraint->initdeferred = constrForm->condeferred;
  157                         10783             175 :         fkconstraint->location = -1;
                              10784             175 :         fkconstraint->pktable = NULL;
                              10785                 :         /* ->fk_attrs determined below */
  157 alvherre                10786 CBC         175 :         fkconstraint->pk_attrs = NIL;
 1467                         10787             175 :         fkconstraint->fk_matchtype = constrForm->confmatchtype;
  157 alvherre                10788 GIC         175 :         fkconstraint->fk_upd_action = constrForm->confupdtype;
                              10789             175 :         fkconstraint->fk_del_action = constrForm->confdeltype;
                              10790             175 :         fkconstraint->fk_del_set_cols = NIL;
                              10791             175 :         fkconstraint->old_conpfeqop = NIL;
                              10792             175 :         fkconstraint->old_pktable_oid = InvalidOid;
                              10793             175 :         fkconstraint->skip_validation = false;
                              10794             175 :         fkconstraint->initially_valid = true;
 1467                         10795             389 :         for (int i = 0; i < numfks; i++)
                              10796                 :         {
                              10797                 :             Form_pg_attribute att;
                              10798                 : 
                              10799             214 :             att = TupleDescAttr(RelationGetDescr(partRel),
                              10800                 :                                 mapped_conkey[i] - 1);
                              10801             214 :             fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
                              10802             214 :                                              makeString(NameStr(att->attname)));
 1467 alvherre                10803 ECB             :         }
  213 alvherre                10804 GIC         175 :         if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
                              10805                 :                                  RelationGetRelid(partRel),
                              10806             175 :                                  NameStr(constrForm->conname)))
                              10807               3 :             fkconstraint->conname =
                              10808               3 :                 ChooseConstraintName(RelationGetRelationName(partRel),
                              10809               3 :                                      ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
                              10810                 :                                      "fkey",
  213 alvherre                10811 CBC           3 :                                      RelationGetNamespace(partRel), NIL);
                              10812                 :         else
  213 alvherre                10813 GIC         172 :             fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
                              10814                 : 
 1467                         10815             175 :         indexOid = constrForm->conindid;
                              10816                 :         constrOid =
                              10817             175 :             CreateConstraintEntry(fkconstraint->conname,
                              10818                 :                                   constrForm->connamespace,
                              10819                 :                                   CONSTRAINT_FOREIGN,
                              10820             175 :                                   fkconstraint->deferrable,
                              10821             175 :                                   fkconstraint->initdeferred,
 1542                         10822             175 :                                   constrForm->convalidated,
 1542 alvherre                10823 ECB             :                                   parentConstrOid,
                              10824                 :                                   RelationGetRelid(partRel),
                              10825                 :                                   mapped_conkey,
                              10826                 :                                   numfks,
                              10827                 :                                   numfks,
                              10828                 :                                   InvalidOid,   /* not a domain constraint */
                              10829                 :                                   indexOid,
                              10830                 :                                   constrForm->confrelid, /* same foreign rel */
                              10831                 :                                   confkey,
                              10832                 :                                   conpfeqop,
                              10833                 :                                   conppeqop,
                              10834                 :                                   conffeqop,
                              10835                 :                                   numfks,
 1467 alvherre                10836 GIC         175 :                                   fkconstraint->fk_upd_action,
 1467 alvherre                10837 CBC         175 :                                   fkconstraint->fk_del_action,
                              10838                 :                                   confdelsetcols,
  487 peter                   10839 ECB             :                                   numfkdelsetcols,
 1467 alvherre                10840 CBC         175 :                                   fkconstraint->fk_matchtype,
                              10841                 :                                   NULL,
                              10842                 :                                   NULL,
                              10843                 :                                   NULL,
                              10844                 :                                   false,    /* islocal */
                              10845                 :                                   1,    /* inhcount */
                              10846                 :                                   false,    /* conNoInherit */
                              10847                 :                                   true);
 1542 alvherre                10848 ECB             : 
                              10849                 :         /* Set up partition dependencies for the new constraint */
 1467 alvherre                10850 CBC         175 :         ObjectAddressSet(address, ConstraintRelationId, constrOid);
 1467 alvherre                10851 GIC         175 :         ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
                              10852             175 :         recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
 1467 alvherre                10853 CBC         175 :         ObjectAddressSet(referenced, RelationRelationId,
                              10854                 :                          RelationGetRelid(partRel));
                              10855             175 :         recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
                              10856                 : 
                              10857                 :         /* Done with the cloned constraint's tuple */
 1467 alvherre                10858 GIC         175 :         ReleaseSysCache(tuple);
                              10859                 : 
                              10860                 :         /* Make all this visible before recursing */
                              10861             175 :         CommandCounterIncrement();
                              10862                 : 
                              10863             175 :         addFkRecurseReferencing(wqueue,
                              10864                 :                                 fkconstraint,
                              10865                 :                                 partRel,
                              10866                 :                                 pkrel,
                              10867                 :                                 indexOid,
                              10868                 :                                 constrOid,
                              10869                 :                                 numfks,
                              10870                 :                                 confkey,
                              10871                 :                                 mapped_conkey,
                              10872                 :                                 conpfeqop,
 1467 alvherre                10873 ECB             :                                 conppeqop,
                              10874                 :                                 conffeqop,
  487 peter                   10875 EUB             :                                 numfkdelsetcols,
  487 peter                   10876 ECB             :                                 confdelsetcols,
                              10877                 :                                 false,  /* no old check exists */
                              10878                 :                                 AccessExclusiveLock,
                              10879                 :                                 insertTriggerOid,
                              10880                 :                                 updateTriggerOid);
 1467 alvherre                10881 GIC         175 :         table_close(pkrel, NoLock);
 1467 alvherre                10882 ECB             :     }
                              10883                 : 
  459 alvherre                10884 CBC         196 :     table_close(trigrel, RowExclusiveLock);
 1467 alvherre                10885 ECB             : }
                              10886                 : 
                              10887                 : /*
                              10888                 :  * When the parent of a partition receives [the referencing side of] a foreign
                              10889                 :  * key, we must propagate that foreign key to the partition.  However, the
                              10890                 :  * partition might already have an equivalent foreign key; this routine
                              10891                 :  * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined
                              10892                 :  * by the other parameters.  If they are equivalent, create the link between
                              10893                 :  * the two constraints and return true.
                              10894                 :  *
                              10895                 :  * If the given FK does not match the one defined by rest of the params,
                              10896                 :  * return false.
                              10897                 :  */
                              10898                 : static bool
 1467 alvherre                10899 GIC          90 : tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
                              10900                 :                              Oid partRelid,
                              10901                 :                              Oid parentConstrOid,
                              10902                 :                              int numfks,
                              10903                 :                              AttrNumber *mapped_conkey,
                              10904                 :                              AttrNumber *confkey,
  459 alvherre                10905 ECB             :                              Oid *conpfeqop,
                              10906                 :                              Oid parentInsTrigger,
                              10907                 :                              Oid parentUpdTrigger,
                              10908                 :                              Relation trigrel)
                              10909                 : {
                              10910                 :     HeapTuple   parentConstrTup;
                              10911                 :     Form_pg_constraint parentConstr;
                              10912                 :     HeapTuple   partcontup;
                              10913                 :     Form_pg_constraint partConstr;
                              10914                 :     ScanKeyData key;
                              10915                 :     SysScanDesc scan;
                              10916                 :     HeapTuple   trigtup;
                              10917                 :     Oid         insertTriggerOid,
                              10918                 :                 updateTriggerOid;
 1467                         10919                 : 
 1467 alvherre                10920 GIC          90 :     parentConstrTup = SearchSysCache1(CONSTROID,
 1467 alvherre                10921 ECB             :                                       ObjectIdGetDatum(parentConstrOid));
 1435 tgl                     10922 CBC          90 :     if (!HeapTupleIsValid(parentConstrTup))
 1467 alvherre                10923 LBC           0 :         elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
 1467 alvherre                10924 CBC          90 :     parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
 1542 alvherre                10925 ECB             : 
 1467                         10926                 :     /*
                              10927                 :      * Do some quick & easy initial checks.  If any of these fail, we cannot
                              10928                 :      * use this constraint.
                              10929                 :      */
 1467 alvherre                10930 CBC          90 :     if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks)
 1467 alvherre                10931 ECB             :     {
 1467 alvherre                10932 LBC           0 :         ReleaseSysCache(parentConstrTup);
                              10933               0 :         return false;
 1467 alvherre                10934 ECB             :     }
 1467 alvherre                10935 CBC         255 :     for (int i = 0; i < numfks; i++)
 1467 alvherre                10936 ECB             :     {
 1467 alvherre                10937 CBC         165 :         if (fk->conkey[i] != mapped_conkey[i] ||
 1467 alvherre                10938 GIC         165 :             fk->confkey[i] != confkey[i] ||
                              10939             165 :             fk->conpfeqop[i] != conpfeqop[i])
 1467 alvherre                10940 ECB             :         {
 1467 alvherre                10941 UIC           0 :             ReleaseSysCache(parentConstrTup);
                              10942               0 :             return false;
                              10943                 :         }
 1467 alvherre                10944 ECB             :     }
                              10945                 : 
                              10946                 :     /*
                              10947                 :      * Looks good so far; do some more extensive checks.  Presumably the check
                              10948                 :      * for 'convalidated' could be dropped, since we don't really care about
                              10949                 :      * that, but let's be careful for now.
                              10950                 :      */
 1467 alvherre                10951 GIC          90 :     partcontup = SearchSysCache1(CONSTROID,
                              10952                 :                                  ObjectIdGetDatum(fk->conoid));
 1435 tgl                     10953              90 :     if (!HeapTupleIsValid(partcontup))
 1435 tgl                     10954 UIC           0 :         elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
 1467 alvherre                10955 CBC          90 :     partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
                              10956              90 :     if (OidIsValid(partConstr->conparentid) ||
 1467 alvherre                10957 GBC          78 :         !partConstr->convalidated ||
 1467 alvherre                10958 GIC          78 :         partConstr->condeferrable != parentConstr->condeferrable ||
                              10959              64 :         partConstr->condeferred != parentConstr->condeferred ||
                              10960              64 :         partConstr->confupdtype != parentConstr->confupdtype ||
                              10961              46 :         partConstr->confdeltype != parentConstr->confdeltype ||
                              10962              46 :         partConstr->confmatchtype != parentConstr->confmatchtype)
                              10963                 :     {
                              10964              51 :         ReleaseSysCache(parentConstrTup);
 1467 alvherre                10965 CBC          51 :         ReleaseSysCache(partcontup);
 1467 alvherre                10966 GIC          51 :         return false;
                              10967                 :     }
                              10968                 : 
 1467 alvherre                10969 CBC          39 :     ReleaseSysCache(partcontup);
 1467 alvherre                10970 GIC          39 :     ReleaseSysCache(parentConstrTup);
                              10971                 : 
                              10972                 :     /*
                              10973                 :      * Looks good!  Attach this constraint.  The action triggers in the new
                              10974                 :      * partition become redundant -- the parent table already has equivalent
                              10975                 :      * ones, and those will be able to reach the partition.  Remove the ones
                              10976                 :      * in the partition.  We identify them because they have our constraint
                              10977                 :      * OID, as well as being on the referenced rel.
                              10978                 :      */
                              10979              39 :     ScanKeyInit(&key,
                              10980                 :                 Anum_pg_trigger_tgconstraint,
                              10981                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              10982                 :                 ObjectIdGetDatum(fk->conoid));
                              10983              39 :     scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
                              10984                 :                               NULL, 1, &key);
                              10985             195 :     while ((trigtup = systable_getnext(scan)) != NULL)
                              10986                 :     {
 1467 alvherre                10987 CBC         156 :         Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
 1467 alvherre                10988 ECB             :         ObjectAddress trigger;
                              10989                 : 
 1467 alvherre                10990 GIC         156 :         if (trgform->tgconstrrelid != fk->conrelid)
 1467 alvherre                10991 CBC          78 :             continue;
                              10992              78 :         if (trgform->tgrelid != fk->confrelid)
 1467 alvherre                10993 UIC           0 :             continue;
                              10994                 : 
                              10995                 :         /*
                              10996                 :          * The constraint is originally set up to contain this trigger as an
                              10997                 :          * implementation object, so there's a dependency record that links
                              10998                 :          * the two; however, since the trigger is no longer needed, we remove
                              10999                 :          * the dependency link in order to be able to drop the trigger while
                              11000                 :          * keeping the constraint intact.
                              11001                 :          */
 1467 alvherre                11002 GIC          78 :         deleteDependencyRecordsFor(TriggerRelationId,
                              11003                 :                                    trgform->oid,
                              11004                 :                                    false);
                              11005                 :         /* make dependency deletion visible to performDeletion */
                              11006              78 :         CommandCounterIncrement();
                              11007              78 :         ObjectAddressSet(trigger, TriggerRelationId,
 1467 alvherre                11008 ECB             :                          trgform->oid);
 1467 alvherre                11009 GIC          78 :         performDeletion(&trigger, DROP_RESTRICT, 0);
                              11010                 :         /* make trigger drop visible, in case the loop iterates */
                              11011              78 :         CommandCounterIncrement();
 1542 alvherre                11012 ECB             :     }
                              11013                 : 
 1467 alvherre                11014 GIC          39 :     systable_endscan(scan);
                              11015                 : 
                              11016              39 :     ConstraintSetParentConstraint(fk->conoid, parentConstrOid, partRelid);
  459 alvherre                11017 ECB             : 
                              11018                 :     /*
                              11019                 :      * Like the constraint, attach partition's "check" triggers to the
                              11020                 :      * corresponding parent triggers.
                              11021                 :      */
  459 alvherre                11022 GIC          39 :     GetForeignKeyCheckTriggers(trigrel,
                              11023                 :                                fk->conoid, fk->confrelid, fk->conrelid,
                              11024                 :                                &insertTriggerOid, &updateTriggerOid);
                              11025              39 :     Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger));
                              11026              39 :     TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger,
                              11027                 :                             partRelid);
  459 alvherre                11028 CBC          39 :     Assert(OidIsValid(updateTriggerOid) && OidIsValid(parentUpdTrigger));
                              11029              39 :     TriggerSetParentTrigger(trigrel, updateTriggerOid, parentUpdTrigger,
                              11030                 :                             partRelid);
  459 alvherre                11031 ECB             : 
 1467 alvherre                11032 GBC          39 :     CommandCounterIncrement();
 1467 alvherre                11033 GIC          39 :     return true;
                              11034                 : }
                              11035                 : 
                              11036                 : /*
                              11037                 :  * GetForeignKeyActionTriggers
                              11038                 :  *      Returns delete and update "action" triggers of the given relation
                              11039                 :  *      belonging to the given constraint
                              11040                 :  */
                              11041                 : static void
  459 alvherre                11042 CBC          60 : GetForeignKeyActionTriggers(Relation trigrel,
                              11043                 :                             Oid conoid, Oid confrelid, Oid conrelid,
                              11044                 :                             Oid *deleteTriggerOid,
                              11045                 :                             Oid *updateTriggerOid)
                              11046                 : {
                              11047                 :     ScanKeyData key;
  459 alvherre                11048 ECB             :     SysScanDesc scan;
                              11049                 :     HeapTuple   trigtup;
                              11050                 : 
  459 alvherre                11051 GIC          60 :     *deleteTriggerOid = *updateTriggerOid = InvalidOid;
  459 alvherre                11052 CBC          60 :     ScanKeyInit(&key,
                              11053                 :                 Anum_pg_trigger_tgconstraint,
  459 alvherre                11054 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              11055                 :                 ObjectIdGetDatum(conoid));
                              11056                 : 
  459 alvherre                11057 GIC          60 :     scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
                              11058                 :                               NULL, 1, &key);
                              11059             270 :     while ((trigtup = systable_getnext(scan)) != NULL)
                              11060                 :     {
                              11061             210 :         Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
                              11062                 : 
                              11063             210 :         if (trgform->tgconstrrelid != conrelid)
                              11064              90 :             continue;
                              11065             120 :         if (trgform->tgrelid != confrelid)
  459 alvherre                11066 UIC           0 :             continue;
                              11067                 :         /* Only ever look at "action" triggers on the PK side. */
  212 alvherre                11068 GIC         120 :         if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK)
  212 alvherre                11069 UIC           0 :             continue;
  459 alvherre                11070 GIC         120 :         if (TRIGGER_FOR_DELETE(trgform->tgtype))
                              11071                 :         {
                              11072              60 :             Assert(*deleteTriggerOid == InvalidOid);
                              11073              60 :             *deleteTriggerOid = trgform->oid;
                              11074                 :         }
                              11075              60 :         else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
                              11076                 :         {
                              11077              60 :             Assert(*updateTriggerOid == InvalidOid);
                              11078              60 :             *updateTriggerOid = trgform->oid;
  459 alvherre                11079 ECB             :         }
  212                         11080                 : #ifndef USE_ASSERT_CHECKING
  212 alvherre                11081 EUB             :         /* In an assert-enabled build, continue looking to find duplicates */
                              11082                 :         if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid))
  459 alvherre                11083 ECB             :             break;
                              11084                 : #endif
                              11085                 :     }
                              11086                 : 
  459 alvherre                11087 GIC          60 :     if (!OidIsValid(*deleteTriggerOid))
  459 alvherre                11088 LBC           0 :         elog(ERROR, "could not find ON DELETE action trigger of foreign key constraint %u",
  459 alvherre                11089 ECB             :              conoid);
  459 alvherre                11090 GIC          60 :     if (!OidIsValid(*updateTriggerOid))
  459 alvherre                11091 UIC           0 :         elog(ERROR, "could not find ON UPDATE action trigger of foreign key constraint %u",
                              11092                 :              conoid);
                              11093                 : 
  459 alvherre                11094 GIC          60 :     systable_endscan(scan);
                              11095              60 : }
  459 alvherre                11096 ECB             : 
                              11097                 : /*
                              11098                 :  * GetForeignKeyCheckTriggers
                              11099                 :  *      Returns insert and update "check" triggers of the given relation
                              11100                 :  *      belonging to the given constraint
                              11101                 :  */
                              11102                 : static void
  459 alvherre                11103 GIC         277 : GetForeignKeyCheckTriggers(Relation trigrel,
  459 alvherre                11104 ECB             :                            Oid conoid, Oid confrelid, Oid conrelid,
                              11105                 :                            Oid *insertTriggerOid,
                              11106                 :                            Oid *updateTriggerOid)
                              11107                 : {
                              11108                 :     ScanKeyData key;
                              11109                 :     SysScanDesc scan;
                              11110                 :     HeapTuple   trigtup;
                              11111                 : 
  459 alvherre                11112 GIC         277 :     *insertTriggerOid = *updateTriggerOid = InvalidOid;
                              11113             277 :     ScanKeyInit(&key,
                              11114                 :                 Anum_pg_trigger_tgconstraint,
                              11115                 :                 BTEqualStrategyNumber, F_OIDEQ,
  459 alvherre                11116 ECB             :                 ObjectIdGetDatum(conoid));
                              11117                 : 
  459 alvherre                11118 GIC         277 :     scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
                              11119                 :                               NULL, 1, &key);
                              11120            1199 :     while ((trigtup = systable_getnext(scan)) != NULL)
                              11121                 :     {
                              11122             922 :         Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
                              11123                 : 
                              11124             922 :         if (trgform->tgconstrrelid != confrelid)
                              11125             326 :             continue;
                              11126             596 :         if (trgform->tgrelid != conrelid)
  459 alvherre                11127 LBC           0 :             continue;
  212 alvherre                11128 ECB             :         /* Only ever look at "check" triggers on the FK side. */
  212 alvherre                11129 GIC         596 :         if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK)
  212 alvherre                11130 CBC          42 :             continue;
  459 alvherre                11131 GIC         554 :         if (TRIGGER_FOR_INSERT(trgform->tgtype))
  459 alvherre                11132 ECB             :         {
  459 alvherre                11133 GIC         277 :             Assert(*insertTriggerOid == InvalidOid);
                              11134             277 :             *insertTriggerOid = trgform->oid;
                              11135                 :         }
                              11136             277 :         else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
                              11137                 :         {
                              11138             277 :             Assert(*updateTriggerOid == InvalidOid);
                              11139             277 :             *updateTriggerOid = trgform->oid;
                              11140                 :         }
                              11141                 : #ifndef USE_ASSERT_CHECKING
                              11142                 :         /* In an assert-enabled build, continue looking to find duplicates. */
  459 alvherre                11143 ECB             :         if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid))
                              11144                 :             break;
  212                         11145                 : #endif
                              11146                 :     }
                              11147                 : 
  459 alvherre                11148 CBC         277 :     if (!OidIsValid(*insertTriggerOid))
  459 alvherre                11149 UIC           0 :         elog(ERROR, "could not find ON INSERT check triggers of foreign key constraint %u",
  459 alvherre                11150 ECB             :              conoid);
  459 alvherre                11151 CBC         277 :     if (!OidIsValid(*updateTriggerOid))
  459 alvherre                11152 UIC           0 :         elog(ERROR, "could not find ON UPDATE check triggers of foreign key constraint %u",
                              11153                 :              conoid);
                              11154                 : 
  459 alvherre                11155 CBC         277 :     systable_endscan(scan);
                              11156             277 : }
                              11157                 : 
 3571 simon                   11158 ECB             : /*
                              11159                 :  * ALTER TABLE ALTER CONSTRAINT
                              11160                 :  *
                              11161                 :  * Update the attributes of a constraint.
                              11162                 :  *
                              11163                 :  * Currently only works for Foreign Key constraints.
 2937 alvherre                11164                 :  *
                              11165                 :  * If the constraint is modified, returns its address; otherwise, return
                              11166                 :  * InvalidObjectAddress.
 3571 simon                   11167                 :  */
 2937 alvherre                11168                 : static ObjectAddress
  704 alvherre                11169 CBC          33 : ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
  704 alvherre                11170 ECB             :                       bool recursing, LOCKMODE lockmode)
 3571 simon                   11171                 : {
 2898 tgl                     11172                 :     Constraint *cmdcon;
                              11173                 :     Relation    conrel;
                              11174                 :     Relation    tgrel;
                              11175                 :     SysScanDesc scan;
 1678                         11176                 :     ScanKeyData skey[3];
                              11177                 :     HeapTuple   contuple;
                              11178                 :     Form_pg_constraint currcon;
 2937 alvherre                11179                 :     ObjectAddress address;
  704 alvherre                11180 GIC          33 :     List       *otherrelids = NIL;
  704 alvherre                11181 ECB             :     ListCell   *lc;
                              11182                 : 
 2264 andres                  11183 CBC          33 :     cmdcon = castNode(Constraint, cmd->def);
 3571 simon                   11184 ECB             : 
 1539 andres                  11185 CBC          33 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
  704 alvherre                11186              33 :     tgrel = table_open(TriggerRelationId, RowExclusiveLock);
                              11187                 : 
 3571 simon                   11188 ECB             :     /*
                              11189                 :      * Find and check the target constraint
                              11190                 :      */
 1678 tgl                     11191 GIC          33 :     ScanKeyInit(&skey[0],
 3571 simon                   11192 ECB             :                 Anum_pg_constraint_conrelid,
                              11193                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              11194                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
 1678 tgl                     11195 GIC          33 :     ScanKeyInit(&skey[1],
                              11196                 :                 Anum_pg_constraint_contypid,
 1678 tgl                     11197 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              11198                 :                 ObjectIdGetDatum(InvalidOid));
 1678 tgl                     11199 CBC          33 :     ScanKeyInit(&skey[2],
                              11200                 :                 Anum_pg_constraint_conname,
                              11201                 :                 BTEqualStrategyNumber, F_NAMEEQ,
 1678 tgl                     11202 GIC          33 :                 CStringGetDatum(cmdcon->conname));
                              11203              33 :     scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
                              11204                 :                               true, NULL, 3, skey);
                              11205                 : 
                              11206                 :     /* There can be at most one matching row */
                              11207              33 :     if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
 3571 simon                   11208 UIC           0 :         ereport(ERROR,
                              11209                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              11210                 :                  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
                              11211                 :                         cmdcon->conname, RelationGetRelationName(rel))));
                              11212                 : 
 1678 tgl                     11213 CBC          33 :     currcon = (Form_pg_constraint) GETSTRUCT(contuple);
 3571 simon                   11214              33 :     if (currcon->contype != CONSTRAINT_FOREIGN)
 3571 simon                   11215 UIC           0 :         ereport(ERROR,
                              11216                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 3571 simon                   11217 ECB             :                  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
                              11218                 :                         cmdcon->conname, RelationGetRelationName(rel))));
                              11219                 : 
                              11220                 :     /*
                              11221                 :      * If it's not the topmost constraint, raise an error.
                              11222                 :      *
                              11223                 :      * Altering a non-topmost constraint leaves some triggers untouched, since
                              11224                 :      * they are not directly connected to this constraint; also, pg_dump would
                              11225                 :      * ignore the deferrability status of the individual constraint, since it
                              11226                 :      * only dumps topmost constraints.  Avoid these problems by refusing this
  704 alvherre                11227                 :      * operation and telling the user to alter the parent constraint instead.
                              11228                 :      */
  704 alvherre                11229 CBC          33 :     if (OidIsValid(currcon->conparentid))
  704 alvherre                11230 ECB             :     {
                              11231                 :         HeapTuple   tp;
  704 alvherre                11232 CBC           6 :         Oid         parent = currcon->conparentid;
  704 alvherre                11233 GIC           6 :         char       *ancestorname = NULL;
                              11234               6 :         char       *ancestortable = NULL;
  704 alvherre                11235 ECB             : 
                              11236                 :         /* Loop to find the topmost constraint */
  704 alvherre                11237 GIC          12 :         while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
  704 alvherre                11238 ECB             :         {
  704 alvherre                11239 GIC          12 :             Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
  704 alvherre                11240 ECB             : 
                              11241                 :             /* If no parent, this is the constraint we want */
  704 alvherre                11242 GIC          12 :             if (!OidIsValid(contup->conparentid))
                              11243                 :             {
                              11244               6 :                 ancestorname = pstrdup(NameStr(contup->conname));
                              11245               6 :                 ancestortable = get_rel_name(contup->conrelid);
                              11246               6 :                 ReleaseSysCache(tp);
                              11247               6 :                 break;
                              11248                 :             }
                              11249                 : 
                              11250               6 :             parent = contup->conparentid;
                              11251               6 :             ReleaseSysCache(tp);
                              11252                 :         }
                              11253                 : 
                              11254               6 :         ereport(ERROR,
                              11255                 :                 (errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
                              11256                 :                         cmdcon->conname, RelationGetRelationName(rel)),
                              11257                 :                  ancestorname && ancestortable ?
  704 alvherre                11258 ECB             :                  errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
                              11259                 :                            cmdcon->conname, ancestorname, ancestortable) : 0,
                              11260                 :                  errhint("You may alter the constraint it derives from, instead.")));
                              11261                 :     }
                              11262                 : 
                              11263                 :     /*
                              11264                 :      * Do the actual catalog work.  We can skip changing if already in the
                              11265                 :      * desired state, but not if a partitioned table: partitions need to be
                              11266                 :      * processed regardless, in case they had the constraint locally changed.
                              11267                 :      */
  704 alvherre                11268 GIC          27 :     address = InvalidObjectAddress;
                              11269              27 :     if (currcon->condeferrable != cmdcon->deferrable ||
                              11270               3 :         currcon->condeferred != cmdcon->initdeferred ||
  704 alvherre                11271 UIC           0 :         rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              11272                 :     {
  704 alvherre                11273 GIC          27 :         if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
                              11274                 :                                      &otherrelids, lockmode))
                              11275              27 :             ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
  704 alvherre                11276 ECB             :     }
                              11277                 : 
                              11278                 :     /*
                              11279                 :      * ATExecConstrRecurse already invalidated relcache for the relations
                              11280                 :      * having the constraint itself; here we also invalidate for relations
                              11281                 :      * that have any triggers that are part of the constraint.
                              11282                 :      */
  704 alvherre                11283 GIC          69 :     foreach(lc, otherrelids)
                              11284              42 :         CacheInvalidateRelcacheByRelid(lfirst_oid(lc));
                              11285                 : 
                              11286              27 :     systable_endscan(scan);
                              11287                 : 
                              11288              27 :     table_close(tgrel, RowExclusiveLock);
                              11289              27 :     table_close(conrel, RowExclusiveLock);
                              11290                 : 
                              11291              27 :     return address;
                              11292                 : }
                              11293                 : 
                              11294                 : /*
                              11295                 :  * Recursive subroutine of ATExecAlterConstraint.  Returns true if the
                              11296                 :  * constraint is altered.
  704 alvherre                11297 ECB             :  *
                              11298                 :  * *otherrelids is appended OIDs of relations containing affected triggers.
                              11299                 :  *
  704 alvherre                11300 EUB             :  * Note that we must recurse even when the values are correct, in case
  704 alvherre                11301 ECB             :  * indirect descendants have had their constraints altered locally.
                              11302                 :  * (This could be avoided if we forbade altering constraints in partitions
                              11303                 :  * but existing releases don't do that.)
                              11304                 :  */
                              11305                 : static bool
  704 alvherre                11306 GIC          60 : ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
  704 alvherre                11307 ECB             :                          Relation rel, HeapTuple contuple, List **otherrelids,
                              11308                 :                          LOCKMODE lockmode)
  704 alvherre                11309 EUB             : {
                              11310                 :     Form_pg_constraint currcon;
                              11311                 :     Oid         conoid;
  704 alvherre                11312 ECB             :     Oid         refrelid;
  704 alvherre                11313 GIC          60 :     bool        changed = false;
  704 alvherre                11314 ECB             : 
  704 alvherre                11315 CBC          60 :     currcon = (Form_pg_constraint) GETSTRUCT(contuple);
                              11316              60 :     conoid = currcon->oid;
  704 alvherre                11317 GIC          60 :     refrelid = currcon->confrelid;
  704 alvherre                11318 EUB             : 
                              11319                 :     /*
                              11320                 :      * Update pg_constraint with the flags from cmdcon.
                              11321                 :      *
                              11322                 :      * If called to modify a constraint that's already in the desired state,
                              11323                 :      * silently do nothing.
                              11324                 :      */
 3571 simon                   11325 GIC          60 :     if (currcon->condeferrable != cmdcon->deferrable ||
                              11326               3 :         currcon->condeferred != cmdcon->initdeferred)
                              11327                 :     {
 3571 simon                   11328 ECB             :         HeapTuple   copyTuple;
                              11329                 :         Form_pg_constraint copy_con;
  704 alvherre                11330                 :         HeapTuple   tgtuple;
 3571 simon                   11331 EUB             :         ScanKeyData tgkey;
 3571 simon                   11332 ECB             :         SysScanDesc tgscan;
                              11333                 : 
 3571 simon                   11334 CBC          60 :         copyTuple = heap_copytuple(contuple);
                              11335              60 :         copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
                              11336              60 :         copy_con->condeferrable = cmdcon->deferrable;
                              11337              60 :         copy_con->condeferred = cmdcon->initdeferred;
 2259 alvherre                11338              60 :         CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
 3571 simon                   11339 ECB             : 
 3571 simon                   11340 GIC          60 :         InvokeObjectPostAlterHook(ConstraintRelationId,
  704 alvherre                11341 ECB             :                                   conoid, 0);
 3571 simon                   11342                 : 
 3571 simon                   11343 CBC          60 :         heap_freetuple(copyTuple);
  704 alvherre                11344 GIC          60 :         changed = true;
                              11345                 : 
  704 alvherre                11346 ECB             :         /* Make new constraint flags visible to others */
  704 alvherre                11347 CBC          60 :         CacheInvalidateRelcache(rel);
                              11348                 : 
                              11349                 :         /*
                              11350                 :          * Now we need to update the multiple entries in pg_trigger that
                              11351                 :          * implement the constraint.
                              11352                 :          */
 3571 simon                   11353 GIC          60 :         ScanKeyInit(&tgkey,
                              11354                 :                     Anum_pg_trigger_tgconstraint,
                              11355                 :                     BTEqualStrategyNumber, F_OIDEQ,
  704 alvherre                11356 ECB             :                     ObjectIdGetDatum(conoid));
 3571 simon                   11357 GIC          60 :         tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
                              11358                 :                                     NULL, 1, &tgkey);
                              11359             234 :         while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
 3571 simon                   11360 ECB             :         {
 2356 tgl                     11361 GIC         174 :             Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
 2898 tgl                     11362 ECB             :             Form_pg_trigger copy_tg;
                              11363                 :             HeapTuple   tgCopyTuple;
                              11364                 : 
                              11365                 :             /*
                              11366                 :              * Remember OIDs of other relation(s) involved in FK constraint.
 2356                         11367                 :              * (Note: it's likely that we could skip forcing a relcache inval
                              11368                 :              * for other rels that don't have a trigger whose properties
                              11369                 :              * change, but let's be conservative.)
 2356 tgl                     11370 EUB             :              */
 2356 tgl                     11371 GIC         174 :             if (tgform->tgrelid != RelationGetRelid(rel))
  704 alvherre                11372              84 :                 *otherrelids = list_append_unique_oid(*otherrelids,
                              11373                 :                                                       tgform->tgrelid);
                              11374                 : 
                              11375                 :             /*
                              11376                 :              * Update deferrability of RI_FKey_noaction_del,
                              11377                 :              * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
                              11378                 :              * triggers, but not others; see createForeignKeyActionTriggers
 1467 alvherre                11379 ECB             :              * and CreateFKCheckTrigger.
                              11380                 :              */
 2356 tgl                     11381 GIC         174 :             if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
                              11382             141 :                 tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
 2356 tgl                     11383 CBC          99 :                 tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
                              11384              54 :                 tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
 2356 tgl                     11385 GIC           9 :                 continue;
 2356 tgl                     11386 ECB             : 
  186 drowley                 11387 GNC         165 :             tgCopyTuple = heap_copytuple(tgtuple);
                              11388             165 :             copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple);
                              11389                 : 
 3571 simon                   11390 GIC         165 :             copy_tg->tgdeferrable = cmdcon->deferrable;
 3571 simon                   11391 CBC         165 :             copy_tg->tginitdeferred = cmdcon->initdeferred;
  186 drowley                 11392 GNC         165 :             CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple);
 3571 simon                   11393 ECB             : 
  705 alvherre                11394 GIC         165 :             InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
                              11395                 : 
  186 drowley                 11396 GNC         165 :             heap_freetuple(tgCopyTuple);
                              11397                 :         }
                              11398                 : 
 3571 simon                   11399 CBC          60 :         systable_endscan(tgscan);
                              11400                 :     }
                              11401                 : 
  704 alvherre                11402 ECB             :     /*
                              11403                 :      * If the table at either end of the constraint is partitioned, we need to
                              11404                 :      * recurse and handle every constraint that is a child of this one.
                              11405                 :      *
                              11406                 :      * (This assumes that the recurse flag is forcibly set for partitioned
                              11407                 :      * tables, and not set for legacy inheritance, though we don't check for
                              11408                 :      * that here.)
                              11409                 :      */
  704 alvherre                11410 CBC         108 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
  704 alvherre                11411 GIC          48 :         get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
                              11412                 :     {
                              11413                 :         ScanKeyData pkey;
                              11414                 :         SysScanDesc pscan;
                              11415                 :         HeapTuple   childtup;
                              11416                 : 
                              11417              21 :         ScanKeyInit(&pkey,
                              11418                 :                     Anum_pg_constraint_conparentid,
  704 alvherre                11419 ECB             :                     BTEqualStrategyNumber, F_OIDEQ,
                              11420                 :                     ObjectIdGetDatum(conoid));
                              11421                 : 
  704 alvherre                11422 GIC          21 :         pscan = systable_beginscan(conrel, ConstraintParentIndexId,
                              11423                 :                                    true, NULL, 1, &pkey);
                              11424                 : 
                              11425              54 :         while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
                              11426                 :         {
                              11427              33 :             Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
  704 alvherre                11428 ECB             :             Relation    childrel;
                              11429                 : 
  704 alvherre                11430 GIC          33 :             childrel = table_open(childcon->conrelid, lockmode);
                              11431              33 :             ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
                              11432                 :                                      otherrelids, lockmode);
                              11433              33 :             table_close(childrel, NoLock);
 2898 tgl                     11434 ECB             :         }
                              11435                 : 
  704 alvherre                11436 CBC          21 :         systable_endscan(pscan);
                              11437                 :     }
 3571 simon                   11438 ECB             : 
  704 alvherre                11439 GIC          60 :     return changed;
 3571 simon                   11440 ECB             : }
                              11441                 : 
 4443                         11442                 : /*
 4443 simon                   11443 EUB             :  * ALTER TABLE VALIDATE CONSTRAINT
                              11444                 :  *
 4330 alvherre                11445 ECB             :  * XXX The reason we handle recursion here rather than at Phase 1 is because
 4330 alvherre                11446 EUB             :  * there's no good way to skip recursing when handling foreign keys: there is
 4330 alvherre                11447 ECB             :  * no need to lock children in that case, yet we wouldn't be able to avoid
                              11448                 :  * doing so at that level.
 2937                         11449                 :  *
                              11450                 :  * Return value is the address of the validated constraint.  If the constraint
                              11451                 :  * was already validated, InvalidObjectAddress is returned.
 4443 simon                   11452                 :  */
                              11453                 : static ObjectAddress
  999 drowley                 11454 CBC         218 : ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
  999 drowley                 11455 ECB             :                          bool recurse, bool recursing, LOCKMODE lockmode)
                              11456                 : {
                              11457                 :     Relation    conrel;
                              11458                 :     SysScanDesc scan;
                              11459                 :     ScanKeyData skey[3];
                              11460                 :     HeapTuple   tuple;
                              11461                 :     Form_pg_constraint con;
                              11462                 :     ObjectAddress address;
                              11463                 : 
 1539 andres                  11464 CBC         218 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
 4443 simon                   11465 EUB             : 
                              11466                 :     /*
 4443 tgl                     11467 ECB             :      * Find and check the target constraint
 4443 simon                   11468 EUB             :      */
 1678 tgl                     11469 GIC         218 :     ScanKeyInit(&skey[0],
                              11470                 :                 Anum_pg_constraint_conrelid,
 4443 simon                   11471 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              11472                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
 1678 tgl                     11473 GIC         218 :     ScanKeyInit(&skey[1],
                              11474                 :                 Anum_pg_constraint_contypid,
                              11475                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              11476                 :                 ObjectIdGetDatum(InvalidOid));
                              11477             218 :     ScanKeyInit(&skey[2],
                              11478                 :                 Anum_pg_constraint_conname,
                              11479                 :                 BTEqualStrategyNumber, F_NAMEEQ,
 1678 tgl                     11480 ECB             :                 CStringGetDatum(constrName));
 1678 tgl                     11481 GIC         218 :     scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
                              11482                 :                               true, NULL, 3, skey);
                              11483                 : 
                              11484                 :     /* There can be at most one matching row */
                              11485             218 :     if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
 4443 tgl                     11486 UIC           0 :         ereport(ERROR,
                              11487                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              11488                 :                  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
 4330 alvherre                11489 ECB             :                         constrName, RelationGetRelationName(rel))));
                              11490                 : 
 1678 tgl                     11491 GIC         218 :     con = (Form_pg_constraint) GETSTRUCT(tuple);
 4330 alvherre                11492             218 :     if (con->contype != CONSTRAINT_FOREIGN &&
                              11493              66 :         con->contype != CONSTRAINT_CHECK)
 4330 alvherre                11494 UIC           0 :         ereport(ERROR,
 4330 alvherre                11495 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              11496                 :                  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
 4382 bruce                   11497                 :                         constrName, RelationGetRelationName(rel))));
                              11498                 : 
 4443 tgl                     11499 CBC         218 :     if (!con->convalidated)
                              11500                 :     {
  999 drowley                 11501 ECB             :         AlteredTableInfo *tab;
 4330 alvherre                11502                 :         HeapTuple   copyTuple;
                              11503                 :         Form_pg_constraint copy_con;
 4443 simon                   11504 EUB             : 
 4330 alvherre                11505 GIC         209 :         if (con->contype == CONSTRAINT_FOREIGN)
 4330 alvherre                11506 ECB             :         {
  999 drowley                 11507                 :             NewConstraint *newcon;
                              11508                 :             Constraint *fkconstraint;
                              11509                 : 
                              11510                 :             /* Queue validation for phase 3 */
  999 drowley                 11511 CBC         149 :             fkconstraint = makeNode(Constraint);
                              11512                 :             /* for now this is all we need */
                              11513             149 :             fkconstraint->conname = constrName;
                              11514                 : 
                              11515             149 :             newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
                              11516             149 :             newcon->name = constrName;
  999 drowley                 11517 GIC         149 :             newcon->contype = CONSTR_FOREIGN;
                              11518             149 :             newcon->refrelid = con->confrelid;
                              11519             149 :             newcon->refindid = con->conindid;
                              11520             149 :             newcon->conid = con->oid;
                              11521             149 :             newcon->qual = (Node *) fkconstraint;
                              11522                 : 
                              11523                 :             /* Find or create work queue entry for this table */
                              11524             149 :             tab = ATGetQueueEntry(wqueue, rel);
  999 drowley                 11525 CBC         149 :             tab->constraints = lappend(tab->constraints, newcon);
 4330 alvherre                11526 EUB             : 
                              11527                 :             /*
 1831 alvherre                11528 ECB             :              * We disallow creating invalid foreign keys to or from
 1831 alvherre                11529 EUB             :              * partitioned tables, so ignoring the recursion bit is okay.
                              11530                 :              */
                              11531                 :         }
 4330 alvherre                11532 CBC          60 :         else if (con->contype == CONSTRAINT_CHECK)
 4330 alvherre                11533 ECB             :         {
 4330 alvherre                11534 GIC          60 :             List       *children = NIL;
                              11535                 :             ListCell   *child;
                              11536                 :             NewConstraint *newcon;
                              11537                 :             Datum       val;
                              11538                 :             char       *conbin;
                              11539                 : 
                              11540                 :             /*
                              11541                 :              * If we're recursing, the parent has already done this, so skip
                              11542                 :              * it.  Also, if the constraint is a NO INHERIT constraint, we
                              11543                 :              * shouldn't try to look for it in the children.
                              11544                 :              */
 2172 rhaas                   11545 CBC          60 :             if (!recursing && !con->connoinherit)
 4330 alvherre                11546 GIC          33 :                 children = find_all_inheritors(RelationGetRelid(rel),
                              11547                 :                                                lockmode, NULL);
                              11548                 : 
                              11549                 :             /*
                              11550                 :              * For CHECK constraints, we must ensure that we only mark the
                              11551                 :              * constraint as validated on the parent if it's already validated
                              11552                 :              * on the children.
                              11553                 :              *
                              11554                 :              * We recurse before validating on the parent, to reduce risk of
                              11555                 :              * deadlocks.
 4330 alvherre                11556 ECB             :              */
 4330 alvherre                11557 GIC         117 :             foreach(child, children)
                              11558                 :             {
 3955 bruce                   11559 CBC          57 :                 Oid         childoid = lfirst_oid(child);
                              11560                 :                 Relation    childrel;
 4443 simon                   11561 ECB             : 
 4330 alvherre                11562 CBC          57 :                 if (childoid == RelationGetRelid(rel))
 4330 alvherre                11563 GIC          33 :                     continue;
                              11564                 : 
                              11565                 :                 /*
                              11566                 :                  * If we are told not to recurse, there had better not be any
 2397 rhaas                   11567 ECB             :                  * child tables, because we can't mark the constraint on the
                              11568                 :                  * parent valid unless it is valid for all child tables.
                              11569                 :                  */
 4330 alvherre                11570 GIC          24 :                 if (!recurse)
 4330 alvherre                11571 LBC           0 :                     ereport(ERROR,
                              11572                 :                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              11573                 :                              errmsg("constraint must be validated on child tables too")));
                              11574                 : 
 4330 alvherre                11575 ECB             :                 /* find_all_inheritors already got lock */
 1539 andres                  11576 GIC          24 :                 childrel = table_open(childoid, NoLock);
                              11577                 : 
  999 drowley                 11578 CBC          24 :                 ATExecValidateConstraint(wqueue, childrel, constrName, false,
 4330 alvherre                11579 ECB             :                                          true, lockmode);
 1539 andres                  11580 GIC          24 :                 table_close(childrel, NoLock);
                              11581                 :             }
                              11582                 : 
  999 drowley                 11583 ECB             :             /* Queue validation for phase 3 */
  999 drowley                 11584 GBC          60 :             newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
  999 drowley                 11585 GIC          60 :             newcon->name = constrName;
                              11586              60 :             newcon->contype = CONSTR_CHECK;
                              11587              60 :             newcon->refrelid = InvalidOid;
                              11588              60 :             newcon->refindid = InvalidOid;
  999 drowley                 11589 CBC          60 :             newcon->conid = con->oid;
  999 drowley                 11590 ECB             : 
   15 dgustafsson             11591 GNC          60 :             val = SysCacheGetAttrNotNull(CONSTROID, tuple,
                              11592                 :                                          Anum_pg_constraint_conbin);
  999 drowley                 11593 GIC          60 :             conbin = TextDatumGetCString(val);
                              11594              60 :             newcon->qual = (Node *) stringToNode(conbin);
                              11595                 : 
                              11596                 :             /* Find or create work queue entry for this table */
                              11597              60 :             tab = ATGetQueueEntry(wqueue, rel);
                              11598              60 :             tab->constraints = lappend(tab->constraints, newcon);
                              11599                 : 
                              11600                 :             /*
                              11601                 :              * Invalidate relcache so that others see the new validated
 4330 alvherre                11602 ECB             :              * constraint.
                              11603                 :              */
 4330 alvherre                11604 GIC          60 :             CacheInvalidateRelcache(rel);
 4330 alvherre                11605 ECB             :         }
 4443 simon                   11606                 : 
                              11607                 :         /*
                              11608                 :          * Now update the catalog, while we have the door open.
                              11609                 :          */
 4330 alvherre                11610 CBC         209 :         copyTuple = heap_copytuple(tuple);
 4330 alvherre                11611 GIC         209 :         copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
 4443 simon                   11612 CBC         209 :         copy_con->convalidated = true;
 2259 alvherre                11613 GIC         209 :         CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
                              11614                 : 
 1601 andres                  11615 CBC         209 :         InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
                              11616                 : 
 4443 simon                   11617             209 :         heap_freetuple(copyTuple);
 2937 alvherre                11618 ECB             : 
 1601 andres                  11619 CBC         209 :         ObjectAddressSet(address, ConstraintRelationId, con->oid);
 4443 simon                   11620 ECB             :     }
                              11621                 :     else
 2878 bruce                   11622 GIC           9 :         address = InvalidObjectAddress; /* already validated */
 4443 simon                   11623 ECB             : 
 4443 simon                   11624 CBC         218 :     systable_endscan(scan);
                              11625                 : 
 1539 andres                  11626 GIC         218 :     table_close(conrel, RowExclusiveLock);
 2937 alvherre                11627 ECB             : 
 2937 alvherre                11628 GIC         218 :     return address;
                              11629                 : }
                              11630                 : 
                              11631                 : 
                              11632                 : /*
                              11633                 :  * transformColumnNameList - transform list of column names
                              11634                 :  *
                              11635                 :  * Lookup each name and return its attnum and, optionally, type OID
                              11636                 :  *
                              11637                 :  * Note: the name of this function suggests that it's general-purpose,
                              11638                 :  * but actually it's only used to look up names appearing in foreign-key
                              11639                 :  * clauses.  The error messages would need work to use it in other cases,
                              11640                 :  * and perhaps the validity checks as well.
 7504 tgl                     11641 ECB             :  */
                              11642                 : static int
 7504 tgl                     11643 CBC        2584 : transformColumnNameList(Oid relId, List *colList,
 7504 tgl                     11644 EUB             :                         int16 *attnums, Oid *atttypids)
                              11645                 : {
 6892 neilc                   11646 ECB             :     ListCell   *l;
                              11647                 :     int         attnum;
 7504 tgl                     11648                 : 
 7504 tgl                     11649 GIC        2584 :     attnum = 0;
                              11650            4548 :     foreach(l, colList)
                              11651                 :     {
                              11652            1997 :         char       *attname = strVal(lfirst(l));
                              11653                 :         HeapTuple   atttuple;
                              11654                 :         Form_pg_attribute attform;
                              11655                 : 
 7504 tgl                     11656 CBC        1997 :         atttuple = SearchSysCacheAttName(relId, attname);
                              11657            1997 :         if (!HeapTupleIsValid(atttuple))
 7203 tgl                     11658 GIC          27 :             ereport(ERROR,
 7203 tgl                     11659 ECB             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                              11660                 :                      errmsg("column \"%s\" referenced in foreign key constraint does not exist",
                              11661                 :                             attname)));
    9 tgl                     11662 CBC        1970 :         attform = (Form_pg_attribute) GETSTRUCT(atttuple);
    9 tgl                     11663 GIC        1970 :         if (attform->attnum < 0)
    9 tgl                     11664 CBC           6 :             ereport(ERROR,
                              11665                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              11666                 :                      errmsg("system columns cannot be used in foreign keys")));
 7504 tgl                     11667 GIC        1964 :         if (attnum >= INDEX_MAX_KEYS)
 7203 tgl                     11668 UIC           0 :             ereport(ERROR,
                              11669                 :                     (errcode(ERRCODE_TOO_MANY_COLUMNS),
                              11670                 :                      errmsg("cannot have more than %d keys in a foreign key",
                              11671                 :                             INDEX_MAX_KEYS)));
    9 tgl                     11672 GIC        1964 :         attnums[attnum] = attform->attnum;
  487 peter                   11673            1964 :         if (atttypids != NULL)
    9 tgl                     11674            1949 :             atttypids[attnum] = attform->atttypid;
 7504                         11675            1964 :         ReleaseSysCache(atttuple);
                              11676            1964 :         attnum++;
                              11677                 :     }
                              11678                 : 
 7504 tgl                     11679 CBC        2551 :     return attnum;
                              11680                 : }
                              11681                 : 
                              11682                 : /*
                              11683                 :  * transformFkeyGetPrimaryKey -
                              11684                 :  *
                              11685                 :  *  Look up the names, attnums, and types of the primary key attributes
 3260 bruce                   11686 ECB             :  *  for the pkrel.  Also return the index OID and index opclasses of the
                              11687                 :  *  index supporting the primary key.
 6966 tgl                     11688                 :  *
 3260 bruce                   11689                 :  *  All parameters except pkrel are output parameters.  Also, the function
 6966 tgl                     11690                 :  *  return value is the number of attributes in the primary key.
                              11691                 :  *
                              11692                 :  *  Used when the column list in the REFERENCES specification is omitted.
                              11693                 :  */
                              11694                 : static int
 7504 tgl                     11695 GIC         458 : transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
                              11696                 :                            List **attnamelist,
                              11697                 :                            int16 *attnums, Oid *atttypids,
 6966 tgl                     11698 ECB             :                            Oid *opclasses)
 7504                         11699                 : {
                              11700                 :     List       *indexoidlist;
                              11701                 :     ListCell   *indexoidscan;
 7504 tgl                     11702 GIC         458 :     HeapTuple   indexTuple = NULL;
                              11703             458 :     Form_pg_index indexStruct = NULL;
                              11704                 :     Datum       indclassDatum;
                              11705                 :     oidvector  *indclass;
 7504 tgl                     11706 ECB             :     int         i;
                              11707                 : 
                              11708                 :     /*
 6385 bruce                   11709                 :      * Get the list of index OIDs for the table from the relcache, and look up
                              11710                 :      * each one in the pg_index syscache until we find one marked primary key
                              11711                 :      * (hopefully there isn't more than one such).  Insist it's valid, too.
 7504 tgl                     11712                 :      */
 6406 tgl                     11713 GIC         458 :     *indexOid = InvalidOid;
                              11714                 : 
 7504 tgl                     11715 CBC         458 :     indexoidlist = RelationGetIndexList(pkrel);
 7504 tgl                     11716 ECB             : 
 7504 tgl                     11717 GIC         461 :     foreach(indexoidscan, indexoidlist)
                              11718                 :     {
 6892 neilc                   11719 CBC         461 :         Oid         indexoid = lfirst_oid(indexoidscan);
                              11720                 : 
 4802 rhaas                   11721 GIC         461 :         indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
 7504 tgl                     11722             461 :         if (!HeapTupleIsValid(indexTuple))
 7203 tgl                     11723 UIC           0 :             elog(ERROR, "cache lookup failed for index %u", indexoid);
 7504 tgl                     11724 GIC         461 :         indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 1564 peter_e                 11725 CBC         461 :         if (indexStruct->indisprimary && indexStruct->indisvalid)
                              11726                 :         {
                              11727                 :             /*
                              11728                 :              * Refuse to use a deferrable primary key.  This is per SQL spec,
 4790 bruce                   11729 ECB             :              * and there would be a lot of interesting semantic problems if we
                              11730                 :              * tried to allow it.
 5002 tgl                     11731                 :              */
 5002 tgl                     11732 GIC         458 :             if (!indexStruct->indimmediate)
 5002 tgl                     11733 LBC           0 :                 ereport(ERROR,
                              11734                 :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              11735                 :                          errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
                              11736                 :                                 RelationGetRelationName(pkrel))));
                              11737                 : 
 7504 tgl                     11738 GIC         458 :             *indexOid = indexoid;
                              11739             458 :             break;
                              11740                 :         }
                              11741               3 :         ReleaseSysCache(indexTuple);
                              11742                 :     }
 7504 tgl                     11743 ECB             : 
 6892 neilc                   11744 CBC         458 :     list_free(indexoidlist);
                              11745                 : 
                              11746                 :     /*
                              11747                 :      * Check that we found it
                              11748                 :      */
 6406 tgl                     11749 GIC         458 :     if (!OidIsValid(*indexOid))
 7203 tgl                     11750 UIC           0 :         ereport(ERROR,
                              11751                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              11752                 :                  errmsg("there is no primary key for referenced table \"%s\"",
 6385 bruce                   11753 ECB             :                         RelationGetRelationName(pkrel))));
 7504 tgl                     11754                 : 
 6585                         11755                 :     /* Must get indclass the hard way */
   15 dgustafsson             11756 GNC         458 :     indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
                              11757                 :                                            Anum_pg_index_indclass);
 6585 tgl                     11758 CBC         458 :     indclass = (oidvector *) DatumGetPointer(indclassDatum);
 6585 tgl                     11759 ECB             : 
                              11760                 :     /*
 7188 bruce                   11761                 :      * Now build the list of PK attributes from the indkey definition (we
                              11762                 :      * assume a primary key cannot have expressional elements)
 7504 tgl                     11763                 :      */
 7504 tgl                     11764 GIC         458 :     *attnamelist = NIL;
 1828 teodor                  11765 CBC        1032 :     for (i = 0; i < indexStruct->indnkeyatts; i++)
                              11766                 :     {
 6585 tgl                     11767             574 :         int         pkattno = indexStruct->indkey.values[i];
                              11768                 : 
 7504 tgl                     11769 GIC         574 :         attnums[i] = pkattno;
 7504 tgl                     11770 CBC         574 :         atttypids[i] = attnumTypeId(pkrel, pkattno);
 6585 tgl                     11771 GIC         574 :         opclasses[i] = indclass->values[i];
 7504                         11772             574 :         *attnamelist = lappend(*attnamelist,
 2118                         11773             574 :                                makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
                              11774                 :     }
                              11775                 : 
 7504                         11776             458 :     ReleaseSysCache(indexTuple);
                              11777                 : 
                              11778             458 :     return i;
                              11779                 : }
                              11780                 : 
 7504 tgl                     11781 ECB             : /*
                              11782                 :  * transformFkeyCheckAttrs -
                              11783                 :  *
                              11784                 :  *  Make sure that the attributes of a referenced table belong to a unique
                              11785                 :  *  (or primary key) constraint.  Return the OID of the index supporting
                              11786                 :  *  the constraint, as well as the opclasses associated with the index
                              11787                 :  *  columns.
                              11788                 :  */
                              11789                 : static Oid
 7504 tgl                     11790 GIC         532 : transformFkeyCheckAttrs(Relation pkrel,
                              11791                 :                         int numattrs, int16 *attnums,
                              11792                 :                         Oid *opclasses) /* output parameter */
 7504 tgl                     11793 ECB             : {
 7504 tgl                     11794 GIC         532 :     Oid         indexoid = InvalidOid;
                              11795             532 :     bool        found = false;
 4988 tgl                     11796 CBC         532 :     bool        found_deferrable = false;
                              11797                 :     List       *indexoidlist;
 6892 neilc                   11798 ECB             :     ListCell   *indexoidscan;
                              11799                 :     int         i,
                              11800                 :                 j;
 3165 tgl                     11801                 : 
                              11802                 :     /*
                              11803                 :      * Reject duplicate appearances of columns in the referenced-columns list.
                              11804                 :      * Such a case is forbidden by the SQL standard, and even if we thought it
                              11805                 :      * useful to allow it, there would be ambiguity about how to match the
                              11806                 :      * list to unique indexes (in particular, it'd be unclear which index
                              11807                 :      * opclass goes with which FK column).
                              11808                 :      */
 3165 tgl                     11809 GIC        1206 :     for (i = 0; i < numattrs; i++)
 3165 tgl                     11810 ECB             :     {
 3165 tgl                     11811 GIC         837 :         for (j = i + 1; j < numattrs; j++)
                              11812                 :         {
                              11813             163 :             if (attnums[i] == attnums[j])
 3165 tgl                     11814 UIC           0 :                 ereport(ERROR,
                              11815                 :                         (errcode(ERRCODE_INVALID_FOREIGN_KEY),
                              11816                 :                          errmsg("foreign key referenced-columns list must not contain duplicates")));
                              11817                 :         }
                              11818                 :     }
                              11819                 : 
                              11820                 :     /*
                              11821                 :      * Get the list of index OIDs for the table from the relcache, and look up
                              11822                 :      * each one in the pg_index syscache, and match unique indexes to the list
                              11823                 :      * of attnums we are given.
                              11824                 :      */
 7504 tgl                     11825 CBC         532 :     indexoidlist = RelationGetIndexList(pkrel);
                              11826                 : 
 7504 tgl                     11827 GIC         622 :     foreach(indexoidscan, indexoidlist)
                              11828                 :     {
                              11829                 :         HeapTuple   indexTuple;
                              11830                 :         Form_pg_index indexStruct;
                              11831                 : 
 6892 neilc                   11832             616 :         indexoid = lfirst_oid(indexoidscan);
 4802 rhaas                   11833             616 :         indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
 7504 tgl                     11834             616 :         if (!HeapTupleIsValid(indexTuple))
 7203 tgl                     11835 LBC           0 :             elog(ERROR, "cache lookup failed for index %u", indexoid);
 7504 tgl                     11836 GIC         616 :         indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
                              11837                 : 
                              11838                 :         /*
                              11839                 :          * Must have the right number of columns; must be unique and not a
 3784 tgl                     11840 ECB             :          * partial index; forget it if there are any expressions, too. Invalid
                              11841                 :          * indexes are out as well.
                              11842                 :          */
 1828 teodor                  11843 GIC         616 :         if (indexStruct->indnkeyatts == numattrs &&
 4988 tgl                     11844 CBC         562 :             indexStruct->indisunique &&
 1564 peter_e                 11845 GIC        1110 :             indexStruct->indisvalid &&
 1838 andrew                  11846            1110 :             heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
                              11847             555 :             heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
 7504 tgl                     11848 ECB             :         {
                              11849                 :             Datum       indclassDatum;
                              11850                 :             oidvector  *indclass;
 6585                         11851                 : 
                              11852                 :             /* Must get indclass the hard way */
   15 dgustafsson             11853 GNC         555 :             indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
                              11854                 :                                                    Anum_pg_index_indclass);
 6585 tgl                     11855 GBC         555 :             indclass = (oidvector *) DatumGetPointer(indclassDatum);
                              11856                 : 
                              11857                 :             /*
                              11858                 :              * The given attnum list may match the index columns in any order.
                              11859                 :              * Check for a match, and extract the appropriate opclasses while
 3165 tgl                     11860 ECB             :              * we're at it.
                              11861                 :              *
                              11862                 :              * We know that attnums[] is duplicate-free per the test at the
 3165 tgl                     11863 EUB             :              * start of this function, and we checked above that the number of
                              11864                 :              * index columns agrees, so if we find a match for each attnums[]
                              11865                 :              * entry then we must have a one-to-one match in some order.
                              11866                 :              */
 7256 tgl                     11867 GIC        1223 :             for (i = 0; i < numattrs; i++)
 7256 tgl                     11868 ECB             :             {
 7256 tgl                     11869 GIC         697 :                 found = false;
                              11870             889 :                 for (j = 0; j < numattrs; j++)
                              11871                 :                 {
 6585                         11872             860 :                     if (attnums[i] == indexStruct->indkey.values[j])
                              11873                 :                     {
 3165 tgl                     11874 CBC         668 :                         opclasses[i] = indclass->values[j];
 7256 tgl                     11875 GIC         668 :                         found = true;
                              11876             668 :                         break;
                              11877                 :                     }
                              11878                 :                 }
                              11879             697 :                 if (!found)
 7256 tgl                     11880 CBC          29 :                     break;
                              11881                 :             }
 4988 tgl                     11882 ECB             : 
                              11883                 :             /*
 4790 bruce                   11884                 :              * Refuse to use a deferrable unique/primary key.  This is per SQL
                              11885                 :              * spec, and there would be a lot of interesting semantic problems
                              11886                 :              * if we tried to allow it.
 4988 tgl                     11887                 :              */
 4988 tgl                     11888 CBC         555 :             if (found && !indexStruct->indimmediate)
 4988 tgl                     11889 ECB             :             {
                              11890                 :                 /*
                              11891                 :                  * Remember that we found an otherwise matching index, so that
                              11892                 :                  * we can generate a more appropriate error message.
                              11893                 :                  */
 4988 tgl                     11894 LBC           0 :                 found_deferrable = true;
 4988 tgl                     11895 UIC           0 :                 found = false;
                              11896                 :             }
                              11897                 :         }
 7504 tgl                     11898 GIC         616 :         ReleaseSysCache(indexTuple);
                              11899             616 :         if (found)
                              11900             526 :             break;
 7576 tgl                     11901 ECB             :     }
                              11902                 : 
 7504 tgl                     11903 CBC         532 :     if (!found)
                              11904                 :     {
 4988 tgl                     11905 GIC           6 :         if (found_deferrable)
 4988 tgl                     11906 UIC           0 :             ereport(ERROR,
                              11907                 :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              11908                 :                      errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
                              11909                 :                             RelationGetRelationName(pkrel))));
                              11910                 :         else
 4988 tgl                     11911 GIC           6 :             ereport(ERROR,
                              11912                 :                     (errcode(ERRCODE_INVALID_FOREIGN_KEY),
                              11913                 :                      errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
 4988 tgl                     11914 ECB             :                             RelationGetRelationName(pkrel))));
                              11915                 :     }
                              11916                 : 
 6892 neilc                   11917 GIC         526 :     list_free(indexoidlist);
                              11918                 : 
 7504 tgl                     11919             526 :     return indexoid;
                              11920                 : }
                              11921                 : 
                              11922                 : /*
                              11923                 :  * findFkeyCast -
                              11924                 :  *
                              11925                 :  *  Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
 4059 alvherre                11926 ECB             :  *  Caller has equal regard for binary coercibility and for an exact match.
                              11927                 : */
                              11928                 : static CoercionPathType
 4059 alvherre                11929 GIC           6 : findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
                              11930                 : {
 4059 alvherre                11931 ECB             :     CoercionPathType ret;
                              11932                 : 
 4059 alvherre                11933 GIC           6 :     if (targetTypeId == sourceTypeId)
                              11934                 :     {
                              11935               6 :         ret = COERCION_PATH_RELABELTYPE;
                              11936               6 :         *funcid = InvalidOid;
                              11937                 :     }
                              11938                 :     else
 4059 alvherre                11939 ECB             :     {
 4059 alvherre                11940 UBC           0 :         ret = find_coercion_pathway(targetTypeId, sourceTypeId,
                              11941                 :                                     COERCION_IMPLICIT, funcid);
 4059 alvherre                11942 UIC           0 :         if (ret == COERCION_PATH_NONE)
                              11943                 :             /* A previously-relied-upon cast is now gone. */
                              11944               0 :             elog(ERROR, "could not find cast from %u to %u",
 4059 alvherre                11945 ECB             :                  sourceTypeId, targetTypeId);
                              11946                 :     }
                              11947                 : 
 4059 alvherre                11948 GIC           6 :     return ret;
 4059 alvherre                11949 ECB             : }
                              11950                 : 
                              11951                 : /*
                              11952                 :  * Permissions checks on the referenced table for ADD FOREIGN KEY
 2200 tgl                     11953                 :  *
                              11954                 :  * Note: we have already checked that the user owns the referencing table,
                              11955                 :  * else we'd have failed much earlier; no additional checks are needed for it.
                              11956                 :  */
 5190                         11957                 : static void
 5190 tgl                     11958 CBC         984 : checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
                              11959                 : {
                              11960             984 :     Oid         roleid = GetUserId();
                              11961                 :     AclResult   aclresult;
 5190 tgl                     11962 ECB             :     int         i;
                              11963                 : 
                              11964                 :     /* Okay if we have relation-level REFERENCES permission */
 5190 tgl                     11965 GIC         984 :     aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
 5190 tgl                     11966 ECB             :                                   ACL_REFERENCES);
 5190 tgl                     11967 CBC         984 :     if (aclresult == ACLCHECK_OK)
 5190 tgl                     11968 GIC         984 :         return;
                              11969                 :     /* Else we must have REFERENCES on each column */
 5190 tgl                     11970 UIC           0 :     for (i = 0; i < natts; i++)
                              11971                 :     {
                              11972               0 :         aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
 5190 tgl                     11973 ECB             :                                           roleid, ACL_REFERENCES);
 5190 tgl                     11974 UIC           0 :         if (aclresult != ACLCHECK_OK)
 1954 peter_e                 11975               0 :             aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
 5190 tgl                     11976               0 :                            RelationGetRelationName(rel));
                              11977                 :     }
                              11978                 : }
 5190 tgl                     11979 ECB             : 
 7576                         11980                 : /*
                              11981                 :  * Scan the existing rows in a table to verify they meet a proposed FK
                              11982                 :  * constraint.
                              11983                 :  *
 4638 simon                   11984                 :  * Caller must have opened and locked both relations appropriately.
                              11985                 :  */
 7576 tgl                     11986                 : static void
 4443 simon                   11987 GIC         466 : validateForeignKeyConstraint(char *conname,
 7576 tgl                     11988 ECB             :                              Relation rel,
                              11989                 :                              Relation pkrel,
                              11990                 :                              Oid pkindOid,
 5898                         11991                 :                              Oid constraintOid)
                              11992                 : {
 1490 andres                  11993                 :     TupleTableSlot *slot;
                              11994                 :     TableScanDesc scan;
  267 peter                   11995 GNC         466 :     Trigger     trig = {0};
                              11996                 :     Snapshot    snapshot;
 1463 andres                  11997 ECB             :     MemoryContext oldcxt;
                              11998                 :     MemoryContext perTupCxt;
                              11999                 : 
 4439 rhaas                   12000 GIC         466 :     ereport(DEBUG1,
                              12001                 :             (errmsg_internal("validating foreign key constraint \"%s\"", conname)));
                              12002                 : 
                              12003                 :     /*
                              12004                 :      * Build a trigger call structure; we'll need it either way.
                              12005                 :      */
 7576 tgl                     12006             466 :     trig.tgoid = InvalidOid;
 4443 simon                   12007             466 :     trig.tgname = conname;
 5865 JanWieck                12008             466 :     trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
 2062 peter_e                 12009             466 :     trig.tgisinternal = true;
 7576 tgl                     12010             466 :     trig.tgconstrrelid = RelationGetRelid(pkrel);
 5003 tgl                     12011 CBC         466 :     trig.tgconstrindid = pkindOid;
 5898 tgl                     12012 GIC         466 :     trig.tgconstraint = constraintOid;
 2062 peter_e                 12013             466 :     trig.tgdeferrable = false;
                              12014             466 :     trig.tginitdeferred = false;
                              12015                 :     /* we needn't fill in remaining fields */
                              12016                 : 
 5898 tgl                     12017 ECB             :     /*
 2062 peter_e                 12018                 :      * See if we can do it with a single LEFT JOIN query.  A false result
                              12019                 :      * indicates we must proceed with the fire-the-trigger method.
 5898 tgl                     12020                 :      */
 5898 tgl                     12021 GIC         466 :     if (RI_Initial_Check(&trig, rel, pkrel))
                              12022             432 :         return;
                              12023                 : 
 5898 tgl                     12024 ECB             :     /*
                              12025                 :      * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
                              12026                 :      * if that tuple had just been inserted.  If any of those fail, it should
                              12027                 :      * ereport(ERROR) and that's that.
                              12028                 :      */
 3568 rhaas                   12029 GIC           6 :     snapshot = RegisterSnapshot(GetLatestSnapshot());
 1490 andres                  12030 CBC           6 :     slot = table_slot_create(rel, NULL);
                              12031               6 :     scan = table_beginscan(rel, snapshot, 0, NULL);
 7664 tgl                     12032 ECB             : 
 1463 andres                  12033 GIC           6 :     perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
                              12034                 :                                       "validateForeignKeyConstraint",
 1463 andres                  12035 ECB             :                                       ALLOCSET_SMALL_SIZES);
 1463 andres                  12036 GBC           6 :     oldcxt = MemoryContextSwitchTo(perTupCxt);
                              12037                 : 
 1490 andres                  12038 GIC          36 :     while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
                              12039                 :     {
 1534 andres                  12040 CBC          33 :         LOCAL_FCINFO(fcinfo, 0);
 1140 peter                   12041              33 :         TriggerData trigdata = {0};
 7664 tgl                     12042 ECB             : 
 1463 andres                  12043 CBC          33 :         CHECK_FOR_INTERRUPTS();
 1463 andres                  12044 ECB             : 
                              12045                 :         /*
                              12046                 :          * Make a call to the trigger function
 7576 tgl                     12047                 :          *
                              12048                 :          * No parameters are passed, but we do set a context
                              12049                 :          */
 1534 andres                  12050 GIC         165 :         MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
                              12051                 : 
                              12052                 :         /*
                              12053                 :          * We assume RI_FKey_check_ins won't look at flinfo...
                              12054                 :          */
 7118 bruce                   12055              33 :         trigdata.type = T_TriggerData;
                              12056              33 :         trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
                              12057              33 :         trigdata.tg_relation = rel;
 1464 tgl                     12058              33 :         trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
 1490 andres                  12059              33 :         trigdata.tg_trigslot = slot;
 7118 bruce                   12060              33 :         trigdata.tg_trigger = &trig;
                              12061                 : 
 1534 andres                  12062              33 :         fcinfo->context = (Node *) &trigdata;
 7576 tgl                     12063 ECB             : 
 1534 andres                  12064 GIC          33 :         RI_FKey_check_ins(fcinfo);
                              12065                 : 
 1463                         12066              30 :         MemoryContextReset(perTupCxt);
                              12067                 :     }
                              12068                 : 
                              12069               3 :     MemoryContextSwitchTo(oldcxt);
 1463 andres                  12070 CBC           3 :     MemoryContextDelete(perTupCxt);
 1490                         12071               3 :     table_endscan(scan);
 3568 rhaas                   12072 GIC           3 :     UnregisterSnapshot(snapshot);
 1490 andres                  12073               3 :     ExecDropSingleTupleTableSlot(slot);
                              12074                 : }
                              12075                 : 
                              12076                 : /*
                              12077                 :  * CreateFKCheckTrigger
                              12078                 :  *      Creates the insert (on_insert=true) or update "check" trigger that
                              12079                 :  *      implements a given foreign key
                              12080                 :  *
  459 alvherre                12081 ECB             :  * Returns the OID of the so created trigger.
                              12082                 :  */
                              12083                 : static Oid
 3338 rhaas                   12084 GIC        2448 : CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
  459 alvherre                12085 ECB             :                      Oid constraintOid, Oid indexOid, Oid parentTrigOid,
                              12086                 :                      bool on_insert)
 7576 tgl                     12087                 : {
                              12088                 :     ObjectAddress trigAddress;
                              12089                 :     CreateTrigStmt *fk_trigger;
                              12090                 : 
 4183 tgl                     12091 EUB             :     /*
 4183 tgl                     12092 ECB             :      * Note: for a self-referential FK (referencing and referenced tables are
                              12093                 :      * the same), it is important that the ON UPDATE action fires before the
                              12094                 :      * CHECK action, since both triggers will fire on the same row during an
                              12095                 :      * UPDATE event; otherwise the CHECK trigger will be checking a non-final
                              12096                 :      * state of the row.  Triggers fire in name order, so we ensure this by
                              12097                 :      * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
                              12098                 :      * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
                              12099                 :      */
 7576 tgl                     12100 CBC        2448 :     fk_trigger = makeNode(CreateTrigStmt);
  876 tgl                     12101 GBC        2448 :     fk_trigger->replace = false;
  876 tgl                     12102 GIC        2448 :     fk_trigger->isconstraint = true;
 4183                         12103            2448 :     fk_trigger->trigname = "RI_ConstraintTrigger_c";
 3338 rhaas                   12104            2448 :     fk_trigger->relation = NULL;
                              12105                 : 
 6523 neilc                   12106 ECB             :     /* Either ON INSERT or ON UPDATE */
 6523 neilc                   12107 CBC        2448 :     if (on_insert)
                              12108                 :     {
                              12109            1224 :         fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
 5043 tgl                     12110 GIC        1224 :         fk_trigger->events = TRIGGER_TYPE_INSERT;
                              12111                 :     }
 6523 neilc                   12112 ECB             :     else
                              12113                 :     {
 6523 neilc                   12114 GIC        1224 :         fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
 5043 tgl                     12115            1224 :         fk_trigger->events = TRIGGER_TYPE_UPDATE;
                              12116                 :     }
 7576 tgl                     12117 ECB             : 
  876 tgl                     12118 GBC        2448 :     fk_trigger->args = NIL;
  876 tgl                     12119 GIC        2448 :     fk_trigger->row = true;
                              12120            2448 :     fk_trigger->timing = TRIGGER_TYPE_AFTER;
 4925                         12121            2448 :     fk_trigger->columns = NIL;
 4888                         12122            2448 :     fk_trigger->whenClause = NULL;
  876                         12123            2448 :     fk_trigger->transitionRels = NIL;
 7576 tgl                     12124 CBC        2448 :     fk_trigger->deferrable = fkconstraint->deferrable;
 7576 tgl                     12125 GIC        2448 :     fk_trigger->initdeferred = fkconstraint->initdeferred;
 3338 rhaas                   12126 CBC        2448 :     fk_trigger->constrrel = NULL;
                              12127                 : 
  459 alvherre                12128 GIC        2448 :     trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid,
                              12129                 :                                 constraintOid, indexOid, InvalidOid,
                              12130                 :                                 parentTrigOid, NULL, true, false);
                              12131                 : 
 6523 neilc                   12132 ECB             :     /* Make changes-so-far visible */
 6523 neilc                   12133 CBC        2448 :     CommandCounterIncrement();
                              12134                 : 
  459 alvherre                12135            2448 :     return trigAddress.objectId;
                              12136                 : }
 6523 neilc                   12137 ECB             : 
                              12138                 : /*
 1831 alvherre                12139                 :  * createForeignKeyActionTriggers
                              12140                 :  *      Create the referenced-side "action" triggers that implement a foreign
                              12141                 :  *      key.
                              12142                 :  *
                              12143                 :  * Returns the OIDs of the so created triggers in *deleteTrigOid and
  459                         12144                 :  * *updateTrigOid.
                              12145                 :  */
 6523 neilc                   12146                 : static void
 1831 alvherre                12147 GIC        1232 : createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint,
                              12148                 :                                Oid constraintOid, Oid indexOid,
                              12149                 :                                Oid parentDelTrigger, Oid parentUpdTrigger,
                              12150                 :                                Oid *deleteTrigOid, Oid *updateTrigOid)
                              12151                 : {
                              12152                 :     CreateTrigStmt *fk_trigger;
                              12153                 :     ObjectAddress trigAddress;
                              12154                 : 
                              12155                 :     /*
                              12156                 :      * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
                              12157                 :      * DELETE action on the referenced table.
 6913 tgl                     12158 ECB             :      */
 6913 tgl                     12159 GIC        1232 :     fk_trigger = makeNode(CreateTrigStmt);
  876                         12160            1232 :     fk_trigger->replace = false;
                              12161            1232 :     fk_trigger->isconstraint = true;
 4183 tgl                     12162 CBC        1232 :     fk_trigger->trigname = "RI_ConstraintTrigger_a";
 3338 rhaas                   12163            1232 :     fk_trigger->relation = NULL;
  876 tgl                     12164            1232 :     fk_trigger->args = NIL;
 6913 tgl                     12165 GIC        1232 :     fk_trigger->row = true;
 4564                         12166            1232 :     fk_trigger->timing = TRIGGER_TYPE_AFTER;
 5043                         12167            1232 :     fk_trigger->events = TRIGGER_TYPE_DELETE;
 4925                         12168            1232 :     fk_trigger->columns = NIL;
 4888                         12169            1232 :     fk_trigger->whenClause = NULL;
  876                         12170            1232 :     fk_trigger->transitionRels = NIL;
 3338 rhaas                   12171            1232 :     fk_trigger->constrrel = NULL;
 6913 tgl                     12172            1232 :     switch (fkconstraint->fk_del_action)
                              12173                 :     {
                              12174             927 :         case FKCONSTR_ACTION_NOACTION:
 6744                         12175             927 :             fk_trigger->deferrable = fkconstraint->deferrable;
                              12176             927 :             fk_trigger->initdeferred = fkconstraint->initdeferred;
 6913 tgl                     12177 CBC         927 :             fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
 6913 tgl                     12178 GIC         927 :             break;
 6913 tgl                     12179 CBC          15 :         case FKCONSTR_ACTION_RESTRICT:
 6913 tgl                     12180 GIC          15 :             fk_trigger->deferrable = false;
 6913 tgl                     12181 CBC          15 :             fk_trigger->initdeferred = false;
 6913 tgl                     12182 GBC          15 :             fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
 6913 tgl                     12183 GIC          15 :             break;
                              12184             218 :         case FKCONSTR_ACTION_CASCADE:
 6744                         12185             218 :             fk_trigger->deferrable = false;
                              12186             218 :             fk_trigger->initdeferred = false;
 6913                         12187             218 :             fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
                              12188             218 :             break;
                              12189              42 :         case FKCONSTR_ACTION_SETNULL:
 6744                         12190              42 :             fk_trigger->deferrable = false;
                              12191              42 :             fk_trigger->initdeferred = false;
 6913                         12192              42 :             fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
 6913 tgl                     12193 CBC          42 :             break;
 6913 tgl                     12194 GIC          30 :         case FKCONSTR_ACTION_SETDEFAULT:
 6744 tgl                     12195 CBC          30 :             fk_trigger->deferrable = false;
 6744 tgl                     12196 GIC          30 :             fk_trigger->initdeferred = false;
 6913                         12197              30 :             fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
                              12198              30 :             break;
 6913 tgl                     12199 UIC           0 :         default:
 6913 tgl                     12200 LBC           0 :             elog(ERROR, "unrecognized FK action type: %d",
 6913 tgl                     12201 ECB             :                  (int) fkconstraint->fk_del_action);
                              12202                 :             break;
 6913 tgl                     12203 EUB             :     }
 6913 tgl                     12204 ECB             : 
  459 alvherre                12205 GIC        1232 :     trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
                              12206                 :                                 RelationGetRelid(rel),
                              12207                 :                                 constraintOid, indexOid, InvalidOid,
                              12208                 :                                 parentDelTrigger, NULL, true, false);
                              12209            1232 :     if (deleteTrigOid)
                              12210            1202 :         *deleteTrigOid = trigAddress.objectId;
 6913 tgl                     12211 ECB             : 
                              12212                 :     /* Make changes-so-far visible */
 6913 tgl                     12213 CBC        1232 :     CommandCounterIncrement();
 6913 tgl                     12214 ECB             : 
                              12215                 :     /*
                              12216                 :      * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
                              12217                 :      * UPDATE action on the referenced table.
                              12218                 :      */
 6913 tgl                     12219 GIC        1232 :     fk_trigger = makeNode(CreateTrigStmt);
  876                         12220            1232 :     fk_trigger->replace = false;
  876 tgl                     12221 CBC        1232 :     fk_trigger->isconstraint = true;
 4183 tgl                     12222 GIC        1232 :     fk_trigger->trigname = "RI_ConstraintTrigger_a";
 3338 rhaas                   12223 CBC        1232 :     fk_trigger->relation = NULL;
  876 tgl                     12224 GIC        1232 :     fk_trigger->args = NIL;
 6913                         12225            1232 :     fk_trigger->row = true;
 4564                         12226            1232 :     fk_trigger->timing = TRIGGER_TYPE_AFTER;
 5043                         12227            1232 :     fk_trigger->events = TRIGGER_TYPE_UPDATE;
 4925                         12228            1232 :     fk_trigger->columns = NIL;
 4888                         12229            1232 :     fk_trigger->whenClause = NULL;
  876                         12230            1232 :     fk_trigger->transitionRels = NIL;
 3338 rhaas                   12231            1232 :     fk_trigger->constrrel = NULL;
 6913 tgl                     12232            1232 :     switch (fkconstraint->fk_upd_action)
                              12233                 :     {
                              12234            1021 :         case FKCONSTR_ACTION_NOACTION:
 6744 tgl                     12235 CBC        1021 :             fk_trigger->deferrable = fkconstraint->deferrable;
 6744 tgl                     12236 GIC        1021 :             fk_trigger->initdeferred = fkconstraint->initdeferred;
 6913 tgl                     12237 CBC        1021 :             fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
                              12238            1021 :             break;
 6913 tgl                     12239 GIC          15 :         case FKCONSTR_ACTION_RESTRICT:
 6913 tgl                     12240 CBC          15 :             fk_trigger->deferrable = false;
 6913 tgl                     12241 GIC          15 :             fk_trigger->initdeferred = false;
 6913 tgl                     12242 CBC          15 :             fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
                              12243              15 :             break;
                              12244             144 :         case FKCONSTR_ACTION_CASCADE:
 6744 tgl                     12245 GIC         144 :             fk_trigger->deferrable = false;
                              12246             144 :             fk_trigger->initdeferred = false;
 6913 tgl                     12247 CBC         144 :             fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
                              12248             144 :             break;
 6913 tgl                     12249 GIC          31 :         case FKCONSTR_ACTION_SETNULL:
 6744                         12250              31 :             fk_trigger->deferrable = false;
                              12251              31 :             fk_trigger->initdeferred = false;
 6913                         12252              31 :             fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
                              12253              31 :             break;
                              12254              21 :         case FKCONSTR_ACTION_SETDEFAULT:
 6744                         12255              21 :             fk_trigger->deferrable = false;
 6744 tgl                     12256 CBC          21 :             fk_trigger->initdeferred = false;
 6913 tgl                     12257 GIC          21 :             fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
                              12258              21 :             break;
 6913 tgl                     12259 UIC           0 :         default:
                              12260               0 :             elog(ERROR, "unrecognized FK action type: %d",
                              12261                 :                  (int) fkconstraint->fk_upd_action);
 6913 tgl                     12262 EUB             :             break;
                              12263                 :     }
                              12264                 : 
  459 alvherre                12265 GIC        1232 :     trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
  459 alvherre                12266 ECB             :                                 RelationGetRelid(rel),
                              12267                 :                                 constraintOid, indexOid, InvalidOid,
                              12268                 :                                 parentUpdTrigger, NULL, true, false);
  459 alvherre                12269 GIC        1232 :     if (updateTrigOid)
                              12270            1202 :         *updateTrigOid = trigAddress.objectId;
 1831 alvherre                12271 CBC        1232 : }
                              12272                 : 
 1831 alvherre                12273 ECB             : /*
 1831 alvherre                12274 EUB             :  * createForeignKeyCheckTriggers
                              12275                 :  *      Create the referencing-side "check" triggers that implement a foreign
                              12276                 :  *      key.
                              12277                 :  *
                              12278                 :  * Returns the OIDs of the so created triggers in *insertTrigOid and
  459 alvherre                12279 ECB             :  * *updateTrigOid.
                              12280                 :  */
                              12281                 : static void
 1831 alvherre                12282 GIC        1224 : createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
                              12283                 :                               Constraint *fkconstraint, Oid constraintOid,
                              12284                 :                               Oid indexOid,
  459 alvherre                12285 ECB             :                               Oid parentInsTrigger, Oid parentUpdTrigger,
                              12286                 :                               Oid *insertTrigOid, Oid *updateTrigOid)
 1831                         12287                 : {
  459 alvherre                12288 GIC        1224 :     *insertTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
                              12289                 :                                           constraintOid, indexOid,
                              12290                 :                                           parentInsTrigger, true);
                              12291            1224 :     *updateTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
                              12292                 :                                           constraintOid, indexOid,
                              12293                 :                                           parentUpdTrigger, false);
 6913 tgl                     12294            1224 : }
                              12295                 : 
                              12296                 : /*
 6913 tgl                     12297 ECB             :  * ALTER TABLE DROP CONSTRAINT
                              12298                 :  *
                              12299                 :  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
                              12300                 :  */
                              12301                 : static void
 5448 tgl                     12302 GIC         261 : ATExecDropConstraint(Relation rel, const char *constrName,
 5448 tgl                     12303 ECB             :                      DropBehavior behavior,
 5011 andrew                  12304                 :                      bool recurse, bool recursing,
                              12305                 :                      bool missing_ok, LOCKMODE lockmode)
                              12306                 : {
                              12307                 :     Relation    conrel;
                              12308                 :     SysScanDesc scan;
 1678 tgl                     12309 EUB             :     ScanKeyData skey[3];
                              12310                 :     HeapTuple   tuple;
 5448 tgl                     12311 GIC         261 :     bool        found = false;
                              12312                 : 
                              12313                 :     /* At top level, permission check was done in ATPrepCmd, else do it */
                              12314             261 :     if (recursing)
  640 peter                   12315 UIC           0 :         ATSimplePermissions(AT_DropConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                              12316                 : 
 1539 andres                  12317 GIC         261 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
                              12318                 : 
                              12319                 :     /*
                              12320                 :      * Find and drop the target constraint
 6913 tgl                     12321 ECB             :      */
 1678 tgl                     12322 GIC         261 :     ScanKeyInit(&skey[0],
 5448 tgl                     12323 ECB             :                 Anum_pg_constraint_conrelid,
                              12324                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              12325                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
 1678 tgl                     12326 GIC         261 :     ScanKeyInit(&skey[1],
                              12327                 :                 Anum_pg_constraint_contypid,
 1678 tgl                     12328 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              12329                 :                 ObjectIdGetDatum(InvalidOid));
 1678 tgl                     12330 CBC         261 :     ScanKeyInit(&skey[2],
 1678 tgl                     12331 ECB             :                 Anum_pg_constraint_conname,
                              12332                 :                 BTEqualStrategyNumber, F_NAMEEQ,
 1678 tgl                     12333 EUB             :                 CStringGetDatum(constrName));
 1678 tgl                     12334 GIC         261 :     scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
 1678 tgl                     12335 EUB             :                               true, NULL, 3, skey);
                              12336                 : 
                              12337                 :     /* There can be at most one matching row */
 1678 tgl                     12338 GBC         261 :     if (HeapTupleIsValid(tuple = systable_getnext(scan)))
 6913 tgl                     12339 EUB             :     {
    2 alvherre                12340 GNC         246 :         dropconstraint_internal(rel, tuple, behavior, recurse, recursing,
                              12341                 :                                 missing_ok, NULL, lockmode);
    2 alvherre                12342 GIC         168 :         found = true;
                              12343                 :     }
                              12344                 : 
    2 alvherre                12345 CBC         183 :     systable_endscan(scan);
 5448 tgl                     12346 ECB             : 
    2 alvherre                12347 GIC         183 :     if (!found)
                              12348                 :     {
                              12349              15 :         if (!missing_ok)
 5448 tgl                     12350               9 :             ereport(ERROR,
                              12351                 :                     errcode(ERRCODE_UNDEFINED_OBJECT),
                              12352                 :                     errmsg("constraint \"%s\" of relation \"%s\" does not exist",
                              12353                 :                            constrName, RelationGetRelationName(rel)));
                              12354                 :         else
    2 alvherre                12355               6 :             ereport(NOTICE,
                              12356                 :                     errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
                              12357                 :                            constrName, RelationGetRelationName(rel)));
                              12358                 :     }
                              12359                 : 
    2 alvherre                12360 GNC         174 :     table_close(conrel, RowExclusiveLock);
                              12361             174 : }
                              12362                 : 
                              12363                 : /*
                              12364                 :  * Remove a constraint, using its pg_constraint tuple
                              12365                 :  *
                              12366                 :  * Implementation for ALTER TABLE DROP CONSTRAINT and ALTER TABLE ALTER COLUMN
                              12367                 :  * DROP NOT NULL.
                              12368                 :  *
                              12369                 :  * Returns the address of the constraint being removed.
                              12370                 :  */
                              12371                 : static ObjectAddress
                              12372             401 : dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior behavior,
                              12373                 :                         bool recurse, bool recursing, bool missing_ok, List **readyRels,
                              12374                 :                         LOCKMODE lockmode)
                              12375                 : {
                              12376                 :     Relation    conrel;
                              12377                 :     Form_pg_constraint con;
                              12378                 :     ObjectAddress conobj;
                              12379                 :     List       *children;
                              12380                 :     ListCell   *child;
                              12381             401 :     bool        is_no_inherit_constraint = false;
                              12382             401 :     bool        dropping_pk = false;
                              12383                 :     char       *constrName;
                              12384             401 :     List       *unconstrained_cols = NIL;
                              12385                 :     char       *colname;    /* to match NOT NULL constraints when recursing */
                              12386             401 :     List       *ready = NIL;
                              12387                 : 
                              12388             401 :     if (readyRels == NULL)
                              12389             323 :         readyRels = &ready;
                              12390             401 :     if (list_member_oid(*readyRels, RelationGetRelid(rel)))
    2 alvherre                12391 UNC           0 :         return InvalidObjectAddress;
    2 alvherre                12392 GNC         401 :     *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
                              12393                 : 
                              12394             401 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
                              12395                 : 
                              12396             401 :     con = (Form_pg_constraint) GETSTRUCT(constraintTup);
                              12397             401 :     constrName = NameStr(con->conname);
                              12398                 : 
                              12399                 :     /*
                              12400                 :      * If the constraint is marked conislocal and is also inherited, then we
                              12401                 :      * just set conislocal false and we're done.  The constraint doesn't go
                              12402                 :      * away, and we don't modify any children.
                              12403                 :      */
                              12404             401 :     if (con->conislocal && con->coninhcount > 0)
                              12405                 :     {
                              12406                 :         HeapTuple   copytup;
                              12407                 : 
                              12408                 :         /* make a copy we can scribble on */
                              12409               6 :         copytup = heap_copytuple(constraintTup);
                              12410               6 :         con = (Form_pg_constraint) GETSTRUCT(copytup);
                              12411               6 :         con->conislocal = false;
                              12412               6 :         CatalogTupleUpdate(conrel, &copytup->t_self, copytup);
                              12413                 : 
                              12414               6 :         table_close(conrel, RowExclusiveLock);
                              12415                 : 
                              12416               6 :         ObjectAddressSet(conobj, ConstraintRelationId, con->oid);
                              12417               6 :         return conobj;
                              12418                 :     }
                              12419                 : 
                              12420                 :     /* Don't drop inherited constraints */
                              12421             395 :     if (con->coninhcount > 0 && !recursing)
                              12422              60 :         ereport(ERROR,
                              12423                 :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              12424                 :                  errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
                              12425                 :                         constrName, RelationGetRelationName(rel))));
                              12426                 : 
                              12427                 :     /*
                              12428                 :      * See if we have a NOT NULL constraint or a PRIMARY KEY.  If so, we have
                              12429                 :      * more checks and actions below, so obtain the list of columns that are
                              12430                 :      * constrained by the constraint being dropped.
                              12431                 :      */
                              12432             335 :     if (con->contype == CONSTRAINT_NOTNULL)
                              12433                 :     {
                              12434              88 :         AttrNumber  colnum = extractNotNullColumn(constraintTup);
                              12435                 : 
                              12436              88 :         if (colnum != InvalidAttrNumber)
                              12437              88 :             unconstrained_cols = list_make1_int(colnum);
                              12438                 :     }
                              12439             247 :     else if (con->contype == CONSTRAINT_PRIMARY)
                              12440                 :     {
                              12441                 :         Datum       adatum;
                              12442                 :         ArrayType  *arr;
                              12443                 :         int         numkeys;
                              12444                 :         bool        isNull;
                              12445                 :         int16      *attnums;
                              12446                 : 
                              12447              61 :         dropping_pk = true;
                              12448                 : 
                              12449              61 :         adatum = heap_getattr(constraintTup, Anum_pg_constraint_conkey,
                              12450                 :                               RelationGetDescr(conrel), &isNull);
                              12451              61 :         if (isNull)
    2 alvherre                12452 UNC           0 :             elog(ERROR, "null conkey for constraint %u", con->oid);
    2 alvherre                12453 GNC          61 :         arr = DatumGetArrayTypeP(adatum);   /* ensure not toasted */
                              12454              61 :         numkeys = ARR_DIMS(arr)[0];
                              12455              61 :         if (ARR_NDIM(arr) != 1 ||
                              12456              61 :             numkeys < 0 ||
                              12457              61 :             ARR_HASNULL(arr) ||
                              12458              61 :             ARR_ELEMTYPE(arr) != INT2OID)
    2 alvherre                12459 UNC           0 :             elog(ERROR, "conkey is not a 1-D smallint array");
    2 alvherre                12460 GNC          61 :         attnums = (int16 *) ARR_DATA_PTR(arr);
                              12461                 : 
                              12462             138 :         for (int i = 0; i < numkeys; i++)
                              12463              77 :             unconstrained_cols = lappend_int(unconstrained_cols, attnums[i]);
                              12464                 :     }
                              12465                 : 
                              12466             335 :     is_no_inherit_constraint = con->connoinherit;
                              12467                 : 
                              12468                 :     /*
                              12469                 :      * If it's a foreign-key constraint, we'd better lock the referenced table
                              12470                 :      * and check that that's not in use, just as we've already done for the
                              12471                 :      * constrained table (else we might, eg, be dropping a trigger that has
                              12472                 :      * unfired events).  But we can/must skip that in the self-referential
                              12473                 :      * case.
                              12474                 :      */
                              12475             335 :     if (con->contype == CONSTRAINT_FOREIGN &&
                              12476              36 :         con->confrelid != RelationGetRelid(rel))
                              12477                 :     {
                              12478                 :         Relation    frel;
                              12479                 : 
                              12480                 :         /* Must match lock taken by RemoveTriggerById: */
                              12481              36 :         frel = table_open(con->confrelid, AccessExclusiveLock);
                              12482              36 :         CheckTableNotInUse(frel, "ALTER TABLE");
                              12483              33 :         table_close(frel, NoLock);
                              12484                 :     }
                              12485                 : 
                              12486                 :     /*
                              12487                 :      * Perform the actual constraint deletion
                              12488                 :      */
                              12489             332 :     ObjectAddressSet(conobj, ConstraintRelationId, con->oid);
                              12490             332 :     performDeletion(&conobj, behavior, 0);
                              12491                 : 
                              12492                 :     /*
                              12493                 :      * If this was a NOT NULL or the primary key, the constrained columns must
                              12494                 :      * have had pg_attribute.attnotnull set.  See if we need to reset it, and
                              12495                 :      * do so.
                              12496                 :      */
                              12497             314 :     if (unconstrained_cols)
                              12498                 :     {
                              12499                 :         Relation    attrel;
                              12500                 :         Bitmapset  *pkcols;
                              12501                 :         Bitmapset  *ircols;
                              12502                 :         ListCell   *lc;
                              12503                 : 
                              12504                 :         /* Make the above deletion visible */
                              12505             131 :         CommandCounterIncrement();
                              12506                 : 
                              12507             131 :         attrel = table_open(AttributeRelationId, RowExclusiveLock);
                              12508                 : 
                              12509                 :         /*
                              12510                 :          * We want to test columns for their presence in the primary key, but
                              12511                 :          * only if we're not dropping it.
                              12512                 :          */
                              12513             131 :         pkcols = dropping_pk ? NULL :
                              12514              88 :             RelationGetIndexAttrBitmap(rel,
                              12515                 :                                        INDEX_ATTR_BITMAP_PRIMARY_KEY);
                              12516             131 :         ircols = RelationGetIndexAttrBitmap(rel, INDEX_ATTR_BITMAP_IDENTITY_KEY);
                              12517                 : 
                              12518             263 :         foreach(lc, unconstrained_cols)
                              12519                 :         {
                              12520             141 :             AttrNumber  attnum = lfirst_int(lc);
                              12521                 :             HeapTuple   atttup;
                              12522                 :             HeapTuple   contup;
                              12523                 :             Form_pg_attribute attForm;
                              12524                 : 
                              12525                 :             /*
                              12526                 :              * Obtain pg_attribute tuple and verify conditions on it.  We use
                              12527                 :              * a copy we can scribble on.
                              12528                 :              */
                              12529             141 :             atttup = SearchSysCacheCopyAttNum(RelationGetRelid(rel), attnum);
                              12530             141 :             if (!HeapTupleIsValid(atttup))
    2 alvherre                12531 UNC           0 :                 elog(ERROR, "cache lookup failed for column %d", attnum);
    2 alvherre                12532 GNC         141 :             attForm = (Form_pg_attribute) GETSTRUCT(atttup);
                              12533                 : 
                              12534                 :             /*
                              12535                 :              * Since the above deletion has been made visible, we can now
                              12536                 :              * search for any remaining constraints on this column (or these
                              12537                 :              * columns, in the case we're dropping a multicol primary key.)
                              12538                 :              * Then, verify whether any further NOT NULL or primary key
                              12539                 :              * exists, and reset attnotnull if none.
                              12540                 :              *
                              12541                 :              * However, if this is a generated identity column, abort the
                              12542                 :              * whole thing with a specific error message, because the
                              12543                 :              * constraint is required in that case.
                              12544                 :              */
                              12545             141 :             contup = findNotNullConstraintAttnum(rel, attnum);
                              12546             273 :             if (contup ||
                              12547             132 :                 bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
                              12548                 :                               pkcols))
                              12549              12 :                 continue;
                              12550                 : 
                              12551                 :             /*
                              12552                 :              * It's not valid to drop the last NOT NULL constraint for a
                              12553                 :              * GENERATED AS IDENTITY column.
                              12554                 :              */
                              12555             129 :             if (attForm->attidentity)
    2 alvherre                12556 UNC           0 :                 ereport(ERROR,
                              12557                 :                         errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              12558                 :                         errmsg("column \"%s\" of relation \"%s\" is an identity column",
                              12559                 :                                get_attname(RelationGetRelid(rel), attnum,
                              12560                 :                                            false),
                              12561                 :                                RelationGetRelationName(rel)));
                              12562                 : 
                              12563                 :             /*
                              12564                 :              * It's not valid to drop the last NOT NULL constraint for the
                              12565                 :              * replica identity either.  XXX make exception for FULL?
                              12566                 :              */
    2 alvherre                12567 GNC         129 :             if (bms_is_member(lfirst_int(lc) - FirstLowInvalidHeapAttributeNumber, ircols))
                              12568               9 :                 ereport(ERROR,
                              12569                 :                         errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              12570                 :                         errmsg("column \"%s\" is in index used as replica identity",
                              12571                 :                                get_attname(RelationGetRelid(rel), lfirst_int(lc), false)));
                              12572                 : 
                              12573                 :             /* Reset attnotnull */
                              12574             120 :             if (attForm->attnotnull)
                              12575                 :             {
                              12576             120 :                 attForm->attnotnull = false;
                              12577             120 :                 CatalogTupleUpdate(attrel, &atttup->t_self, atttup);
                              12578                 :             }
                              12579                 :         }
                              12580             122 :         table_close(attrel, RowExclusiveLock);
 5011 andrew                  12581 ECB             :     }
 4790 bruce                   12582                 : 
                              12583                 :     /*
 1536 alvherre                12584                 :      * For partitioned tables, non-CHECK inherited constraints are dropped via
                              12585                 :      * the dependency mechanism, so we're done here.
                              12586                 :      */
    2 alvherre                12587 GNC         305 :     if (con->contype != CONSTRAINT_CHECK &&
 1536 alvherre                12588 GIC         179 :         rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              12589                 :     {
                              12590              24 :         table_close(conrel, RowExclusiveLock);
    2 alvherre                12591 GNC          24 :         return conobj;
                              12592                 :     }
                              12593                 : 
                              12594                 :     /*
                              12595                 :      * Propagate to children as appropriate.  Unlike most other ALTER
 5448 tgl                     12596 ECB             :      * routines, we have to do this one level of recursion at a time; we can't
                              12597                 :      * use find_all_inheritors to do it in one pass.
                              12598                 :      */
 4006 alvherre                12599 CBC         281 :     if (!is_no_inherit_constraint)
  711                         12600             208 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
 5448 tgl                     12601 ECB             :     else
 5448 tgl                     12602 GIC          73 :         children = NIL;
 5448 tgl                     12603 ECB             : 
                              12604                 :     /*
 2175 sfrost                  12605                 :      * For a partitioned table, if partitions exist and we are told not to
                              12606                 :      * recurse, it's a user error.  It doesn't make sense to have a constraint
                              12607                 :      * be defined only on the parent, especially if it's a partitioned table.
                              12608                 :      */
 2175 sfrost                  12609 GIC         281 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
 2175 sfrost                  12610 CBC          31 :         children != NIL && !recurse)
                              12611               3 :         ereport(ERROR,
 2175 sfrost                  12612 ECB             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              12613                 :                  errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
                              12614                 :                  errhint("Do not specify the ONLY keyword.")));
                              12615                 : 
                              12616                 :     /* For NOT NULL constraints we recurse by column name */
    2 alvherre                12617 GNC         278 :     if (con->contype == CONSTRAINT_NOTNULL)
                              12618              79 :         colname = NameStr(TupleDescAttr(RelationGetDescr(rel),
                              12619                 :                                         linitial_int(unconstrained_cols) - 1)->attname);
                              12620                 :     else
                              12621             199 :         colname = NULL;     /* keep compiler quiet */
                              12622                 : 
 5448 tgl                     12623 GIC         365 :     foreach(child, children)
                              12624                 :     {
                              12625              87 :         Oid         childrelid = lfirst_oid(child);
                              12626                 :         Relation    childrel;
                              12627                 :         HeapTuple   tuple;
                              12628                 :         Form_pg_constraint childcon;
                              12629                 :         HeapTuple   copy_tuple;
                              12630                 :         SysScanDesc scan;
                              12631                 :         ScanKeyData skey[3];
                              12632                 : 
    2 alvherre                12633 GNC          87 :         if (list_member_oid(*readyRels, childrelid))
                              12634               3 :             continue;       /* child already processed */
                              12635                 : 
                              12636                 :         /* find_inheritance_children already got lock */
 1539 andres                  12637 GIC          84 :         childrel = table_open(childrelid, NoLock);
 5448 tgl                     12638              84 :         CheckTableNotInUse(childrel, "ALTER TABLE");
 5448 tgl                     12639 ECB             : 
                              12640                 :         /*
                              12641                 :          * We search for NOT NULL constraint by column number, and other
                              12642                 :          * constraints by name.
                              12643                 :          */
    2 alvherre                12644 GNC          84 :         if (con->contype == CONSTRAINT_NOTNULL)
                              12645                 :         {
                              12646              26 :             bool    found = false;
                              12647                 :             AttrNumber child_colnum;
                              12648                 :             HeapTuple   child_tup;
                              12649                 : 
                              12650              26 :             child_colnum = get_attnum(RelationGetRelid(childrel), colname);
                              12651              26 :             ScanKeyInit(&skey[0],
                              12652                 :                         Anum_pg_constraint_conrelid,
                              12653                 :                         BTEqualStrategyNumber, F_OIDEQ,
                              12654                 :                         ObjectIdGetDatum(childrelid));
                              12655              26 :             scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
                              12656                 :                                       true, NULL, 1, skey);
                              12657              37 :             while (HeapTupleIsValid(child_tup = systable_getnext(scan)))
                              12658                 :             {
                              12659              37 :                 Form_pg_constraint constr = (Form_pg_constraint) GETSTRUCT(child_tup);
                              12660                 :                 AttrNumber  constr_colnum;
 5448 tgl                     12661 ECB             : 
    2 alvherre                12662 GNC          37 :                 if (constr->contype != CONSTRAINT_NOTNULL)
                              12663               2 :                     continue;
                              12664              35 :                 constr_colnum = extractNotNullColumn(child_tup);
                              12665              35 :                 if (constr_colnum != child_colnum)
                              12666               9 :                     continue;
 5448 tgl                     12667 ECB             : 
    2 alvherre                12668 GNC          26 :                 found = true;
                              12669              26 :                 break;  /* found it */
                              12670                 :             }
                              12671              26 :             if (!found) /* shouldn't happen? */
    2 alvherre                12672 UNC           0 :                 elog(ERROR, "failed to find NOT NULL constraint for column \"%s\" in table \"%s\"",
                              12673                 :                      colname, RelationGetRelationName(childrel));
                              12674                 : 
    2 alvherre                12675 GNC          26 :             copy_tuple = heap_copytuple(child_tup);
                              12676              26 :             systable_endscan(scan);
                              12677                 :         }
                              12678                 :         else
                              12679                 :         {
                              12680              58 :             ScanKeyInit(&skey[0],
                              12681                 :                         Anum_pg_constraint_conrelid,
                              12682                 :                         BTEqualStrategyNumber, F_OIDEQ,
                              12683                 :                         ObjectIdGetDatum(childrelid));
                              12684              58 :             ScanKeyInit(&skey[1],
                              12685                 :                         Anum_pg_constraint_contypid,
                              12686                 :                         BTEqualStrategyNumber, F_OIDEQ,
                              12687                 :                         ObjectIdGetDatum(InvalidOid));
                              12688              58 :             ScanKeyInit(&skey[2],
                              12689                 :                         Anum_pg_constraint_conname,
                              12690                 :                         BTEqualStrategyNumber, F_NAMEEQ,
                              12691                 :                         CStringGetDatum(constrName));
                              12692              58 :             scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
                              12693                 :                                       true, NULL, 3, skey);
                              12694                 :             /* There can only be one, so no need to loop */
                              12695              58 :             tuple = systable_getnext(scan);
                              12696              58 :             if (!HeapTupleIsValid(tuple))
    2 alvherre                12697 UNC           0 :                 ereport(ERROR,
                              12698                 :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
                              12699                 :                          errmsg("constraint \"%s\" of relation \"%s\" does not exist",
                              12700                 :                                 constrName,
                              12701                 :                                 RelationGetRelationName(childrel))));
    2 alvherre                12702 GNC          58 :             copy_tuple = heap_copytuple(tuple);
                              12703              58 :             systable_endscan(scan);
                              12704                 :         }
                              12705                 : 
                              12706              84 :         childcon = (Form_pg_constraint) GETSTRUCT(copy_tuple);
                              12707                 : 
                              12708                 :         /* Right now only CHECK and NOT NULL constraints can be inherited */
                              12709              84 :         if (childcon->contype != CONSTRAINT_CHECK &&
                              12710              26 :             childcon->contype != CONSTRAINT_NOTNULL)
    2 alvherre                12711 UNC           0 :             elog(ERROR, "inherited constraint is not a CHECK or NOT NULL constraint");
                              12712                 : 
    2 alvherre                12713 GNC          84 :         if (childcon->coninhcount <= 0)   /* shouldn't happen */
 4200 rhaas                   12714 LBC           0 :             elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
 4200 rhaas                   12715 ECB             :                  childrelid, constrName);
                              12716                 : 
 4200 rhaas                   12717 CBC          84 :         if (recurse)
 4200 rhaas                   12718 ECB             :         {
                              12719                 :             /*
                              12720                 :              * If the child constraint has other definition sources, just
 3955 bruce                   12721                 :              * decrement its inheritance count; if not, recurse to delete it.
                              12722                 :              */
    2 alvherre                12723 GNC          81 :             if (childcon->coninhcount == 1 && !childcon->conislocal)
                              12724                 :             {
                              12725                 :                 /* Time to delete this child constraint, too */
                              12726              78 :                 dropconstraint_internal(childrel, copy_tuple, behavior,
                              12727                 :                                         recurse, true, missing_ok, readyRels,
                              12728                 :                                         lockmode);
                              12729                 :             }
 5448 tgl                     12730 ECB             :             else
                              12731                 :             {
                              12732                 :                 /* Child constraint must survive my deletion */
    2 alvherre                12733 GNC           3 :                 childcon->coninhcount--;
 2259 alvherre                12734 GIC           3 :                 CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
                              12735                 : 
                              12736                 :                 /* Make update visible */
 5448 tgl                     12737               3 :                 CommandCounterIncrement();
                              12738                 :             }
                              12739                 :         }
                              12740                 :         else
                              12741                 :         {
 4200 rhaas                   12742 ECB             :             /*
                              12743                 :              * If we were told to drop ONLY in this table (no recursion), we
                              12744                 :              * need to mark the inheritors' constraints as locally defined
                              12745                 :              * rather than inherited.
                              12746                 :              */
    2 alvherre                12747 GNC           3 :             childcon->coninhcount--;
                              12748               3 :             childcon->conislocal = true;
                              12749                 : 
 2259 alvherre                12750 GIC           3 :             CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
                              12751                 : 
                              12752                 :             /* Make update visible */
 4200 rhaas                   12753               3 :             CommandCounterIncrement();
 4200 rhaas                   12754 ECB             :         }
                              12755                 : 
 4200 rhaas                   12756 CBC          84 :         heap_freetuple(copy_tuple);
 5448 tgl                     12757 ECB             : 
 1539 andres                  12758 CBC          84 :         table_close(childrel, NoLock);
 6913 tgl                     12759 ECB             :     }
 5448                         12760                 : 
 1539 andres                  12761 CBC         278 :     table_close(conrel, RowExclusiveLock);
                              12762                 : 
    2 alvherre                12763 GNC         278 :     return conobj;
 6913 tgl                     12764 ECB             : }
                              12765                 : 
                              12766                 : /*
                              12767                 :  * ALTER COLUMN TYPE
 1180                         12768                 :  *
                              12769                 :  * Unlike other subcommand types, we do parse transformation for ALTER COLUMN
                              12770                 :  * TYPE during phase 1 --- the AlterTableCmd passed in here is already
                              12771                 :  * transformed (and must be, because we rely on some transformed fields).
                              12772                 :  *
                              12773                 :  * The point of this is that the execution of all ALTER COLUMN TYPEs for a
                              12774                 :  * table will be done "in parallel" during phase 3, so all the USING
                              12775                 :  * expressions should be parsed assuming the original column types.  Also,
                              12776                 :  * this allows a USING expression to refer to a field that will be dropped.
                              12777                 :  *
                              12778                 :  * To make this work safely, AT_PASS_DROP then AT_PASS_ALTER_TYPE must be
                              12779                 :  * the first two execution steps in phase 2; they must not see the effects
                              12780                 :  * of any other subcommand types, since the USING expressions are parsed
                              12781                 :  * against the unmodified table's state.
 6913                         12782                 :  */
                              12783                 : static void
 6913 tgl                     12784 CBC         550 : ATPrepAlterColumnType(List **wqueue,
 6913 tgl                     12785 ECB             :                       AlteredTableInfo *tab, Relation rel,
                              12786                 :                       bool recurse, bool recursing,
 1180                         12787                 :                       AlterTableCmd *cmd, LOCKMODE lockmode,
                              12788                 :                       AlterTableUtilityContext *context)
 6913                         12789                 : {
 6913 tgl                     12790 CBC         550 :     char       *colName = cmd->name;
 4414                         12791             550 :     ColumnDef  *def = (ColumnDef *) cmd->def;
                              12792             550 :     TypeName   *typeName = def->typeName;
 2928 alvherre                12793             550 :     Node       *transform = def->cooked_default;
 6913 tgl                     12794 ECB             :     HeapTuple   tuple;
                              12795                 :     Form_pg_attribute attTup;
 6913 tgl                     12796 EUB             :     AttrNumber  attnum;
                              12797                 :     Oid         targettype;
                              12798                 :     int32       targettypmod;
                              12799                 :     Oid         targetcollid;
                              12800                 :     NewColumnValue *newval;
 6913 tgl                     12801 GIC         550 :     ParseState *pstate = make_parsestate(NULL);
 4128 peter_e                 12802 ECB             :     AclResult   aclresult;
                              12803                 :     bool        is_expr;
                              12804                 : 
 4520 peter_e                 12805 GIC         550 :     if (rel->rd_rel->reloftype && !recursing)
 4643 peter_e                 12806 CBC           3 :         ereport(ERROR,
 4643 peter_e                 12807 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              12808                 :                  errmsg("cannot alter column type of typed table")));
                              12809                 : 
 6913 tgl                     12810                 :     /* lookup the attribute so we can check inheritance status */
 6913 tgl                     12811 GIC         547 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
                              12812             547 :     if (!HeapTupleIsValid(tuple))
 6913 tgl                     12813 UIC           0 :         ereport(ERROR,
                              12814                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                              12815                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
 6913 tgl                     12816 ECB             :                         colName, RelationGetRelationName(rel))));
 6913 tgl                     12817 CBC         547 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                              12818             547 :     attnum = attTup->attnum;
 6913 tgl                     12819 ECB             : 
                              12820                 :     /* Can't alter a system attribute */
 6913 tgl                     12821 CBC         547 :     if (attnum <= 0)
 6913 tgl                     12822 LBC           0 :         ereport(ERROR,
 6913 tgl                     12823 ECB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              12824                 :                  errmsg("cannot alter system column \"%s\"",
                              12825                 :                         colName)));
                              12826                 : 
 1330                         12827                 :     /*
                              12828                 :      * Don't alter inherited columns.  At outer level, there had better not be
                              12829                 :      * any inherited definition; when recursing, we assume this was checked at
                              12830                 :      * the parent level (see below).
                              12831                 :      */
 6913 tgl                     12832 CBC         547 :     if (attTup->attinhcount > 0 && !recursing)
                              12833               3 :         ereport(ERROR,
 6913 tgl                     12834 ECB             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              12835                 :                  errmsg("cannot alter inherited column \"%s\"",
                              12836                 :                         colName)));
                              12837                 : 
 2314 rhaas                   12838                 :     /* Don't alter columns used in the partition key */
 1921 rhaas                   12839 CBC         544 :     if (has_partition_attrs(rel,
 1921 rhaas                   12840 ECB             :                             bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
                              12841                 :                             &is_expr))
 1357 tgl                     12842 CBC           9 :         ereport(ERROR,
 1357 tgl                     12843 ECB             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              12844                 :                  errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
                              12845                 :                         colName, RelationGetRelationName(rel))));
 2314 rhaas                   12846                 : 
 6913 tgl                     12847                 :     /* Look up the target type */
 4414 tgl                     12848 CBC         535 :     typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
 4414 tgl                     12849 ECB             : 
  147 peter                   12850 GNC         535 :     aclresult = object_aclcheck(TypeRelationId, targettype, GetUserId(), ACL_USAGE);
 4128 peter_e                 12851 CBC         535 :     if (aclresult != ACLCHECK_OK)
 3950                         12852               6 :         aclcheck_error_type(aclresult, targettype);
 4128 peter_e                 12853 ECB             : 
 4414 tgl                     12854                 :     /* And the collation */
 4414 tgl                     12855 CBC         529 :     targetcollid = GetColumnDefCollation(NULL, def, targettype);
 6913 tgl                     12856 EUB             : 
                              12857                 :     /* make sure datatype is legal for a column */
 4395 tgl                     12858 GIC         529 :     CheckAttributeType(colName, targettype, targetcollid,
                              12859             529 :                        list_make1_oid(rel->rd_rel->reltype),
                              12860                 :                        0);
                              12861                 : 
 2314 rhaas                   12862 CBC         526 :     if (tab->relkind == RELKIND_RELATION ||
 2314 rhaas                   12863 GIC          95 :         tab->relkind == RELKIND_PARTITIONED_TABLE)
                              12864                 :     {
                              12865                 :         /*
 4382 bruce                   12866 ECB             :          * Set up an expression to transform the old data value to the new
 2878                         12867                 :          * type. If a USING option was given, use the expression as
                              12868                 :          * transformed by transformAlterTableStmt, else just take the old
                              12869                 :          * value and try to coerce it.  We do this first so that type
                              12870                 :          * incompatibility can be detected before we waste effort, and because
                              12871                 :          * we need the expression to be parsed against the original table row
                              12872                 :          * type.
                              12873                 :          */
 2928 alvherre                12874 GIC         458 :         if (!transform)
                              12875                 :         {
 4578 peter_e                 12876             356 :             transform = (Node *) makeVar(1, attnum,
                              12877                 :                                          attTup->atttypid, attTup->atttypmod,
                              12878                 :                                          attTup->attcollation,
 4578 peter_e                 12879 ECB             :                                          0);
                              12880                 :         }
                              12881                 : 
 4578 peter_e                 12882 GIC         458 :         transform = coerce_to_target_type(pstate,
                              12883                 :                                           transform, exprType(transform),
                              12884                 :                                           targettype, targettypmod,
 4578 peter_e                 12885 ECB             :                                           COERCION_ASSIGNMENT,
                              12886                 :                                           COERCE_IMPLICIT_CAST,
                              12887                 :                                           -1);
 4578 peter_e                 12888 CBC         458 :         if (transform == NULL)
                              12889                 :         {
                              12890                 :             /* error text depends on whether USING was specified or not */
 2858 tgl                     12891              12 :             if (def->cooked_default != NULL)
 2858 tgl                     12892 GIC           3 :                 ereport(ERROR,
                              12893                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              12894                 :                          errmsg("result of USING clause for column \"%s\""
                              12895                 :                                 " cannot be cast automatically to type %s",
                              12896                 :                                 colName, format_type_be(targettype)),
                              12897                 :                          errhint("You might need to add an explicit cast.")));
                              12898                 :             else
 2858 tgl                     12899 CBC           9 :                 ereport(ERROR,
                              12900                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              12901                 :                          errmsg("column \"%s\" cannot be cast automatically to type %s",
                              12902                 :                                 colName, format_type_be(targettype)),
                              12903                 :                 /* translator: USING is SQL, don't translate it */
                              12904                 :                          errhint("You might need to specify \"USING %s::%s\".",
                              12905                 :                                  quote_identifier(colName),
                              12906                 :                                  format_type_with_typemod(targettype,
                              12907                 :                                                           targettypmod))));
 2858 tgl                     12908 ECB             :         }
                              12909                 : 
                              12910                 :         /* Fix collations after all else */
 4404 tgl                     12911 CBC         446 :         assign_expr_collations(pstate, transform);
 4310 rhaas                   12912 EUB             : 
                              12913                 :         /* Plan the expr now so we can accurately assess the need to rewrite. */
 4310 rhaas                   12914 CBC         446 :         transform = (Node *) expression_planner((Expr *) transform);
                              12915                 : 
                              12916                 :         /*
                              12917                 :          * Add a work queue item to make ATRewriteTable update the column
                              12918                 :          * contents.
 4578 peter_e                 12919 ECB             :          */
 4578 peter_e                 12920 GIC         446 :         newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
                              12921             446 :         newval->attnum = attnum;
                              12922             446 :         newval->expr = (Expr *) transform;
 1187 tgl                     12923 CBC         446 :         newval->is_generated = false;
                              12924                 : 
 4578 peter_e                 12925 GIC         446 :         tab->newvals = lappend(tab->newvals, newval);
 4439 rhaas                   12926             446 :         if (ATColumnChangeRequiresRewrite(transform, attnum))
 3044 simon                   12927 CBC         364 :             tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
                              12928                 :     }
 4414 tgl                     12929 GIC          68 :     else if (transform)
                              12930               6 :         ereport(ERROR,
 4414 tgl                     12931 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              12932                 :                  errmsg("\"%s\" is not a table",
                              12933                 :                         RelationGetRelationName(rel))));
                              12934                 : 
  458 tgl                     12935 CBC         508 :     if (!RELKIND_HAS_STORAGE(tab->relkind))
                              12936                 :     {
 4578 peter_e                 12937 ECB             :         /*
                              12938                 :          * For relations without storage, do this check now.  Regular tables
  458 tgl                     12939                 :          * will check it later when the table is being rewritten.
                              12940                 :          */
 4440 rhaas                   12941 GIC          89 :         find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
 4578 peter_e                 12942 ECB             :     }
                              12943                 : 
 6913 tgl                     12944 CBC         493 :     ReleaseSysCache(tuple);
                              12945                 : 
 6913 tgl                     12946 ECB             :     /*
 2281 alvherre                12947                 :      * Recurse manually by queueing a new command for each child, if
                              12948                 :      * necessary. We cannot apply ATSimpleRecursion here because we need to
                              12949                 :      * remap attribute numbers in the USING expression, if any.
                              12950                 :      *
                              12951                 :      * If we are told not to recurse, there had better not be any child
                              12952                 :      * tables; else the alter would put them out of step.
                              12953                 :      */
 6913 tgl                     12954 GIC         493 :     if (recurse)
                              12955                 :     {
 2281 alvherre                12956             373 :         Oid         relid = RelationGetRelid(rel);
 1330 tgl                     12957 ECB             :         List       *child_oids,
                              12958                 :                    *child_numparents;
                              12959                 :         ListCell   *lo,
                              12960                 :                    *li;
                              12961                 : 
 1330 tgl                     12962 GIC         373 :         child_oids = find_all_inheritors(relid, lockmode,
                              12963                 :                                          &child_numparents);
                              12964                 : 
                              12965                 :         /*
                              12966                 :          * find_all_inheritors does the recursive search of the inheritance
                              12967                 :          * hierarchy, so all we have to do is process all of the relids in the
                              12968                 :          * list that it returns.
 2281 alvherre                12969 ECB             :          */
 1330 tgl                     12970 GIC         841 :         forboth(lo, child_oids, li, child_numparents)
                              12971                 :         {
                              12972             480 :             Oid         childrelid = lfirst_oid(lo);
                              12973             480 :             int         numparents = lfirst_int(li);
                              12974                 :             Relation    childrel;
                              12975                 :             HeapTuple   childtuple;
                              12976                 :             Form_pg_attribute childattTup;
                              12977                 : 
 2281 alvherre                12978 CBC         480 :             if (childrelid == relid)
                              12979             373 :                 continue;
                              12980                 : 
 2281 alvherre                12981 ECB             :             /* find_all_inheritors already got lock */
 2281 alvherre                12982 GIC         107 :             childrel = relation_open(childrelid, NoLock);
 2281 alvherre                12983 CBC         107 :             CheckTableNotInUse(childrel, "ALTER TABLE");
                              12984                 : 
 1330 tgl                     12985 ECB             :             /*
                              12986                 :              * Verify that the child doesn't have any inherited definitions of
                              12987                 :              * this column that came from outside this inheritance hierarchy.
 1330 tgl                     12988 EUB             :              * (renameatt makes a similar test, though in a different way
 1330 tgl                     12989 ECB             :              * because of its different recursion mechanism.)
                              12990                 :              */
 1330 tgl                     12991 CBC         107 :             childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
                              12992                 :                                                colName);
                              12993             107 :             if (!HeapTupleIsValid(childtuple))
 1330 tgl                     12994 LBC           0 :                 ereport(ERROR,
                              12995                 :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
                              12996                 :                          errmsg("column \"%s\" of relation \"%s\" does not exist",
                              12997                 :                                 colName, RelationGetRelationName(childrel))));
 1330 tgl                     12998 GIC         107 :             childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
                              12999                 : 
                              13000             107 :             if (childattTup->attinhcount > numparents)
 1330 tgl                     13001 CBC           3 :                 ereport(ERROR,
                              13002                 :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              13003                 :                          errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
                              13004                 :                                 colName, RelationGetRelationName(childrel))));
                              13005                 : 
                              13006             104 :             ReleaseSysCache(childtuple);
 1330 tgl                     13007 ECB             : 
 2281 alvherre                13008                 :             /*
                              13009                 :              * Remap the attribute numbers.  If no USING expression was
                              13010                 :              * specified, there is no need for this step.
                              13011                 :              */
 2281 alvherre                13012 GIC         104 :             if (def->cooked_default)
 2281 alvherre                13013 ECB             :             {
 1208 michael                 13014                 :                 AttrMap    *attmap;
                              13015                 :                 bool        found_whole_row;
                              13016                 : 
                              13017                 :                 /* create a copy to scribble on */
 2281 alvherre                13018 CBC          36 :                 cmd = copyObject(cmd);
 2281 alvherre                13019 ECB             : 
 1208 michael                 13020 GIC          36 :                 attmap = build_attrmap_by_name(RelationGetDescr(childrel),
                              13021                 :                                                RelationGetDescr(rel),
                              13022                 :                                                false);
 2281 alvherre                13023              72 :                 ((ColumnDef *) cmd->def)->cooked_default =
                              13024              36 :                     map_variable_attnos(def->cooked_default,
                              13025                 :                                         1, 0,
                              13026                 :                                         attmap,
                              13027                 :                                         InvalidOid, &found_whole_row);
                              13028              36 :                 if (found_whole_row)
                              13029               3 :                     ereport(ERROR,
 2281 alvherre                13030 ECB             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              13031                 :                              errmsg("cannot convert whole-row table reference"),
                              13032                 :                              errdetail("USING expression contains a whole-row table reference.")));
 2281 alvherre                13033 GIC          33 :                 pfree(attmap);
 2281 alvherre                13034 ECB             :             }
 1180 tgl                     13035 CBC         101 :             ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
 2281 alvherre                13036 GIC          95 :             relation_close(childrel, NoLock);
 2281 alvherre                13037 ECB             :         }
                              13038                 :     }
 6913 tgl                     13039 GIC         145 :     else if (!recursing &&
  711 alvherre                13040              25 :              find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
 6913 tgl                     13041 UIC           0 :         ereport(ERROR,
                              13042                 :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              13043                 :                  errmsg("type of inherited column \"%s\" must be changed in child tables too",
                              13044                 :                         colName)));
 4520 peter_e                 13045 ECB             : 
 4520 peter_e                 13046 GIC         481 :     if (tab->relkind == RELKIND_COMPOSITE_TYPE)
 1180 tgl                     13047 CBC          25 :         ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
 6913 tgl                     13048 GIC         478 : }
 6913 tgl                     13049 ECB             : 
 4439 rhaas                   13050 EUB             : /*
 4437 rhaas                   13051 ECB             :  * When the data type of a column is changed, a rewrite might not be required
                              13052                 :  * if the new type is sufficiently identical to the old one, and the USING
                              13053                 :  * clause isn't trying to insert some other value.  It's safe to skip the
 1493 noah                    13054                 :  * rewrite in these cases:
                              13055                 :  *
                              13056                 :  * - the old type is binary coercible to the new type
 1493 noah                    13057 EUB             :  * - the new type is an unconstrained domain over the old type
 1493 noah                    13058 ECB             :  * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
                              13059                 :  *
                              13060                 :  * In the case of a constrained domain, we could get by with scanning the
                              13061                 :  * table and checking the constraint rather than actually rewriting it, but we
                              13062                 :  * don't currently try to do that.
                              13063                 :  */
 4439 rhaas                   13064                 : static bool
 4439 rhaas                   13065 GIC         446 : ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
                              13066                 : {
                              13067             446 :     Assert(expr != NULL);
                              13068                 : 
                              13069                 :     for (;;)
                              13070                 :     {
                              13071                 :         /* only one varno, so no need to check that */
 1058 tgl                     13072             498 :         if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
 4439 rhaas                   13073 CBC          82 :             return false;
                              13074             416 :         else if (IsA(expr, RelabelType))
 4439 rhaas                   13075 GIC          46 :             expr = (Node *) ((RelabelType *) expr)->arg;
 4437                         13076             370 :         else if (IsA(expr, CoerceToDomain))
                              13077                 :         {
 4437 rhaas                   13078 UIC           0 :             CoerceToDomain *d = (CoerceToDomain *) expr;
 4437 rhaas                   13079 ECB             : 
 2961 tgl                     13080 LBC           0 :             if (DomainHasConstraints(d->resulttype))
 4437 rhaas                   13081               0 :                 return true;
 4437 rhaas                   13082 UIC           0 :             expr = (Node *) d->arg;
                              13083                 :         }
 1493 noah                    13084 GIC         370 :         else if (IsA(expr, FuncExpr))
                              13085                 :         {
                              13086             270 :             FuncExpr   *f = (FuncExpr *) expr;
 1493 noah                    13087 ECB             : 
 1493 noah                    13088 CBC         270 :             switch (f->funcid)
                              13089                 :             {
 1493 noah                    13090 GIC           9 :                 case F_TIMESTAMPTZ_TIMESTAMP:
                              13091                 :                 case F_TIMESTAMP_TIMESTAMPTZ:
                              13092               9 :                     if (TimestampTimestampTzRequiresRewrite())
                              13093               3 :                         return true;
                              13094                 :                     else
 1493 noah                    13095 CBC           6 :                         expr = linitial(f->args);
 1493 noah                    13096 GIC           6 :                     break;
                              13097             261 :                 default:
                              13098             261 :                     return true;
                              13099                 :             }
                              13100                 :         }
                              13101                 :         else
 4439 rhaas                   13102             100 :             return true;
 4439 rhaas                   13103 ECB             :     }
                              13104                 : }
                              13105                 : 
                              13106                 : /*
                              13107                 :  * ALTER COLUMN .. SET DATA TYPE
                              13108                 :  *
                              13109                 :  * Return the address of the modified column.
                              13110                 :  */
 2937 alvherre                13111                 : static ObjectAddress
 6913 tgl                     13112 CBC         463 : ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                              13113                 :                       AlterTableCmd *cmd, LOCKMODE lockmode)
 6913 tgl                     13114 ECB             : {
 4414 tgl                     13115 GIC         463 :     char       *colName = cmd->name;
 4414 tgl                     13116 CBC         463 :     ColumnDef  *def = (ColumnDef *) cmd->def;
 4414 tgl                     13117 GIC         463 :     TypeName   *typeName = def->typeName;
 6913 tgl                     13118 ECB             :     HeapTuple   heapTup;
                              13119                 :     Form_pg_attribute attTup,
                              13120                 :                 attOldTup;
                              13121                 :     AttrNumber  attnum;
                              13122                 :     HeapTuple   typeTuple;
                              13123                 :     Form_pg_type tform;
                              13124                 :     Oid         targettype;
                              13125                 :     int32       targettypmod;
                              13126                 :     Oid         targetcollid;
                              13127                 :     Node       *defaultexpr;
                              13128                 :     Relation    attrelation;
 6913 tgl                     13129 EUB             :     Relation    depRel;
 6913 tgl                     13130 ECB             :     ScanKeyData key[3];
                              13131                 :     SysScanDesc scan;
                              13132                 :     HeapTuple   depTup;
                              13133                 :     ObjectAddress address;
                              13134                 : 
                              13135                 :     /*
                              13136                 :      * Clear all the missing values if we're rewriting the table, since this
                              13137                 :      * renders them pointless.
                              13138                 :      */
 1550 andrew                  13139 GIC         463 :     if (tab->rewrite)
                              13140                 :     {
                              13141                 :         Relation    newrel;
                              13142                 : 
 1539 andres                  13143 CBC         337 :         newrel = table_open(RelationGetRelid(rel), NoLock);
 1550 andrew                  13144             337 :         RelationClearMissing(newrel);
                              13145             337 :         relation_close(newrel, NoLock);
                              13146                 :         /* make sure we don't conflict with later attribute modifications */
                              13147             337 :         CommandCounterIncrement();
                              13148                 :     }
                              13149                 : 
 1539 andres                  13150 GIC         463 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                              13151                 : 
                              13152                 :     /* Look up the target column */
 6913 tgl                     13153 CBC         463 :     heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
 2118 tgl                     13154 GBC         463 :     if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
 6913 tgl                     13155 UIC           0 :         ereport(ERROR,
                              13156                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                              13157                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                              13158                 :                         colName, RelationGetRelationName(rel))));
 6913 tgl                     13159 GIC         463 :     attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
                              13160             463 :     attnum = attTup->attnum;
 2058 andres                  13161             463 :     attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
                              13162                 : 
                              13163                 :     /* Check for multiple ALTER TYPE on same column --- can't cope */
                              13164             463 :     if (attTup->atttypid != attOldTup->atttypid ||
 2058 andres                  13165 CBC         463 :         attTup->atttypmod != attOldTup->atttypmod)
 6913 tgl                     13166 LBC           0 :         ereport(ERROR,
                              13167                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              13168                 :                  errmsg("cannot alter type of column \"%s\" twice",
                              13169                 :                         colName)));
                              13170                 : 
                              13171                 :     /* Look up the target type (should not fail, since prep found it) */
 4414 tgl                     13172 CBC         463 :     typeTuple = typenameType(NULL, typeName, &targettypmod);
 6913 tgl                     13173 GIC         463 :     tform = (Form_pg_type) GETSTRUCT(typeTuple);
 1601 andres                  13174 CBC         463 :     targettype = tform->oid;
 4414 tgl                     13175 ECB             :     /* And the collation */
 4414 tgl                     13176 GIC         463 :     targetcollid = GetColumnDefCollation(NULL, def, targettype);
                              13177                 : 
 6913 tgl                     13178 ECB             :     /*
                              13179                 :      * If there is a default expression for the column, get it and ensure we
                              13180                 :      * can coerce it to the new datatype.  (We must do this before changing
                              13181                 :      * the column type, because build_column_default itself will try to
                              13182                 :      * coerce, and will not issue the error message we want if it fails.)
                              13183                 :      *
                              13184                 :      * We remove any implicit coercion steps at the top level of the old
 6347 bruce                   13185                 :      * default expression; this has been agreed to satisfy the principle of
 3260                         13186                 :      * least surprise.  (The conversion to the new column type should act like
                              13187                 :      * it started from what the user sees as the stored expression, and the
 6385                         13188                 :      * implicit coercions aren't going to be shown.)
 6913 tgl                     13189                 :      */
 6913 tgl                     13190 GIC         463 :     if (attTup->atthasdef)
                              13191                 :     {
                              13192              31 :         defaultexpr = build_column_default(rel, attnum);
                              13193              31 :         Assert(defaultexpr);
 6743                         13194              31 :         defaultexpr = strip_implicit_coercions(defaultexpr);
 2118                         13195              31 :         defaultexpr = coerce_to_target_type(NULL,   /* no UNKNOWN params */
                              13196                 :                                             defaultexpr, exprType(defaultexpr),
 5944 tgl                     13197 ECB             :                                             targettype, targettypmod,
 6913                         13198                 :                                             COERCION_ASSIGNMENT,
                              13199                 :                                             COERCE_IMPLICIT_CAST,
 5337                         13200                 :                                             -1);
 6913 tgl                     13201 GIC          31 :         if (defaultexpr == NULL)
                              13202                 :         {
 1471 peter                   13203               6 :             if (attTup->attgenerated)
                              13204               3 :                 ereport(ERROR,
                              13205                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              13206                 :                          errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
 1471 peter                   13207 ECB             :                                 colName, format_type_be(targettype))));
                              13208                 :             else
 1471 peter                   13209 CBC           3 :                 ereport(ERROR,
                              13210                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              13211                 :                          errmsg("default for column \"%s\" cannot be cast automatically to type %s",
                              13212                 :                                 colName, format_type_be(targettype))));
                              13213                 :         }
                              13214                 :     }
 6913 tgl                     13215 ECB             :     else
 6913 tgl                     13216 CBC         432 :         defaultexpr = NULL;
                              13217                 : 
                              13218                 :     /*
 6385 bruce                   13219 ECB             :      * Find everything that depends on the column (constraints, indexes, etc),
                              13220                 :      * and record enough information to let us recreate the objects.
 6913 tgl                     13221                 :      *
                              13222                 :      * The actual recreation does not happen here, but only after we have
 3260 bruce                   13223                 :      * performed all the individual ALTER TYPE operations.  We have to save
                              13224                 :      * the info before executing ALTER TYPE, though, else the deparser will
                              13225                 :      * get confused.
                              13226                 :      */
 1539 andres                  13227 GIC         457 :     depRel = table_open(DependRelationId, RowExclusiveLock);
                              13228                 : 
 6913 tgl                     13229             457 :     ScanKeyInit(&key[0],
                              13230                 :                 Anum_pg_depend_refclassid,
 6913 tgl                     13231 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
 6569                         13232                 :                 ObjectIdGetDatum(RelationRelationId));
 6913 tgl                     13233 GIC         457 :     ScanKeyInit(&key[1],
                              13234                 :                 Anum_pg_depend_refobjid,
 6913 tgl                     13235 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              13236                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
 6913 tgl                     13237 GIC         457 :     ScanKeyInit(&key[2],
                              13238                 :                 Anum_pg_depend_refobjsubid,
                              13239                 :                 BTEqualStrategyNumber, F_INT4EQ,
                              13240                 :                 Int32GetDatum((int32) attnum));
                              13241                 : 
 6569 tgl                     13242 CBC         457 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
                              13243                 :                               NULL, 3, key);
 6913 tgl                     13244 ECB             : 
 6913 tgl                     13245 GIC         847 :     while (HeapTupleIsValid(depTup = systable_getnext(scan)))
                              13246                 :     {
 6797 bruce                   13247             402 :         Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
 6797 bruce                   13248 ECB             :         ObjectAddress foundObject;
 6913 tgl                     13249                 : 
 6913 tgl                     13250 GIC         402 :         foundObject.classId = foundDep->classid;
                              13251             402 :         foundObject.objectId = foundDep->objid;
                              13252             402 :         foundObject.objectSubId = foundDep->objsubid;
 6913 tgl                     13253 ECB             : 
 6913 tgl                     13254 GIC         402 :         switch (getObjectClass(&foundObject))
 6913 tgl                     13255 ECB             :         {
 6913 tgl                     13256 GIC         123 :             case OCLASS_CLASS:
 6913 tgl                     13257 ECB             :                 {
 6797 bruce                   13258 GIC         123 :                     char        relKind = get_rel_relkind(foundObject.objectId);
                              13259                 : 
 1906 alvherre                13260 CBC         123 :                     if (relKind == RELKIND_INDEX ||
 1906 alvherre                13261 ECB             :                         relKind == RELKIND_PARTITIONED_INDEX)
 6913 tgl                     13262                 :                     {
 6797 bruce                   13263 CBC         107 :                         Assert(foundObject.objectSubId == 0);
 1385 tgl                     13264             107 :                         RememberIndexForRebuilding(foundObject.objectId, tab);
                              13265                 :                     }
 6797 bruce                   13266              16 :                     else if (relKind == RELKIND_SEQUENCE)
 6797 bruce                   13267 ECB             :                     {
                              13268                 :                         /*
 6385                         13269                 :                          * This must be a SERIAL column's sequence.  We need
 6385 bruce                   13270 EUB             :                          * not do anything to it.
                              13271                 :                          */
 6797 bruce                   13272 GIC          16 :                         Assert(foundObject.objectSubId == 0);
 6797 bruce                   13273 ECB             :                     }
                              13274                 :                     else
                              13275                 :                     {
                              13276                 :                         /* Not expecting any other direct dependencies... */
 6797 bruce                   13277 UIC           0 :                         elog(ERROR, "unexpected object depending on column: %s",
  998 michael                 13278 ECB             :                              getObjectDescription(&foundObject, false));
                              13279                 :                     }
 6797 bruce                   13280 GIC         123 :                     break;
                              13281                 :                 }
 6913 tgl                     13282 ECB             : 
 6913 tgl                     13283 GIC         235 :             case OCLASS_CONSTRAINT:
                              13284             235 :                 Assert(foundObject.objectSubId == 0);
 1385                         13285             235 :                 RememberConstraintForRebuilding(foundObject.objectId, tab);
 6913 tgl                     13286 CBC         235 :                 break;
                              13287                 : 
 6913 tgl                     13288 GIC           6 :             case OCLASS_REWRITE:
                              13289                 :                 /* XXX someday see if we can cope with revising views */
 6913 tgl                     13290 CBC           6 :                 ereport(ERROR,
                              13291                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              13292                 :                          errmsg("cannot alter type of a column used by a view or rule"),
 6913 tgl                     13293 ECB             :                          errdetail("%s depends on column \"%s\"",
  998 michael                 13294                 :                                    getObjectDescription(&foundObject, false),
 6913 tgl                     13295 EUB             :                                    colName)));
                              13296                 :                 break;
                              13297                 : 
 4572 tgl                     13298 UIC           0 :             case OCLASS_TRIGGER:
                              13299                 : 
 4572 tgl                     13300 ECB             :                 /*
                              13301                 :                  * A trigger can depend on a column because the column is
                              13302                 :                  * specified as an update target, or because the column is
                              13303                 :                  * used in the trigger's WHEN condition.  The first case would
                              13304                 :                  * not require any extra work, but the second case would
                              13305                 :                  * require updating the WHEN expression, which will take a
                              13306                 :                  * significant amount of new code.  Since we can't easily tell
                              13307                 :                  * which case applies, we punt for both.  FIXME someday.
                              13308                 :                  */
 4572 tgl                     13309 UBC           0 :                 ereport(ERROR,
                              13310                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 4572 tgl                     13311 ECB             :                          errmsg("cannot alter type of a column used in a trigger definition"),
 4572 tgl                     13312 EUB             :                          errdetail("%s depends on column \"%s\"",
                              13313                 :                                    getObjectDescription(&foundObject, false),
                              13314                 :                                    colName)));
 4572 tgl                     13315 ECB             :                 break;
                              13316                 : 
 3055 sfrost                  13317 UIC           0 :             case OCLASS_POLICY:
                              13318                 : 
                              13319                 :                 /*
                              13320                 :                  * A policy can depend on a column because the column is
 3055 sfrost                  13321 ECB             :                  * specified in the policy's USING or WITH CHECK qual
                              13322                 :                  * expressions.  It might be possible to rewrite and recheck
                              13323                 :                  * the policy expression, but punt for now.  It's certainly
 2878 bruce                   13324                 :                  * easy enough to remove and recreate the policy; still, FIXME
                              13325                 :                  * someday.
                              13326                 :                  */
 3055 sfrost                  13327 UIC           0 :                 ereport(ERROR,
                              13328                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              13329                 :                          errmsg("cannot alter type of a column used in a policy definition"),
                              13330                 :                          errdetail("%s depends on column \"%s\"",
  998 michael                 13331 ECB             :                                    getObjectDescription(&foundObject, false),
 3055 sfrost                  13332                 :                                    colName)));
                              13333                 :                 break;
                              13334                 : 
 6913 tgl                     13335 CBC          31 :             case OCLASS_DEFAULT:
                              13336                 :                 {
  384 tgl                     13337 GIC          31 :                     ObjectAddress col = GetAttrDefaultColumnAddress(foundObject.objectId);
                              13338                 : 
                              13339              31 :                     if (col.objectId == RelationGetRelid(rel) &&
                              13340              31 :                         col.objectSubId == attnum)
                              13341                 :                     {
                              13342                 :                         /*
                              13343                 :                          * Ignore the column's own default expression, which
                              13344                 :                          * we will deal with below.
  384 tgl                     13345 ECB             :                          */
  384 tgl                     13346 CBC          25 :                         Assert(defaultexpr);
                              13347                 :                     }
  384 tgl                     13348 ECB             :                     else
                              13349                 :                     {
                              13350                 :                         /*
                              13351                 :                          * This must be a reference from the expression of a
                              13352                 :                          * generated column elsewhere in the same table.
                              13353                 :                          * Changing the type of a column that is used by a
                              13354                 :                          * generated column is not allowed by SQL standard, so
                              13355                 :                          * just punt for now.  It might be doable with some
                              13356                 :                          * thinking and effort.
                              13357                 :                          */
  384 tgl                     13358 GIC           6 :                         ereport(ERROR,
  384 tgl                     13359 ECB             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              13360                 :                                  errmsg("cannot alter type of a column used by a generated column"),
                              13361                 :                                  errdetail("Column \"%s\" is used by generated column \"%s\".",
                              13362                 :                                            colName,
                              13363                 :                                            get_attname(col.objectId,
                              13364                 :                                                        col.objectSubId,
                              13365                 :                                                        false))));
                              13366                 :                     }
  384 tgl                     13367 GIC          25 :                     break;
                              13368                 :                 }
                              13369                 : 
 2156                         13370               7 :             case OCLASS_STATISTIC_EXT:
                              13371                 : 
                              13372                 :                 /*
                              13373                 :                  * Give the extended-stats machinery a chance to fix anything
                              13374                 :                  * that this column type change would break.
                              13375                 :                  */
  744 tomas.vondra            13376               7 :                 RememberStatisticsForRebuilding(foundObject.objectId, tab);
 2156 tgl                     13377               7 :                 break;
                              13378                 : 
 6913 tgl                     13379 UIC           0 :             case OCLASS_PROC:
                              13380                 :             case OCLASS_TYPE:
                              13381                 :             case OCLASS_CAST:
 4439 peter_e                 13382 ECB             :             case OCLASS_COLLATION:
                              13383                 :             case OCLASS_CONVERSION:
                              13384                 :             case OCLASS_LANGUAGE:
                              13385                 :             case OCLASS_LARGEOBJECT:
                              13386                 :             case OCLASS_OPERATOR:
                              13387                 :             case OCLASS_OPCLASS:
 5710 tgl                     13388                 :             case OCLASS_OPFAMILY:
 2156                         13389                 :             case OCLASS_AM:
 4993                         13390                 :             case OCLASS_AMOP:
                              13391                 :             case OCLASS_AMPROC:
                              13392                 :             case OCLASS_SCHEMA:
                              13393                 :             case OCLASS_TSPARSER:
                              13394                 :             case OCLASS_TSDICT:
                              13395                 :             case OCLASS_TSTEMPLATE:
                              13396                 :             case OCLASS_TSCONFIG:
                              13397                 :             case OCLASS_ROLE:
                              13398                 :             case OCLASS_ROLE_MEMBERSHIP:
                              13399                 :             case OCLASS_DATABASE:
                              13400                 :             case OCLASS_TBLSPACE:
                              13401                 :             case OCLASS_FDW:
                              13402                 :             case OCLASS_FOREIGN_SERVER:
                              13403                 :             case OCLASS_USER_MAPPING:
 4934                         13404                 :             case OCLASS_DEFACL:
 4443                         13405                 :             case OCLASS_EXTENSION:
                              13406                 :             case OCLASS_EVENT_TRIGGER:
                              13407                 :             case OCLASS_PARAMETER_ACL:
                              13408                 :             case OCLASS_PUBLICATION:
                              13409                 :             case OCLASS_PUBLICATION_NAMESPACE:
 2156                         13410                 :             case OCLASS_PUBLICATION_REL:
                              13411                 :             case OCLASS_SUBSCRIPTION:
 2156 tgl                     13412 EUB             :             case OCLASS_TRANSFORM:
                              13413                 : 
                              13414                 :                 /*
                              13415                 :                  * We don't expect any of these sorts of objects to depend on
 6385 bruce                   13416 ECB             :                  * a column.
 6913 tgl                     13417                 :                  */
 6913 tgl                     13418 UIC           0 :                 elog(ERROR, "unexpected object depending on column: %s",
                              13419                 :                      getObjectDescription(&foundObject, false));
 6913 tgl                     13420 ECB             :                 break;
 6913 tgl                     13421 EUB             : 
                              13422                 :                 /*
                              13423                 :                  * There's intentionally no default: case here; we want the
                              13424                 :                  * compiler to warn if a new OCLASS hasn't been handled above.
                              13425                 :                  */
                              13426                 :         }
                              13427                 :     }
                              13428                 : 
 6913 tgl                     13429 GIC         445 :     systable_endscan(scan);
                              13430                 : 
 6913 tgl                     13431 ECB             :     /*
                              13432                 :      * Now scan for dependencies of this column on other things.  The only
                              13433                 :      * things we should find are the dependency on the column datatype and
                              13434                 :      * possibly a collation dependency.  Those can be removed.
                              13435                 :      */
 6913 tgl                     13436 GIC         445 :     ScanKeyInit(&key[0],
                              13437                 :                 Anum_pg_depend_classid,
 6913 tgl                     13438 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              13439                 :                 ObjectIdGetDatum(RelationRelationId));
 6913 tgl                     13440 GIC         445 :     ScanKeyInit(&key[1],
 6913 tgl                     13441 ECB             :                 Anum_pg_depend_objid,
                              13442                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              13443                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
 6913 tgl                     13444 GIC         445 :     ScanKeyInit(&key[2],
                              13445                 :                 Anum_pg_depend_objsubid,
                              13446                 :                 BTEqualStrategyNumber, F_INT4EQ,
 6913 tgl                     13447 ECB             :                 Int32GetDatum((int32) attnum));
                              13448                 : 
 6569 tgl                     13449 CBC         445 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
 3568 rhaas                   13450 ECB             :                               NULL, 3, key);
 6913 tgl                     13451                 : 
 6913 tgl                     13452 GIC         447 :     while (HeapTupleIsValid(depTup = systable_getnext(scan)))
                              13453                 :     {
 6797 bruce                   13454 CBC           2 :         Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
                              13455                 :         ObjectAddress foundObject;
                              13456                 : 
 1471 peter                   13457               2 :         foundObject.classId = foundDep->refclassid;
                              13458               2 :         foundObject.objectId = foundDep->refobjid;
 1471 peter                   13459 GIC           2 :         foundObject.objectSubId = foundDep->refobjsubid;
                              13460                 : 
  384 tgl                     13461 CBC           2 :         if (foundDep->deptype != DEPENDENCY_NORMAL)
 6913 tgl                     13462 LBC           0 :             elog(ERROR, "found unexpected dependency type '%c'",
                              13463                 :                  foundDep->deptype);
 4439 peter_e                 13464 GIC           2 :         if (!(foundDep->refclassid == TypeRelationId &&
                              13465               2 :               foundDep->refobjid == attTup->atttypid) &&
 4439 peter_e                 13466 UIC           0 :             !(foundDep->refclassid == CollationRelationId &&
  384 tgl                     13467               0 :               foundDep->refobjid == attTup->attcollation))
 1471 peter                   13468               0 :             elog(ERROR, "found unexpected dependency for column: %s",
                              13469                 :                  getObjectDescription(&foundObject, false));
                              13470                 : 
 2258 tgl                     13471 GIC           2 :         CatalogTupleDelete(depRel, &depTup->t_self);
                              13472                 :     }
 6913 tgl                     13473 ECB             : 
 6913 tgl                     13474 GIC         445 :     systable_endscan(scan);
 6913 tgl                     13475 ECB             : 
 1539 andres                  13476 GIC         445 :     table_close(depRel, RowExclusiveLock);
                              13477                 : 
                              13478                 :     /*
                              13479                 :      * Here we go --- change the recorded column type and collation.  (Note
                              13480                 :      * heapTup is a copy of the syscache entry, so okay to scribble on.) First
 1418 tgl                     13481 ECB             :      * fix up the missing value if any.
                              13482                 :      */
 1550 andrew                  13483 GIC         445 :     if (attTup->atthasmissing)
                              13484                 :     {
                              13485                 :         Datum       missingval;
                              13486                 :         bool        missingNull;
 1550 andrew                  13487 ECB             : 
                              13488                 :         /* if rewrite is true the missing value should already be cleared */
 1550 andrew                  13489 GIC           3 :         Assert(tab->rewrite == 0);
 1550 andrew                  13490 ECB             : 
                              13491                 :         /* Get the missing value datum */
 1550 andrew                  13492 GIC           3 :         missingval = heap_getattr(heapTup,
                              13493                 :                                   Anum_pg_attribute_attmissingval,
                              13494                 :                                   attrelation->rd_att,
                              13495                 :                                   &missingNull);
                              13496                 : 
                              13497                 :         /* if it's a null array there is nothing to do */
 1550 andrew                  13498 ECB             : 
 1418 tgl                     13499 GIC           3 :         if (!missingNull)
                              13500                 :         {
                              13501                 :             /*
                              13502                 :              * Get the datum out of the array and repack it in a new array
                              13503                 :              * built with the new type data. We assume that since the table
                              13504                 :              * doesn't need rewriting, the actual Datum doesn't need to be
                              13505                 :              * changed, only the array metadata.
                              13506                 :              */
                              13507                 : 
                              13508               3 :             int         one = 1;
                              13509                 :             bool        isNull;
  267 peter                   13510 GNC           3 :             Datum       valuesAtt[Natts_pg_attribute] = {0};
                              13511               3 :             bool        nullsAtt[Natts_pg_attribute] = {0};
                              13512               3 :             bool        replacesAtt[Natts_pg_attribute] = {0};
 1418 tgl                     13513 ECB             :             HeapTuple   newTup;
                              13514                 : 
 1550 andrew                  13515 CBC           6 :             missingval = array_get_element(missingval,
 1550 andrew                  13516 ECB             :                                            1,
                              13517                 :                                            &one,
                              13518                 :                                            0,
 1550 andrew                  13519 GIC           3 :                                            attTup->attlen,
 1550 andrew                  13520 CBC           3 :                                            attTup->attbyval,
                              13521               3 :                                            attTup->attalign,
 1550 andrew                  13522 ECB             :                                            &isNull);
 1165 alvherre                13523 GIC           3 :             missingval = PointerGetDatum(construct_array(&missingval,
 1418 tgl                     13524 ECB             :                                                          1,
                              13525                 :                                                          targettype,
 1418 tgl                     13526 GIC           3 :                                                          tform->typlen,
                              13527               3 :                                                          tform->typbyval,
                              13528               3 :                                                          tform->typalign));
                              13529                 : 
 1550 andrew                  13530 CBC           3 :             valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
 1550 andrew                  13531 GIC           3 :             replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
                              13532               3 :             nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
                              13533                 : 
 1549                         13534               3 :             newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
                              13535                 :                                        valuesAtt, nullsAtt, replacesAtt);
 1549 andrew                  13536 CBC           3 :             heap_freetuple(heapTup);
 1549 andrew                  13537 GIC           3 :             heapTup = newTup;
 1550                         13538               3 :             attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
 1550 andrew                  13539 ECB             :         }
                              13540                 :     }
                              13541                 : 
 6913 tgl                     13542 GIC         445 :     attTup->atttypid = targettype;
 5944                         13543             445 :     attTup->atttypmod = targettypmod;
 4443 peter_e                 13544             445 :     attTup->attcollation = targetcollid;
   12 peter                   13545 GNC         445 :     if (list_length(typeName->arrayBounds) > PG_INT16_MAX)
   12 peter                   13546 UNC           0 :         ereport(ERROR,
                              13547                 :                 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                              13548                 :                 errmsg("too many array dimensions"));
 5015 peter_e                 13549 GIC         445 :     attTup->attndims = list_length(typeName->arrayBounds);
 6913 tgl                     13550             445 :     attTup->attlen = tform->typlen;
                              13551             445 :     attTup->attbyval = tform->typbyval;
                              13552             445 :     attTup->attalign = tform->typalign;
 6913 tgl                     13553 CBC         445 :     attTup->attstorage = tform->typstorage;
  682 tgl                     13554 GIC         445 :     attTup->attcompression = InvalidCompressionMethod;
  751 rhaas                   13555 ECB             : 
  751 rhaas                   13556 GIC         445 :     ReleaseSysCache(typeTuple);
                              13557                 : 
 2259 alvherre                13558             445 :     CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
                              13559                 : 
 1539 andres                  13560             445 :     table_close(attrelation, RowExclusiveLock);
 7576 tgl                     13561 ECB             : 
                              13562                 :     /* Install dependencies on new datatype and collation */
 4370 tgl                     13563 GIC         445 :     add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
                              13564             445 :     add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
                              13565                 : 
                              13566                 :     /*
                              13567                 :      * Drop any pg_statistic entry for the column, since it's now wrong type
                              13568                 :      */
 6798 tgl                     13569 CBC         445 :     RemoveStatistics(RelationGetRelid(rel), attnum);
                              13570                 : 
 3675 rhaas                   13571             445 :     InvokeObjectPostAlterHook(RelationRelationId,
 3675 rhaas                   13572 ECB             :                               RelationGetRelid(rel), attnum);
                              13573                 : 
                              13574                 :     /*
                              13575                 :      * Update the default, if present, by brute force --- remove and re-add
                              13576                 :      * the default.  Probably unsafe to take shortcuts, since the new version
 6385 bruce                   13577                 :      * may well have additional dependencies.  (It's okay to do this now,
                              13578                 :      * rather than after other ALTER TYPE commands, since the default won't
                              13579                 :      * depend on other column types.)
                              13580                 :      */
 6913 tgl                     13581 CBC         445 :     if (defaultexpr)
 7576 tgl                     13582 ECB             :     {
                              13583                 :         /*
                              13584                 :          * If it's a GENERATED default, drop its dependency records, in
                              13585                 :          * particular its INTERNAL dependency on the column, which would
                              13586                 :          * otherwise cause dependency.c to refuse to perform the deletion.
                              13587                 :          */
  384 tgl                     13588 GIC          25 :         if (attTup->attgenerated)
                              13589                 :         {
  384 tgl                     13590 CBC           3 :             Oid         attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
                              13591                 : 
                              13592               3 :             if (!OidIsValid(attrdefoid))
  384 tgl                     13593 UBC           0 :                 elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
                              13594                 :                      RelationGetRelid(rel), attnum);
  384 tgl                     13595 GIC           3 :             (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
                              13596                 :         }
  384 tgl                     13597 ECB             : 
                              13598                 :         /*
                              13599                 :          * Make updates-so-far visible, particularly the new pg_attribute row
                              13600                 :          * which will be updated again.
                              13601                 :          */
 6913 tgl                     13602 GIC          25 :         CommandCounterIncrement();
                              13603                 : 
                              13604                 :         /*
 6385 bruce                   13605 ECB             :          * We use RESTRICT here for safety, but at present we do not expect
                              13606                 :          * anything to depend on the default.
                              13607                 :          */
 4091 rhaas                   13608 GIC          25 :         RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
                              13609                 :                           true);
                              13610                 : 
 1838 andrew                  13611 CBC          25 :         StoreAttrDefault(rel, attnum, defaultexpr, true, false);
                              13612                 :     }
                              13613                 : 
 2937 alvherre                13614 GIC         445 :     ObjectAddressSubSet(address, RelationRelationId,
                              13615                 :                         RelationGetRelid(rel), attnum);
                              13616                 : 
 6913 tgl                     13617 ECB             :     /* Cleanup */
 6913 tgl                     13618 GIC         445 :     heap_freetuple(heapTup);
 2937 alvherre                13619 ECB             : 
 2937 alvherre                13620 GIC         445 :     return address;
                              13621                 : }
 7576 tgl                     13622 ECB             : 
 1122 peter                   13623                 : /*
                              13624                 :  * Subroutine for ATExecAlterColumnType: remember that a replica identity
                              13625                 :  * needs to be reset.
                              13626                 :  */
                              13627                 : static void
 1122 peter                   13628 CBC         199 : RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
                              13629                 : {
 1122 peter                   13630 GIC         199 :     if (!get_index_isreplident(indoid))
                              13631             190 :         return;
 1122 peter                   13632 ECB             : 
 1122 peter                   13633 GIC           9 :     if (tab->replicaIdentityIndex)
 1122 peter                   13634 LBC           0 :         elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
 1122 peter                   13635 ECB             : 
 1122 peter                   13636 GIC           9 :     tab->replicaIdentityIndex = get_rel_name(indoid);
                              13637                 : }
 1122 peter                   13638 ECB             : 
 1098 michael                 13639                 : /*
 1098 michael                 13640 EUB             :  * Subroutine for ATExecAlterColumnType: remember any clustered index.
                              13641                 :  */
                              13642                 : static void
 1098 michael                 13643 GIC         199 : RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
                              13644                 : {
 1098 michael                 13645 CBC         199 :     if (!get_index_isclustered(indoid))
                              13646             190 :         return;
 1098 michael                 13647 ECB             : 
 1098 michael                 13648 GIC           9 :     if (tab->clusterOnIndex)
 1098 michael                 13649 UIC           0 :         elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
                              13650                 : 
 1098 michael                 13651 GIC           9 :     tab->clusterOnIndex = get_rel_name(indoid);
                              13652                 : }
                              13653                 : 
                              13654                 : /*
                              13655                 :  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
                              13656                 :  * to be rebuilt (which we might already know).
                              13657                 :  */
                              13658                 : static void
 1385 tgl                     13659             241 : RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
                              13660                 : {
                              13661                 :     /*
                              13662                 :      * This de-duplication check is critical for two independent reasons: we
                              13663                 :      * mustn't try to recreate the same constraint twice, and if a constraint
 1385 tgl                     13664 ECB             :      * depends on more than one column whose type is to be altered, we must
                              13665                 :      * capture its definition string before applying any of the column type
                              13666                 :      * changes.  ruleutils.c will get confused if we ask again later.
                              13667                 :      */
 1385 tgl                     13668 GIC         241 :     if (!list_member_oid(tab->changedConstraintOids, conoid))
                              13669                 :     {
                              13670                 :         /* OK, capture the constraint's existing definition string */
 1385 tgl                     13671 CBC         202 :         char       *defstring = pg_get_constraintdef_command(conoid);
 1122 peter                   13672 ECB             :         Oid         indoid;
 1385 tgl                     13673                 : 
 1385 tgl                     13674 CBC         202 :         tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
 1385 tgl                     13675 ECB             :                                                  conoid);
 1385 tgl                     13676 GIC         202 :         tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
 1385 tgl                     13677 EUB             :                                              defstring);
                              13678                 : 
 1098 michael                 13679                 :         /*
                              13680                 :          * For the index of a constraint, if any, remember if it is used for
                              13681                 :          * the table's replica identity or if it is a clustered index, so that
                              13682                 :          * ATPostAlterTypeCleanup() can queue up commands necessary to restore
 1098 michael                 13683 ECB             :          * those properties.
                              13684                 :          */
 1122 peter                   13685 CBC         202 :         indoid = get_constraint_index(conoid);
 1122 peter                   13686 GIC         202 :         if (OidIsValid(indoid))
 1098 michael                 13687 ECB             :         {
 1122 peter                   13688 GIC         102 :             RememberReplicaIdentityForRebuilding(indoid, tab);
 1098 michael                 13689 CBC         102 :             RememberClusterOnForRebuilding(indoid, tab);
                              13690                 :         }
 1385 tgl                     13691 ECB             :     }
 1385 tgl                     13692 CBC         241 : }
                              13693                 : 
 1385 tgl                     13694 ECB             : /*
                              13695                 :  * Subroutine for ATExecAlterColumnType: remember that an index needs
                              13696                 :  * to be rebuilt (which we might already know).
                              13697                 :  */
                              13698                 : static void
 1385 tgl                     13699 GIC         107 : RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
                              13700                 : {
 1385 tgl                     13701 ECB             :     /*
                              13702                 :      * This de-duplication check is critical for two independent reasons: we
                              13703                 :      * mustn't try to recreate the same index twice, and if an index depends
                              13704                 :      * on more than one column whose type is to be altered, we must capture
                              13705                 :      * its definition string before applying any of the column type changes.
                              13706                 :      * ruleutils.c will get confused if we ask again later.
                              13707                 :      */
 1385 tgl                     13708 GIC         107 :     if (!list_member_oid(tab->changedIndexOids, indoid))
                              13709                 :     {
                              13710                 :         /*
 1385 tgl                     13711 ECB             :          * Before adding it as an index-to-rebuild, we'd better see if it
                              13712                 :          * belongs to a constraint, and if so rebuild the constraint instead.
                              13713                 :          * Typically this check fails, because constraint indexes normally
                              13714                 :          * have only dependencies on their constraint.  But it's possible for
                              13715                 :          * such an index to also have direct dependencies on table columns,
                              13716                 :          * for example with a partial exclusion constraint.
                              13717                 :          */
 1385 tgl                     13718 GIC         103 :         Oid         conoid = get_index_constraint(indoid);
                              13719                 : 
                              13720             103 :         if (OidIsValid(conoid))
                              13721                 :         {
                              13722               6 :             RememberConstraintForRebuilding(conoid, tab);
                              13723                 :         }
                              13724                 :         else
                              13725                 :         {
                              13726                 :             /* OK, capture the index's existing definition string */
                              13727              97 :             char       *defstring = pg_get_indexdef_string(indoid);
                              13728                 : 
                              13729              97 :             tab->changedIndexOids = lappend_oid(tab->changedIndexOids,
                              13730                 :                                                 indoid);
                              13731              97 :             tab->changedIndexDefs = lappend(tab->changedIndexDefs,
                              13732                 :                                             defstring);
                              13733                 : 
                              13734                 :             /*
                              13735                 :              * Remember if this index is used for the table's replica identity
                              13736                 :              * or if it is a clustered index, so that ATPostAlterTypeCleanup()
                              13737                 :              * can queue up commands necessary to restore those properties.
 1098 michael                 13738 ECB             :              */
 1122 peter                   13739 GIC          97 :             RememberReplicaIdentityForRebuilding(indoid, tab);
 1098 michael                 13740              97 :             RememberClusterOnForRebuilding(indoid, tab);
                              13741                 :         }
 1385 tgl                     13742 ECB             :     }
 1385 tgl                     13743 CBC         107 : }
 1385 tgl                     13744 ECB             : 
                              13745                 : /*
  744 tomas.vondra            13746                 :  * Subroutine for ATExecAlterColumnType: remember that a statistics object
                              13747                 :  * needs to be rebuilt (which we might already know).
                              13748                 :  */
                              13749                 : static void
  744 tomas.vondra            13750 GIC           7 : RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab)
                              13751                 : {
  744 tomas.vondra            13752 ECB             :     /*
                              13753                 :      * This de-duplication check is critical for two independent reasons: we
  744 tomas.vondra            13754 EUB             :      * mustn't try to recreate the same statistics object twice, and if the
                              13755                 :      * statistics object depends on more than one column whose type is to be
                              13756                 :      * altered, we must capture its definition string before applying any of
                              13757                 :      * the type changes. ruleutils.c will get confused if we ask again later.
  744 tomas.vondra            13758 ECB             :      */
  744 tomas.vondra            13759 CBC           7 :     if (!list_member_oid(tab->changedStatisticsOids, stxoid))
  744 tomas.vondra            13760 ECB             :     {
                              13761                 :         /* OK, capture the statistics object's existing definition string */
  744 tomas.vondra            13762 GIC           7 :         char       *defstring = pg_get_statisticsobjdef_string(stxoid);
  744 tomas.vondra            13763 ECB             : 
  744 tomas.vondra            13764 CBC           7 :         tab->changedStatisticsOids = lappend_oid(tab->changedStatisticsOids,
  744 tomas.vondra            13765 EUB             :                                                  stxoid);
  744 tomas.vondra            13766 GIC           7 :         tab->changedStatisticsDefs = lappend(tab->changedStatisticsDefs,
                              13767                 :                                              defstring);
                              13768                 :     }
                              13769               7 : }
                              13770                 : 
 7576 tgl                     13771 ECB             : /*
 6913                         13772                 :  * Cleanup after we've finished all the ALTER TYPE operations for a
                              13773                 :  * particular relation.  We have to drop and recreate all the indexes
                              13774                 :  * and constraints that depend on the altered columns.  We do the
 1385                         13775                 :  * actual dropping here, but re-creation is managed by adding work
                              13776                 :  * queue entries to do those steps later.
                              13777                 :  */
                              13778                 : static void
 4638 simon                   13779 GIC         430 : ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
                              13780                 : {
                              13781                 :     ObjectAddress obj;
                              13782                 :     ObjectAddresses *objects;
                              13783                 :     ListCell   *def_item;
                              13784                 :     ListCell   *oid_item;
                              13785                 : 
                              13786                 :     /*
                              13787                 :      * Collect all the constraints and indexes to drop so we can process them
                              13788                 :      * in a single call.  That way we don't have to worry about dependencies
 1668 alvherre                13789 ECB             :      * among them.
                              13790                 :      */
 1668 alvherre                13791 CBC         430 :     objects = new_object_addresses();
 1668 alvherre                13792 ECB             : 
 6913 tgl                     13793                 :     /*
 6385 bruce                   13794                 :      * Re-parse the index and constraint definitions, and attach them to the
                              13795                 :      * appropriate work queue entries.  We do this before dropping because in
                              13796                 :      * the case of a FOREIGN KEY constraint, we might not yet have exclusive
                              13797                 :      * lock on the table the constraint is attached to, and we need to get
                              13798                 :      * that before reparsing/dropping.
                              13799                 :      *
 3260                         13800                 :      * We can't rely on the output of deparsing to tell us which relation to
                              13801                 :      * operate on, because concurrent activity might have made the name
 3338 rhaas                   13802                 :      * resolve differently.  Instead, we've got to use the OID of the
 3260 bruce                   13803                 :      * constraint or index we're processing to figure out which relation to
                              13804                 :      * operate on.
                              13805                 :      */
 4283 rhaas                   13806 GIC         632 :     forboth(oid_item, tab->changedConstraintOids,
                              13807                 :             def_item, tab->changedConstraintDefs)
 3338 rhaas                   13808 ECB             :     {
 3260 bruce                   13809 GIC         202 :         Oid         oldId = lfirst_oid(oid_item);
                              13810                 :         HeapTuple   tup;
                              13811                 :         Form_pg_constraint con;
                              13812                 :         Oid         relid;
                              13813                 :         Oid         confrelid;
                              13814                 :         char        contype;
 2697 tgl                     13815 ECB             :         bool        conislocal;
                              13816                 : 
 2697 tgl                     13817 GIC         202 :         tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
 2118                         13818             202 :         if (!HeapTupleIsValid(tup)) /* should not happen */
 2697 tgl                     13819 UIC           0 :             elog(ERROR, "cache lookup failed for constraint %u", oldId);
 2697 tgl                     13820 GIC         202 :         con = (Form_pg_constraint) GETSTRUCT(tup);
 1985                         13821             202 :         if (OidIsValid(con->conrelid))
                              13822             195 :             relid = con->conrelid;
                              13823                 :         else
                              13824                 :         {
                              13825                 :             /* must be a domain constraint */
 1985 tgl                     13826 CBC           7 :             relid = get_typ_typrelid(getBaseType(con->contypid));
 1985 tgl                     13827 GIC           7 :             if (!OidIsValid(relid))
 1985 tgl                     13828 LBC           0 :                 elog(ERROR, "could not identify relation associated with constraint %u", oldId);
                              13829                 :         }
 2697 tgl                     13830 GIC         202 :         confrelid = con->confrelid;
 1651                         13831             202 :         contype = con->contype;
 2697 tgl                     13832 CBC         202 :         conislocal = con->conislocal;
 2697 tgl                     13833 GIC         202 :         ReleaseSysCache(tup);
                              13834                 : 
 1651                         13835             202 :         ObjectAddressSet(obj, ConstraintRelationId, oldId);
 1668 alvherre                13836 CBC         202 :         add_exact_object_address(&obj, objects);
                              13837                 : 
                              13838                 :         /*
                              13839                 :          * If the constraint is inherited (only), we don't want to inject a
                              13840                 :          * new definition here; it'll get recreated when ATAddCheckConstraint
 2697 tgl                     13841 ECB             :          * recurses from adding the parent table's constraint.  But we had to
                              13842                 :          * carry the info this far so that we can drop the constraint below.
                              13843                 :          */
 2697 tgl                     13844 CBC         202 :         if (!conislocal)
 2697 tgl                     13845 GIC           8 :             continue;
 3338 rhaas                   13846 ECB             : 
                              13847                 :         /*
                              13848                 :          * When rebuilding an FK constraint that references the table we're
 1651 tgl                     13849                 :          * modifying, we might not yet have any lock on the FK's table, so get
                              13850                 :          * one now.  We'll need AccessExclusiveLock for the DROP CONSTRAINT
                              13851                 :          * step, so there's no value in asking for anything weaker.
                              13852                 :          */
 1651 tgl                     13853 CBC         194 :         if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
 1651 tgl                     13854 GIC          18 :             LockRelationOid(relid, AccessExclusiveLock);
 1651 tgl                     13855 ECB             : 
 3338 rhaas                   13856 GIC         194 :         ATPostAlterTypeParse(oldId, relid, confrelid,
 3338 rhaas                   13857 CBC         194 :                              (char *) lfirst(def_item),
 4283 rhaas                   13858 GIC         194 :                              wqueue, lockmode, tab->rewrite);
 3338 rhaas                   13859 ECB             :     }
 4283 rhaas                   13860 GIC         527 :     forboth(oid_item, tab->changedIndexOids,
                              13861                 :             def_item, tab->changedIndexDefs)
 3338 rhaas                   13862 ECB             :     {
 3260 bruce                   13863 CBC          97 :         Oid         oldId = lfirst_oid(oid_item);
                              13864                 :         Oid         relid;
 3338 rhaas                   13865 ECB             : 
 3338 rhaas                   13866 GIC          97 :         relid = IndexGetRelation(oldId, false);
                              13867              97 :         ATPostAlterTypeParse(oldId, relid, InvalidOid,
                              13868              97 :                              (char *) lfirst(def_item),
 4283                         13869              97 :                              wqueue, lockmode, tab->rewrite);
                              13870                 : 
 1651 tgl                     13871 CBC          97 :         ObjectAddressSet(obj, RelationRelationId, oldId);
 1668 alvherre                13872 GIC          97 :         add_exact_object_address(&obj, objects);
                              13873                 :     }
                              13874                 : 
                              13875                 :     /* add dependencies for new statistics */
  744 tomas.vondra            13876 GBC         437 :     forboth(oid_item, tab->changedStatisticsOids,
                              13877                 :             def_item, tab->changedStatisticsDefs)
                              13878                 :     {
  744 tomas.vondra            13879 CBC           7 :         Oid         oldId = lfirst_oid(oid_item);
                              13880                 :         Oid         relid;
                              13881                 : 
                              13882               7 :         relid = StatisticsGetRelation(oldId, false);
                              13883               7 :         ATPostAlterTypeParse(oldId, relid, InvalidOid,
                              13884               7 :                              (char *) lfirst(def_item),
                              13885               7 :                              wqueue, lockmode, tab->rewrite);
                              13886                 : 
                              13887               7 :         ObjectAddressSet(obj, StatisticExtRelationId, oldId);
  744 tomas.vondra            13888 GIC           7 :         add_exact_object_address(&obj, objects);
  744 tomas.vondra            13889 ECB             :     }
                              13890                 : 
                              13891                 :     /*
                              13892                 :      * Queue up command to restore replica identity index marking
                              13893                 :      */
 1122 peter                   13894 GIC         430 :     if (tab->replicaIdentityIndex)
                              13895                 :     {
                              13896               9 :         AlterTableCmd *cmd = makeNode(AlterTableCmd);
 1122 peter                   13897 GBC           9 :         ReplicaIdentityStmt *subcmd = makeNode(ReplicaIdentityStmt);
                              13898                 : 
 1122 peter                   13899 GIC           9 :         subcmd->identity_type = REPLICA_IDENTITY_INDEX;
                              13900               9 :         subcmd->name = tab->replicaIdentityIndex;
                              13901               9 :         cmd->subtype = AT_ReplicaIdentity;
                              13902               9 :         cmd->def = (Node *) subcmd;
                              13903                 : 
                              13904                 :         /* do it after indexes and constraints */
                              13905               9 :         tab->subcmds[AT_PASS_OLD_CONSTR] =
                              13906               9 :             lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
                              13907                 :     }
 1122 peter                   13908 EUB             : 
                              13909                 :     /*
                              13910                 :      * Queue up command to restore marking of index used for cluster.
                              13911                 :      */
 1098 michael                 13912 GIC         430 :     if (tab->clusterOnIndex)
                              13913                 :     {
                              13914               9 :         AlterTableCmd *cmd = makeNode(AlterTableCmd);
                              13915                 : 
 1098 michael                 13916 GBC           9 :         cmd->subtype = AT_ClusterOn;
 1098 michael                 13917 GIC           9 :         cmd->name = tab->clusterOnIndex;
                              13918                 : 
                              13919                 :         /* do it after indexes and constraints */
                              13920               9 :         tab->subcmds[AT_PASS_OLD_CONSTR] =
                              13921               9 :             lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
                              13922                 :     }
                              13923                 : 
                              13924                 :     /*
                              13925                 :      * It should be okay to use DROP_RESTRICT here, since nothing else should
 1668 alvherre                13926 EUB             :      * be depending on these objects.
                              13927                 :      */
 1668 alvherre                13928 GIC         430 :     performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
                              13929                 : 
                              13930             430 :     free_object_addresses(objects);
                              13931                 : 
                              13932                 :     /*
                              13933                 :      * The objects will get recreated during subsequent passes over the work
 6385 bruce                   13934 ECB             :      * queue.
                              13935                 :      */
 6913 tgl                     13936 CBC         430 : }
                              13937                 : 
 1385 tgl                     13938 ECB             : /*
  744 tomas.vondra            13939                 :  * Parse the previously-saved definition string for a constraint, index or
                              13940                 :  * statistics object against the newly-established column data type(s), and
                              13941                 :  * queue up the resulting command parsetrees for execution.
                              13942                 :  *
                              13943                 :  * This might fail if, for example, you have a WHERE clause that uses an
                              13944                 :  * operator that's not available for the new column type.
 1385 tgl                     13945                 :  */
                              13946                 : static void
 3338 rhaas                   13947 GIC         298 : ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
                              13948                 :                      List **wqueue, LOCKMODE lockmode, bool rewrite)
                              13949                 : {
                              13950                 :     List       *raw_parsetree_list;
                              13951                 :     List       *querytree_list;
                              13952                 :     ListCell   *list_item;
                              13953                 :     Relation    rel;
                              13954                 : 
                              13955                 :     /*
                              13956                 :      * We expect that we will get only ALTER TABLE and CREATE INDEX
 5624 bruce                   13957 ECB             :      * statements. Hence, there is no need to pass them through
                              13958                 :      * parse_analyze_*() or the rewriter, but instead we need to pass them
                              13959                 :      * through parse_utilcmd.c to make them ready for execution.
                              13960                 :      */
  825 tgl                     13961 GIC         298 :     raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT);
 6913                         13962             298 :     querytree_list = NIL;
                              13963             596 :     foreach(list_item, raw_parsetree_list)
                              13964                 :     {
 2190                         13965             298 :         RawStmt    *rs = lfirst_node(RawStmt, list_item);
 2276 tgl                     13966 CBC         298 :         Node       *stmt = rs->stmt;
                              13967                 : 
 5769 tgl                     13968 GIC         298 :         if (IsA(stmt, IndexStmt))
 5769 tgl                     13969 CBC          97 :             querytree_list = lappend(querytree_list,
 3338 rhaas                   13970 GIC          97 :                                      transformIndexStmt(oldRelId,
                              13971                 :                                                         (IndexStmt *) stmt,
                              13972                 :                                                         cmd));
 5769 tgl                     13973             201 :         else if (IsA(stmt, AlterTableStmt))
                              13974                 :         {
 1180 tgl                     13975 ECB             :             List       *beforeStmts;
                              13976                 :             List       *afterStmts;
                              13977                 : 
 1180 tgl                     13978 GBC         187 :             stmt = (Node *) transformAlterTableStmt(oldRelId,
                              13979                 :                                                     (AlterTableStmt *) stmt,
                              13980                 :                                                     cmd,
                              13981                 :                                                     &beforeStmts,
                              13982                 :                                                     &afterStmts);
 1180 tgl                     13983 GIC         187 :             querytree_list = list_concat(querytree_list, beforeStmts);
                              13984             187 :             querytree_list = lappend(querytree_list, stmt);
                              13985             187 :             querytree_list = list_concat(querytree_list, afterStmts);
                              13986                 :         }
  744 tomas.vondra            13987              14 :         else if (IsA(stmt, CreateStatsStmt))
                              13988               7 :             querytree_list = lappend(querytree_list,
                              13989               7 :                                      transformStatsStmt(oldRelId,
                              13990                 :                                                         (CreateStatsStmt *) stmt,
                              13991                 :                                                         cmd));
                              13992                 :         else
 5769 tgl                     13993               7 :             querytree_list = lappend(querytree_list, stmt);
                              13994                 :     }
                              13995                 : 
                              13996                 :     /* Caller should already have acquired whatever lock we need. */
 3338 rhaas                   13997             298 :     rel = relation_open(oldRelId, NoLock);
                              13998                 : 
                              13999                 :     /*
                              14000                 :      * Attach each generated command to the proper place in the work queue.
                              14001                 :      * Note this could result in creation of entirely new work-queue entries.
                              14002                 :      *
                              14003                 :      * Also note that we have to tweak the command subtypes, because it turns
                              14004                 :      * out that re-creation of indexes and constraints has to act a bit
                              14005                 :      * differently from initial creation.
                              14006                 :      */
 6913 tgl                     14007             596 :     foreach(list_item, querytree_list)
                              14008                 :     {
 5769                         14009             298 :         Node       *stm = (Node *) lfirst(list_item);
                              14010                 :         AlteredTableInfo *tab;
                              14011                 : 
 2826 heikki.linnakangas      14012             298 :         tab = ATGetQueueEntry(wqueue, rel);
                              14013                 : 
                              14014             298 :         if (IsA(stm, IndexStmt))
                              14015                 :         {
                              14016              97 :             IndexStmt  *stmt = (IndexStmt *) stm;
 2826 heikki.linnakangas      14017 EUB             :             AlterTableCmd *newcmd;
                              14018                 : 
 2826 heikki.linnakangas      14019 GIC          97 :             if (!rewrite)
                              14020              27 :                 TryReuseIndex(oldId, stmt);
 1445 alvherre                14021              97 :             stmt->reset_default_tblspc = true;
                              14022                 :             /* keep the index's comment */
 2826 heikki.linnakangas      14023              97 :             stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
                              14024                 : 
                              14025              97 :             newcmd = makeNode(AlterTableCmd);
                              14026              97 :             newcmd->subtype = AT_ReAddIndex;
                              14027              97 :             newcmd->def = (Node *) stmt;
 2826 heikki.linnakangas      14028 CBC          97 :             tab->subcmds[AT_PASS_OLD_INDEX] =
 2826 heikki.linnakangas      14029 GIC          97 :                 lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
                              14030                 :         }
                              14031             201 :         else if (IsA(stm, AlterTableStmt))
                              14032                 :         {
                              14033             187 :             AlterTableStmt *stmt = (AlterTableStmt *) stm;
                              14034                 :             ListCell   *lcmd;
 2826 heikki.linnakangas      14035 ECB             : 
 2826 heikki.linnakangas      14036 GIC         434 :             foreach(lcmd, stmt->cmds)
                              14037                 :             {
  629 peter                   14038             247 :                 AlterTableCmd *cmd = lfirst_node(AlterTableCmd, lcmd);
 2826 heikki.linnakangas      14039 ECB             : 
 2826 heikki.linnakangas      14040 GIC         247 :                 if (cmd->subtype == AT_AddIndex)
                              14041                 :                 {
                              14042                 :                     IndexStmt  *indstmt;
 2826 heikki.linnakangas      14043 ECB             :                     Oid         indoid;
                              14044                 : 
 2264 andres                  14045 GIC         102 :                     indstmt = castNode(IndexStmt, cmd->def);
 2826 heikki.linnakangas      14046             102 :                     indoid = get_constraint_index(oldId);
                              14047                 : 
 4283 rhaas                   14048 CBC         102 :                     if (!rewrite)
 2826 heikki.linnakangas      14049 GIC          24 :                         TryReuseIndex(indoid, indstmt);
                              14050                 :                     /* keep any comment on the index */
 2826 heikki.linnakangas      14051 CBC         102 :                     indstmt->idxcomment = GetComment(indoid,
                              14052                 :                                                      RelationRelationId, 0);
 1445 alvherre                14053             102 :                     indstmt->reset_default_tblspc = true;
                              14054                 : 
 2826 heikki.linnakangas      14055 GIC         102 :                     cmd->subtype = AT_ReAddIndex;
 6797 bruce                   14056 CBC         102 :                     tab->subcmds[AT_PASS_OLD_INDEX] =
 2826 heikki.linnakangas      14057             102 :                         lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
 2826 heikki.linnakangas      14058 ECB             : 
                              14059                 :                     /* recreate any comment on the constraint */
 2826 heikki.linnakangas      14060 CBC         102 :                     RebuildConstraintComment(tab,
 2826 heikki.linnakangas      14061 EUB             :                                              AT_PASS_OLD_INDEX,
                              14062                 :                                              oldId,
 1985 tgl                     14063 ECB             :                                              rel,
                              14064                 :                                              NIL,
 1985 tgl                     14065 GBC         102 :                                              indstmt->idxname);
 6797 bruce                   14066 EUB             :                 }
 2826 heikki.linnakangas      14067 GBC         145 :                 else if (cmd->subtype == AT_AddConstraint)
                              14068                 :                 {
 1985 tgl                     14069 GIC          85 :                     Constraint *con = castNode(Constraint, cmd->def);
 2826 heikki.linnakangas      14070 ECB             : 
 2826 heikki.linnakangas      14071 GIC          85 :                     con->old_pktable_oid = refRelId;
                              14072                 :                     /* rewriting neither side of a FK */
 2826 heikki.linnakangas      14073 CBC          85 :                     if (con->contype == CONSTR_FOREIGN &&
 2826 heikki.linnakangas      14074 GIC          30 :                         !rewrite && tab->rewrite == 0)
 2826 heikki.linnakangas      14075 CBC           3 :                         TryReuseForeignKey(oldId, con);
 1445 alvherre                14076 GIC          85 :                     con->reset_default_tblspc = true;
 2826 heikki.linnakangas      14077              85 :                     cmd->subtype = AT_ReAddConstraint;
                              14078              85 :                     tab->subcmds[AT_PASS_OLD_CONSTR] =
                              14079              85 :                         lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
                              14080                 : 
                              14081                 :                     /* recreate any comment on the constraint */
 2826 heikki.linnakangas      14082 CBC          85 :                     RebuildConstraintComment(tab,
                              14083                 :                                              AT_PASS_OLD_CONSTR,
                              14084                 :                                              oldId,
                              14085                 :                                              rel,
                              14086                 :                                              NIL,
 1985 tgl                     14087 GIC          85 :                                              con->conname);
 6913 tgl                     14088 ECB             :                 }
    2 alvherre                14089 GNC          60 :                 else if (cmd->subtype == AT_SetAttNotNull)
                              14090                 :                 {
 1447 tgl                     14091 ECB             :                     /*
                              14092                 :                      * The parser will create AT_AttSetNotNull subcommands for
                              14093                 :                      * columns of PRIMARY KEY indexes/constraints, but we need
                              14094                 :                      * not do anything with them here, because the columns'
                              14095                 :                      * NOT NULL marks will already have been propagated into
                              14096                 :                      * the new table definition.
                              14097                 :                      */
                              14098                 :                 }
                              14099                 :                 else
 2697 tgl                     14100 UIC           0 :                     elog(ERROR, "unexpected statement subtype: %d",
                              14101                 :                          (int) cmd->subtype);
                              14102                 :             }
                              14103                 :         }
 1985 tgl                     14104 GIC          14 :         else if (IsA(stm, AlterDomainStmt))
                              14105                 :         {
                              14106               7 :             AlterDomainStmt *stmt = (AlterDomainStmt *) stm;
 1985 tgl                     14107 ECB             : 
 1985 tgl                     14108 GIC           7 :             if (stmt->subtype == 'C')    /* ADD CONSTRAINT */
 1985 tgl                     14109 ECB             :             {
 1985 tgl                     14110 CBC           7 :                 Constraint *con = castNode(Constraint, stmt->def);
                              14111               7 :                 AlterTableCmd *cmd = makeNode(AlterTableCmd);
                              14112                 : 
 1985 tgl                     14113 GIC           7 :                 cmd->subtype = AT_ReAddDomainConstraint;
 1985 tgl                     14114 CBC           7 :                 cmd->def = (Node *) stmt;
 1985 tgl                     14115 GIC           7 :                 tab->subcmds[AT_PASS_OLD_CONSTR] =
                              14116               7 :                     lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
                              14117                 : 
 1985 tgl                     14118 ECB             :                 /* recreate any comment on the constraint */
 1985 tgl                     14119 CBC           7 :                 RebuildConstraintComment(tab,
 1985 tgl                     14120 ECB             :                                          AT_PASS_OLD_CONSTR,
                              14121                 :                                          oldId,
                              14122                 :                                          NULL,
                              14123                 :                                          stmt->typeName,
 1985 tgl                     14124 GIC           7 :                                          con->conname);
 1985 tgl                     14125 ECB             :             }
                              14126                 :             else
 1985 tgl                     14127 LBC           0 :                 elog(ERROR, "unexpected statement subtype: %d",
                              14128                 :                      (int) stmt->subtype);
 1985 tgl                     14129 ECB             :         }
  744 tomas.vondra            14130 CBC           7 :         else if (IsA(stm, CreateStatsStmt))
  744 tomas.vondra            14131 ECB             :         {
  697 tgl                     14132 GIC           7 :             CreateStatsStmt *stmt = (CreateStatsStmt *) stm;
  744 tomas.vondra            14133 ECB             :             AlterTableCmd *newcmd;
                              14134                 : 
                              14135                 :             /* keep the statistics object's comment */
  744 tomas.vondra            14136 CBC           7 :             stmt->stxcomment = GetComment(oldId, StatisticExtRelationId, 0);
  744 tomas.vondra            14137 ECB             : 
  744 tomas.vondra            14138 GIC           7 :             newcmd = makeNode(AlterTableCmd);
                              14139               7 :             newcmd->subtype = AT_ReAddStatistics;
                              14140               7 :             newcmd->def = (Node *) stmt;
  744 tomas.vondra            14141 CBC           7 :             tab->subcmds[AT_PASS_MISC] =
                              14142               7 :                 lappend(tab->subcmds[AT_PASS_MISC], newcmd);
  744 tomas.vondra            14143 ECB             :         }
 2826 heikki.linnakangas      14144                 :         else
 2826 heikki.linnakangas      14145 UBC           0 :             elog(ERROR, "unexpected statement type: %d",
                              14146                 :                  (int) nodeTag(stm));
                              14147                 :     }
 3338 rhaas                   14148 ECB             : 
 3338 rhaas                   14149 CBC         298 :     relation_close(rel, NoLock);
 7653 tgl                     14150             298 : }
 7653 tgl                     14151 ECB             : 
 2826 heikki.linnakangas      14152                 : /*
 1985 tgl                     14153                 :  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
                              14154                 :  * for a table or domain constraint that is being rebuilt.
                              14155                 :  *
                              14156                 :  * objid is the OID of the constraint.
                              14157                 :  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
                              14158                 :  * as a string list) for a domain constraint.
                              14159                 :  * (We could dig that info, as well as the conname, out of the pg_constraint
                              14160                 :  * entry; but callers already have them so might as well pass them.)
                              14161                 :  */
 2826 heikki.linnakangas      14162                 : static void
 2826 heikki.linnakangas      14163 CBC         194 : RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
                              14164                 :                          Relation rel, List *domname,
                              14165                 :                          const char *conname)
                              14166                 : {
                              14167                 :     CommentStmt *cmd;
 2826 heikki.linnakangas      14168 ECB             :     char       *comment_str;
                              14169                 :     AlterTableCmd *newcmd;
                              14170                 : 
                              14171                 :     /* Look for comment for object wanted, and leave if none */
 2826 heikki.linnakangas      14172 GIC         194 :     comment_str = GetComment(objid, ConstraintRelationId, 0);
                              14173             194 :     if (comment_str == NULL)
                              14174             161 :         return;
                              14175                 : 
                              14176                 :     /* Build CommentStmt node, copying all input data for safety */
                              14177              33 :     cmd = makeNode(CommentStmt);
 1985 tgl                     14178              33 :     if (rel)
                              14179                 :     {
 1985 tgl                     14180 CBC          27 :         cmd->objtype = OBJECT_TABCONSTRAINT;
 1985 tgl                     14181 GIC          27 :         cmd->object = (Node *)
                              14182              27 :             list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
                              14183                 :                        makeString(pstrdup(RelationGetRelationName(rel))),
                              14184                 :                        makeString(pstrdup(conname)));
                              14185                 :     }
                              14186                 :     else
 1985 tgl                     14187 ECB             :     {
 1985 tgl                     14188 GIC           6 :         cmd->objtype = OBJECT_DOMCONSTRAINT;
 1985 tgl                     14189 CBC           6 :         cmd->object = (Node *)
 1985 tgl                     14190 GIC           6 :             list_make2(makeTypeNameFromNameList(copyObject(domname)),
 1985 tgl                     14191 ECB             :                        makeString(pstrdup(conname)));
 1985 tgl                     14192 EUB             :     }
 2826 heikki.linnakangas      14193 GIC          33 :     cmd->comment = comment_str;
 2826 heikki.linnakangas      14194 ECB             : 
                              14195                 :     /* Append it to list of commands */
 2826 heikki.linnakangas      14196 GIC          33 :     newcmd = makeNode(AlterTableCmd);
                              14197              33 :     newcmd->subtype = AT_ReAddComment;
                              14198              33 :     newcmd->def = (Node *) cmd;
                              14199              33 :     tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
                              14200                 : }
 2826 heikki.linnakangas      14201 ECB             : 
                              14202                 : /*
                              14203                 :  * Subroutine for ATPostAlterTypeParse().  Calls out to CheckIndexCompatible()
                              14204                 :  * for the real analysis, then mutates the IndexStmt based on that verdict.
                              14205                 :  */
                              14206                 : static void
 4283 rhaas                   14207 CBC          51 : TryReuseIndex(Oid oldId, IndexStmt *stmt)
                              14208                 : {
 4283 rhaas                   14209 GIC          51 :     if (CheckIndexCompatible(oldId,
 4283 rhaas                   14210 CBC          51 :                              stmt->accessMethod,
                              14211                 :                              stmt->indexParams,
                              14212                 :                              stmt->excludeOpNames))
 4283 rhaas                   14213 ECB             :     {
 3955 bruce                   14214 GIC          51 :         Relation    irel = index_open(oldId, NoLock);
                              14215                 : 
                              14216                 :         /* If it's a partitioned index, there is no storage to share. */
 1444 tgl                     14217 CBC          51 :         if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
                              14218                 :         {
  277 rhaas                   14219 GNC          36 :             stmt->oldNumber = irel->rd_locator.relNumber;
 1100 noah                    14220 GIC          36 :             stmt->oldCreateSubid = irel->rd_createSubid;
  277 rhaas                   14221 GNC          36 :             stmt->oldFirstRelfilelocatorSubid = irel->rd_firstRelfilelocatorSubid;
                              14222                 :         }
 4283 rhaas                   14223 GIC          51 :         index_close(irel, NoLock);
                              14224                 :     }
                              14225              51 : }
                              14226                 : 
 4059 alvherre                14227 ECB             : /*
                              14228                 :  * Subroutine for ATPostAlterTypeParse().
                              14229                 :  *
                              14230                 :  * Stash the old P-F equality operator into the Constraint node, for possible
                              14231                 :  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
                              14232                 :  * this constraint can be skipped.
 4059 alvherre                14233 EUB             :  */
                              14234                 : static void
 4059 alvherre                14235 CBC           3 : TryReuseForeignKey(Oid oldId, Constraint *con)
                              14236                 : {
                              14237                 :     HeapTuple   tup;
                              14238                 :     Datum       adatum;
                              14239                 :     ArrayType  *arr;
                              14240                 :     Oid        *rawarr;
 4059 alvherre                14241 ECB             :     int         numkeys;
                              14242                 :     int         i;
                              14243                 : 
 4059 alvherre                14244 CBC           3 :     Assert(con->contype == CONSTR_FOREIGN);
 3955 bruce                   14245 GIC           3 :     Assert(con->old_conpfeqop == NIL);   /* already prepared this node */
 4059 alvherre                14246 ECB             : 
 4059 alvherre                14247 GBC           3 :     tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
 4059 alvherre                14248 GIC           3 :     if (!HeapTupleIsValid(tup)) /* should not happen */
 4059 alvherre                14249 LBC           0 :         elog(ERROR, "cache lookup failed for constraint %u", oldId);
                              14250                 : 
   15 dgustafsson             14251 GNC           3 :     adatum = SysCacheGetAttrNotNull(CONSTROID, tup,
                              14252                 :                                     Anum_pg_constraint_conpfeqop);
 4059 alvherre                14253 GIC           3 :     arr = DatumGetArrayTypeP(adatum);   /* ensure not toasted */
                              14254               3 :     numkeys = ARR_DIMS(arr)[0];
 4059 alvherre                14255 ECB             :     /* test follows the one in ri_FetchConstraintInfo() */
 4059 alvherre                14256 GIC           3 :     if (ARR_NDIM(arr) != 1 ||
                              14257               3 :         ARR_HASNULL(arr) ||
                              14258               3 :         ARR_ELEMTYPE(arr) != OIDOID)
 4059 alvherre                14259 UIC           0 :         elog(ERROR, "conpfeqop is not a 1-D Oid array");
 4059 alvherre                14260 GIC           3 :     rawarr = (Oid *) ARR_DATA_PTR(arr);
                              14261                 : 
                              14262                 :     /* stash a List of the operator Oids in our Constraint node */
                              14263               6 :     for (i = 0; i < numkeys; i++)
 1363 tgl                     14264 CBC           3 :         con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
                              14265                 : 
 4059 alvherre                14266 GIC           3 :     ReleaseSysCache(tup);
 4059 alvherre                14267 CBC           3 : }
                              14268                 : 
                              14269                 : /*
 1385 tgl                     14270 ECB             :  * ALTER COLUMN .. OPTIONS ( ... )
                              14271                 :  *
                              14272                 :  * Returns the address of the modified column
                              14273                 :  */
                              14274                 : static ObjectAddress
 1385 tgl                     14275 GIC          82 : ATExecAlterColumnGenericOptions(Relation rel,
                              14276                 :                                 const char *colName,
                              14277                 :                                 List *options,
                              14278                 :                                 LOCKMODE lockmode)
                              14279                 : {
                              14280                 :     Relation    ftrel;
 1385 tgl                     14281 ECB             :     Relation    attrel;
                              14282                 :     ForeignServer *server;
                              14283                 :     ForeignDataWrapper *fdw;
                              14284                 :     HeapTuple   tuple;
                              14285                 :     HeapTuple   newtuple;
                              14286                 :     bool        isnull;
                              14287                 :     Datum       repl_val[Natts_pg_attribute];
                              14288                 :     bool        repl_null[Natts_pg_attribute];
                              14289                 :     bool        repl_repl[Natts_pg_attribute];
                              14290                 :     Datum       datum;
                              14291                 :     Form_pg_foreign_table fttableform;
                              14292                 :     Form_pg_attribute atttableform;
                              14293                 :     AttrNumber  attnum;
                              14294                 :     ObjectAddress address;
                              14295                 : 
 1385 tgl                     14296 GIC          82 :     if (options == NIL)
 1385 tgl                     14297 UIC           0 :         return InvalidObjectAddress;
                              14298                 : 
                              14299                 :     /* First, determine FDW validator associated to the foreign table. */
 1385 tgl                     14300 GIC          82 :     ftrel = table_open(ForeignTableRelationId, AccessShareLock);
                              14301              82 :     tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
                              14302              82 :     if (!HeapTupleIsValid(tuple))
 1385 tgl                     14303 UIC           0 :         ereport(ERROR,
 1385 tgl                     14304 ECB             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              14305                 :                  errmsg("foreign table \"%s\" does not exist",
                              14306                 :                         RelationGetRelationName(rel))));
 1385 tgl                     14307 GIC          82 :     fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
                              14308              82 :     server = GetForeignServer(fttableform->ftserver);
                              14309              82 :     fdw = GetForeignDataWrapper(server->fdwid);
                              14310                 : 
                              14311              82 :     table_close(ftrel, AccessShareLock);
                              14312              82 :     ReleaseSysCache(tuple);
                              14313                 : 
 1385 tgl                     14314 CBC          82 :     attrel = table_open(AttributeRelationId, RowExclusiveLock);
 1385 tgl                     14315 GIC          82 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
 1385 tgl                     14316 CBC          82 :     if (!HeapTupleIsValid(tuple))
 1385 tgl                     14317 UIC           0 :         ereport(ERROR,
 1385 tgl                     14318 ECB             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                              14319                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                              14320                 :                         colName, RelationGetRelationName(rel))));
                              14321                 : 
                              14322                 :     /* Prevent them from altering a system attribute */
 1385 tgl                     14323 CBC          82 :     atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
 1385 tgl                     14324 GIC          82 :     attnum = atttableform->attnum;
 1385 tgl                     14325 CBC          82 :     if (attnum <= 0)
 1385 tgl                     14326 GIC           3 :         ereport(ERROR,
 1385 tgl                     14327 ECB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              14328                 :                  errmsg("cannot alter system column \"%s\"", colName)));
                              14329                 : 
                              14330                 : 
                              14331                 :     /* Initialize buffers for new tuple values */
 1385 tgl                     14332 GIC          79 :     memset(repl_val, 0, sizeof(repl_val));
                              14333              79 :     memset(repl_null, false, sizeof(repl_null));
                              14334              79 :     memset(repl_repl, false, sizeof(repl_repl));
 1385 tgl                     14335 ECB             : 
                              14336                 :     /* Extract the current options */
 1385 tgl                     14337 GIC          79 :     datum = SysCacheGetAttr(ATTNAME,
                              14338                 :                             tuple,
 1385 tgl                     14339 ECB             :                             Anum_pg_attribute_attfdwoptions,
                              14340                 :                             &isnull);
 1385 tgl                     14341 GIC          79 :     if (isnull)
                              14342              74 :         datum = PointerGetDatum(NULL);
                              14343                 : 
                              14344                 :     /* Transform the options */
                              14345              79 :     datum = transformGenericOptions(AttributeRelationId,
 1385 tgl                     14346 ECB             :                                     datum,
                              14347                 :                                     options,
                              14348                 :                                     fdw->fdwvalidator);
                              14349                 : 
 1385 tgl                     14350 GIC          79 :     if (PointerIsValid(DatumGetPointer(datum)))
                              14351              79 :         repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
                              14352                 :     else
 1385 tgl                     14353 UIC           0 :         repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
                              14354                 : 
 1385 tgl                     14355 CBC          79 :     repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
                              14356                 : 
                              14357                 :     /* Everything looks good - update the tuple */
 1385 tgl                     14358 ECB             : 
 1385 tgl                     14359 GIC          79 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
 1385 tgl                     14360 ECB             :                                  repl_val, repl_null, repl_repl);
                              14361                 : 
 1385 tgl                     14362 CBC          79 :     CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
                              14363                 : 
 1385 tgl                     14364 GIC          79 :     InvokeObjectPostAlterHook(RelationRelationId,
 1385 tgl                     14365 ECB             :                               RelationGetRelid(rel),
                              14366                 :                               atttableform->attnum);
 1385 tgl                     14367 GIC          79 :     ObjectAddressSubSet(address, RelationRelationId,
                              14368                 :                         RelationGetRelid(rel), attnum);
                              14369                 : 
                              14370              79 :     ReleaseSysCache(tuple);
                              14371                 : 
                              14372              79 :     table_close(attrel, RowExclusiveLock);
                              14373                 : 
                              14374              79 :     heap_freetuple(newtuple);
 1385 tgl                     14375 ECB             : 
 1385 tgl                     14376 GIC          79 :     return address;
                              14377                 : }
                              14378                 : 
                              14379                 : /*
                              14380                 :  * ALTER TABLE OWNER
                              14381                 :  *
                              14382                 :  * recursing is true if we are recursing from a table to its indexes,
                              14383                 :  * sequences, or toast table.  We don't allow the ownership of those things to
                              14384                 :  * be changed separately from the parent table.  Also, we can skip permission
                              14385                 :  * checks (this is necessary not just an optimization, else we'd fail to
                              14386                 :  * handle toast tables properly).
 5812 tgl                     14387 ECB             :  *
                              14388                 :  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
                              14389                 :  * free-standing composite type.
                              14390                 :  */
                              14391                 : void
 4638 simon                   14392 GIC         940 : ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
                              14393                 : {
                              14394                 :     Relation    target_rel;
                              14395                 :     Relation    class_rel;
                              14396                 :     HeapTuple   tuple;
                              14397                 :     Form_pg_class tuple_class;
                              14398                 : 
                              14399                 :     /*
                              14400                 :      * Get exclusive lock till end of transaction on the target table. Use
                              14401                 :      * relation_open so that we can work on indexes and sequences.
 6772 tgl                     14402 ECB             :      */
 4638 simon                   14403 GIC         940 :     target_rel = relation_open(relationOid, lockmode);
                              14404                 : 
 7653 tgl                     14405 ECB             :     /* Get its pg_class tuple, too */
 1539 andres                  14406 GIC         940 :     class_rel = table_open(RelationRelationId, RowExclusiveLock);
                              14407                 : 
 4802 rhaas                   14408             940 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
 7653 tgl                     14409             940 :     if (!HeapTupleIsValid(tuple))
 7203 tgl                     14410 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relationOid);
 7653 tgl                     14411 GIC         940 :     tuple_class = (Form_pg_class) GETSTRUCT(tuple);
                              14412                 : 
 7653 tgl                     14413 ECB             :     /* Can we change the ownership of this tuple? */
 7203 tgl                     14414 CBC         940 :     switch (tuple_class->relkind)
 7203 tgl                     14415 EUB             :     {
 7203 tgl                     14416 CBC         826 :         case RELKIND_RELATION:
 7203 tgl                     14417 ECB             :         case RELKIND_VIEW:
 3689 kgrittn                 14418                 :         case RELKIND_MATVIEW:
                              14419                 :         case RELKIND_FOREIGN_TABLE:
                              14420                 :         case RELKIND_PARTITIONED_TABLE:
                              14421                 :             /* ok to change owner */
 7203 tgl                     14422 CBC         826 :             break;
 6457                         14423              42 :         case RELKIND_INDEX:
 6439 tgl                     14424 GBC          42 :             if (!recursing)
                              14425                 :             {
 6439 tgl                     14426 ECB             :                 /*
                              14427                 :                  * Because ALTER INDEX OWNER used to be allowed, and in fact
                              14428                 :                  * is generated by old versions of pg_dump, we give a warning
                              14429                 :                  * and do nothing rather than erroring out.  Also, to avoid
                              14430                 :                  * unnecessary chatter while restoring those old dumps, say
                              14431                 :                  * nothing at all if the command would be a no-op anyway.
                              14432                 :                  */
 6439 tgl                     14433 UIC           0 :                 if (tuple_class->relowner != newOwnerId)
                              14434               0 :                     ereport(WARNING,
                              14435                 :                             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              14436                 :                              errmsg("cannot change owner of index \"%s\"",
                              14437                 :                                     NameStr(tuple_class->relname)),
                              14438                 :                              errhint("Change the ownership of the index's table, instead.")));
                              14439                 :                 /* quick hack to exit via the no-op path */
 6439 tgl                     14440 LBC           0 :                 newOwnerId = tuple_class->relowner;
 6439 tgl                     14441 ECB             :             }
 6439 tgl                     14442 GIC          42 :             break;
 1906 alvherre                14443              10 :         case RELKIND_PARTITIONED_INDEX:
                              14444              10 :             if (recursing)
                              14445              10 :                 break;
 1906 alvherre                14446 UIC           0 :             ereport(ERROR,
                              14447                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              14448                 :                      errmsg("cannot change owner of index \"%s\"",
 1906 alvherre                14449 ECB             :                             NameStr(tuple_class->relname)),
                              14450                 :                      errhint("Change the ownership of the index's table, instead.")));
                              14451                 :             break;
 6075 tgl                     14452 CBC          41 :         case RELKIND_SEQUENCE:
                              14453              41 :             if (!recursing &&
                              14454              26 :                 tuple_class->relowner != newOwnerId)
                              14455                 :             {
 6075 tgl                     14456 ECB             :                 /* if it's an owned sequence, disallow changing it by itself */
                              14457                 :                 Oid         tableId;
                              14458                 :                 int32       colId;
                              14459                 : 
 2194 peter_e                 14460 UIC           0 :                 if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
                              14461               0 :                     sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
 6075 tgl                     14462 LBC           0 :                     ereport(ERROR,
 6075 tgl                     14463 ECB             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              14464                 :                              errmsg("cannot change owner of sequence \"%s\"",
                              14465                 :                                     NameStr(tuple_class->relname)),
                              14466                 :                              errdetail("Sequence \"%s\" is linked to table \"%s\".",
 2118                         14467                 :                                        NameStr(tuple_class->relname),
                              14468                 :                                        get_rel_name(tableId))));
                              14469                 :             }
 6075 tgl                     14470 GIC          41 :             break;
 5812                         14471               3 :         case RELKIND_COMPOSITE_TYPE:
 5671 tgl                     14472 CBC           3 :             if (recursing)
 5671 tgl                     14473 GIC           3 :                 break;
 5671 tgl                     14474 UIC           0 :             ereport(ERROR,
 5671 tgl                     14475 ECB             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              14476                 :                      errmsg("\"%s\" is a composite type",
                              14477                 :                             NameStr(tuple_class->relname)),
                              14478                 :                      errhint("Use ALTER TYPE instead.")));
                              14479                 :             break;
 5671 tgl                     14480 CBC          18 :         case RELKIND_TOASTVALUE:
 6457                         14481              18 :             if (recursing)
 6457 tgl                     14482 GIC          18 :                 break;
 1061 alvherre                14483 ECB             :             /* FALL THRU */
 7203 tgl                     14484                 :         default:
 7203 tgl                     14485 UIC           0 :             ereport(ERROR,
                              14486                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              14487                 :                      errmsg("cannot change owner of relation \"%s\"",
                              14488                 :                             NameStr(tuple_class->relname)),
                              14489                 :                      errdetail_relkind_not_supported(tuple_class->relkind)));
 7203 tgl                     14490 ECB             :     }
                              14491                 : 
 6797 bruce                   14492                 :     /*
 6862 tgl                     14493                 :      * If the new owner is the same as the existing owner, consider the
                              14494                 :      * command to have succeeded.  This is for dump restoration purposes.
 7655 bruce                   14495                 :      */
 6494 tgl                     14496 CBC         940 :     if (tuple_class->relowner != newOwnerId)
 6862 tgl                     14497 ECB             :     {
 6825                         14498                 :         Datum       repl_val[Natts_pg_class];
                              14499                 :         bool        repl_null[Natts_pg_class];
                              14500                 :         bool        repl_repl[Natts_pg_class];
 6797 bruce                   14501                 :         Acl        *newAcl;
 6825 tgl                     14502                 :         Datum       aclDatum;
                              14503                 :         bool        isNull;
                              14504                 :         HeapTuple   newtuple;
                              14505                 : 
                              14506                 :         /* skip permission checks when recursing to index or toast table */
 6457 tgl                     14507 GIC         224 :         if (!recursing)
 6457 tgl                     14508 ECB             :         {
                              14509                 :             /* Superusers can always do it */
 6439 tgl                     14510 CBC         136 :             if (!superuser())
                              14511                 :             {
 6385 bruce                   14512              21 :                 Oid         namespaceOid = tuple_class->relnamespace;
 6439 tgl                     14513 ECB             :                 AclResult   aclresult;
                              14514                 : 
                              14515                 :                 /* Otherwise, must be owner of the existing object */
  147 peter                   14516 GNC          21 :                 if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
 1954 peter_e                 14517 LBC           0 :                     aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relationOid)),
 6439 tgl                     14518 UIC           0 :                                    RelationGetRelationName(target_rel));
                              14519                 : 
                              14520                 :                 /* Must be able to become new owner */
  142 rhaas                   14521 GNC          21 :                 check_can_set_role(GetUserId(), newOwnerId);
                              14522                 : 
                              14523                 :                 /* New owner must have CREATE privilege on namespace */
  147 peter                   14524              15 :                 aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
                              14525                 :                                                   ACL_CREATE);
 6439 tgl                     14526 CBC          15 :                 if (aclresult != ACLCHECK_OK)
 1954 peter_e                 14527 UIC           0 :                     aclcheck_error(aclresult, OBJECT_SCHEMA,
 6439 tgl                     14528               0 :                                    get_namespace_name(namespaceOid));
                              14529                 :             }
                              14530                 :         }
                              14531                 : 
 5271 tgl                     14532 CBC         218 :         memset(repl_null, false, sizeof(repl_null));
 5271 tgl                     14533 GIC         218 :         memset(repl_repl, false, sizeof(repl_repl));
                              14534                 : 
                              14535             218 :         repl_repl[Anum_pg_class_relowner - 1] = true;
 6494                         14536             218 :         repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
                              14537                 : 
                              14538                 :         /*
                              14539                 :          * Determine the modified ACL for the new owner.  This is only
                              14540                 :          * necessary when the ACL is non-null.
                              14541                 :          */
 6825                         14542             218 :         aclDatum = SysCacheGetAttr(RELOID, tuple,
 6825 tgl                     14543 ECB             :                                    Anum_pg_class_relacl,
                              14544                 :                                    &isNull);
 6825 tgl                     14545 GIC         218 :         if (!isNull)
                              14546                 :         {
                              14547              16 :             newAcl = aclnewowner(DatumGetAclP(aclDatum),
                              14548                 :                                  tuple_class->relowner, newOwnerId);
 5271                         14549              16 :             repl_repl[Anum_pg_class_relacl - 1] = true;
 6825                         14550              16 :             repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
                              14551                 :         }
                              14552                 : 
 5271                         14553             218 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
                              14554                 : 
 2259 alvherre                14555             218 :         CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
                              14556                 : 
 6825 tgl                     14557 CBC         218 :         heap_freetuple(newtuple);
 7655 bruce                   14558 ECB             : 
 4127 tgl                     14559                 :         /*
                              14560                 :          * We must similarly update any per-column ACLs to reflect the new
                              14561                 :          * owner; for neatness reasons that's split out as a subroutine.
                              14562                 :          */
 4127 tgl                     14563 GIC         218 :         change_owner_fix_column_acls(relationOid,
 4127 tgl                     14564 ECB             :                                      tuple_class->relowner,
                              14565                 :                                      newOwnerId);
                              14566                 : 
                              14567                 :         /*
                              14568                 :          * Update owner dependency reference, if any.  A composite type has
 5812                         14569                 :          * none, because it's tracked for the pg_type entry instead of here;
                              14570                 :          * indexes and TOAST tables don't have their own entries either.
                              14571                 :          */
 5812 tgl                     14572 GIC         218 :         if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
 5809                         14573             215 :             tuple_class->relkind != RELKIND_INDEX &&
 1906 alvherre                14574 CBC         173 :             tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
 5809 tgl                     14575 GIC         163 :             tuple_class->relkind != RELKIND_TOASTVALUE)
 5812                         14576             145 :             changeDependencyOnOwner(RelationRelationId, relationOid,
                              14577                 :                                     newOwnerId);
                              14578                 : 
 6457 tgl                     14579 ECB             :         /*
 4309 peter_e                 14580                 :          * Also change the ownership of the table's row type, if it has one
 6457 tgl                     14581                 :          */
 1006 tgl                     14582 GIC         218 :         if (OidIsValid(tuple_class->reltype))
 2670 alvherre                14583 CBC         139 :             AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
 6457 tgl                     14584 ECB             : 
 6862                         14585                 :         /*
                              14586                 :          * If we are operating on a table or materialized view, also change
                              14587                 :          * the ownership of any indexes and sequences that belong to the
                              14588                 :          * relation, as well as its toast table (if it has one).
                              14589                 :          */
 6862 tgl                     14590 GIC         218 :         if (tuple_class->relkind == RELKIND_RELATION ||
 1906 alvherre                14591             112 :             tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
 3689 kgrittn                 14592              93 :             tuple_class->relkind == RELKIND_MATVIEW ||
 6862 tgl                     14593 CBC          93 :             tuple_class->relkind == RELKIND_TOASTVALUE)
                              14594                 :         {
                              14595                 :             List       *index_oid_list;
                              14596                 :             ListCell   *i;
                              14597                 : 
                              14598                 :             /* Find all the indexes belonging to this relation */
 6862 tgl                     14599 GIC         143 :             index_oid_list = RelationGetIndexList(target_rel);
                              14600                 : 
                              14601                 :             /* For each index, recursively change its ownership */
                              14602             195 :             foreach(i, index_oid_list)
 4638 simon                   14603 CBC          52 :                 ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
                              14604                 : 
 6862 tgl                     14605             143 :             list_free(index_oid_list);
                              14606                 :         }
                              14607                 : 
 1760 peter_e                 14608 ECB             :         /* If it has a toast table, recurse to change its ownership */
 1760 peter_e                 14609 GIC         218 :         if (tuple_class->reltoastrelid != InvalidOid)
 1760 peter_e                 14610 CBC          18 :             ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
                              14611                 :                               true, lockmode);
 6772 tgl                     14612 ECB             : 
                              14613                 :         /* If it has dependent sequences, recurse to change them too */
 1760 peter_e                 14614 GIC         218 :         change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
 7655 bruce                   14615 ECB             :     }
                              14616                 : 
 3675 rhaas                   14617 CBC         934 :     InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
                              14618                 : 
 6825 tgl                     14619             934 :     ReleaseSysCache(tuple);
 1539 andres                  14620 GIC         934 :     table_close(class_rel, RowExclusiveLock);
 7601 tgl                     14621 CBC         934 :     relation_close(target_rel, NoLock);
 7655 bruce                   14622             934 : }
 7655 bruce                   14623 ECB             : 
 4127 tgl                     14624                 : /*
                              14625                 :  * change_owner_fix_column_acls
                              14626                 :  *
                              14627                 :  * Helper function for ATExecChangeOwner.  Scan the columns of the table
                              14628                 :  * and fix any non-null column ACLs to reflect the new owner.
                              14629                 :  */
                              14630                 : static void
 4127 tgl                     14631 GIC         218 : change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
 4127 tgl                     14632 ECB             : {
                              14633                 :     Relation    attRelation;
                              14634                 :     SysScanDesc scan;
                              14635                 :     ScanKeyData key[1];
                              14636                 :     HeapTuple   attributeTuple;
                              14637                 : 
 1539 andres                  14638 GIC         218 :     attRelation = table_open(AttributeRelationId, RowExclusiveLock);
 4127 tgl                     14639             218 :     ScanKeyInit(&key[0],
                              14640                 :                 Anum_pg_attribute_attrelid,
 4127 tgl                     14641 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              14642                 :                 ObjectIdGetDatum(relationOid));
 4127 tgl                     14643 GIC         218 :     scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
 3568 rhaas                   14644 ECB             :                               true, NULL, 1, key);
 4127 tgl                     14645 CBC        1502 :     while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
                              14646                 :     {
                              14647            1284 :         Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
                              14648                 :         Datum       repl_val[Natts_pg_attribute];
 4127 tgl                     14649 ECB             :         bool        repl_null[Natts_pg_attribute];
                              14650                 :         bool        repl_repl[Natts_pg_attribute];
                              14651                 :         Acl        *newAcl;
                              14652                 :         Datum       aclDatum;
                              14653                 :         bool        isNull;
                              14654                 :         HeapTuple   newtuple;
                              14655                 : 
                              14656                 :         /* Ignore dropped columns */
 4127 tgl                     14657 GIC        1284 :         if (att->attisdropped)
                              14658            1284 :             continue;
                              14659                 : 
                              14660            1284 :         aclDatum = heap_getattr(attributeTuple,
 4127 tgl                     14661 ECB             :                                 Anum_pg_attribute_attacl,
                              14662                 :                                 RelationGetDescr(attRelation),
                              14663                 :                                 &isNull);
                              14664                 :         /* Null ACLs do not require changes */
 4127 tgl                     14665 CBC        1284 :         if (isNull)
 4127 tgl                     14666 GIC        1284 :             continue;
 4127 tgl                     14667 ECB             : 
 4127 tgl                     14668 UIC           0 :         memset(repl_null, false, sizeof(repl_null));
 4127 tgl                     14669 LBC           0 :         memset(repl_repl, false, sizeof(repl_repl));
 4127 tgl                     14670 ECB             : 
 4127 tgl                     14671 LBC           0 :         newAcl = aclnewowner(DatumGetAclP(aclDatum),
 4127 tgl                     14672 ECB             :                              oldOwnerId, newOwnerId);
 4127 tgl                     14673 LBC           0 :         repl_repl[Anum_pg_attribute_attacl - 1] = true;
                              14674               0 :         repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
 4127 tgl                     14675 ECB             : 
 4127 tgl                     14676 UIC           0 :         newtuple = heap_modify_tuple(attributeTuple,
                              14677                 :                                      RelationGetDescr(attRelation),
 4127 tgl                     14678 ECB             :                                      repl_val, repl_null, repl_repl);
                              14679                 : 
 2259 alvherre                14680 UIC           0 :         CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
                              14681                 : 
 4127 tgl                     14682               0 :         heap_freetuple(newtuple);
 4127 tgl                     14683 ECB             :     }
 4127 tgl                     14684 GIC         218 :     systable_endscan(scan);
 1539 andres                  14685 CBC         218 :     table_close(attRelation, RowExclusiveLock);
 4127 tgl                     14686 GIC         218 : }
                              14687                 : 
                              14688                 : /*
                              14689                 :  * change_owner_recurse_to_sequences
                              14690                 :  *
                              14691                 :  * Helper function for ATExecChangeOwner.  Examines pg_depend searching
                              14692                 :  * for sequences that are dependent on serial columns, and changes their
                              14693                 :  * ownership.
                              14694                 :  */
                              14695                 : static void
 4638 simon                   14696 GBC         218 : change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
                              14697                 : {
                              14698                 :     Relation    depRel;
                              14699                 :     SysScanDesc scan;
 6385 bruce                   14700 ECB             :     ScanKeyData key[2];
                              14701                 :     HeapTuple   tup;
 6772 tgl                     14702                 : 
                              14703                 :     /*
 6075                         14704                 :      * SERIAL sequences are those having an auto dependency on one of the
                              14705                 :      * table's columns (we don't care *which* column, exactly).
 6772                         14706                 :      */
 1539 andres                  14707 CBC         218 :     depRel = table_open(DependRelationId, AccessShareLock);
                              14708                 : 
 6772 tgl                     14709             218 :     ScanKeyInit(&key[0],
 6385 bruce                   14710 ECB             :                 Anum_pg_depend_refclassid,
                              14711                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              14712                 :                 ObjectIdGetDatum(RelationRelationId));
 6772 tgl                     14713 GIC         218 :     ScanKeyInit(&key[1],
                              14714                 :                 Anum_pg_depend_refobjid,
 6385 bruce                   14715 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              14716                 :                 ObjectIdGetDatum(relationOid));
                              14717                 :     /* we leave refobjsubid unspecified */
                              14718                 : 
 6569 tgl                     14719 GIC         218 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
 3568 rhaas                   14720 ECB             :                               NULL, 2, key);
                              14721                 : 
 6772 tgl                     14722 GIC         605 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
 6772 tgl                     14723 EUB             :     {
 6772 tgl                     14724 GIC         387 :         Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
                              14725                 :         Relation    seqRel;
 6772 tgl                     14726 ECB             : 
                              14727                 :         /* skip dependencies other than auto dependencies on columns */
 6772 tgl                     14728 CBC         387 :         if (depForm->refobjsubid == 0 ||
 6569 tgl                     14729 GIC         134 :             depForm->classid != RelationRelationId ||
 6772                         14730              61 :             depForm->objsubid != 0 ||
 2194 peter_e                 14731              61 :             !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
 6772 tgl                     14732 CBC         326 :             continue;
                              14733                 : 
 6772 tgl                     14734 ECB             :         /* Use relation_open just in case it's an index */
 4638 simon                   14735 CBC          61 :         seqRel = relation_open(depForm->objid, lockmode);
 6772 tgl                     14736 ECB             : 
                              14737                 :         /* skip non-sequence relations */
 6772 tgl                     14738 CBC          61 :         if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
                              14739                 :         {
                              14740                 :             /* No need to keep the lock */
 4638 simon                   14741 GBC          52 :             relation_close(seqRel, lockmode);
 6772 tgl                     14742 GIC          52 :             continue;
                              14743                 :         }
                              14744                 : 
 6772 tgl                     14745 ECB             :         /* We don't need to close the sequence while we alter it. */
 4638 simon                   14746 CBC           9 :         ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
                              14747                 : 
                              14748                 :         /* Now we can close it.  Keep the lock till end of transaction. */
 6772 tgl                     14749 GIC           9 :         relation_close(seqRel, NoLock);
                              14750                 :     }
                              14751                 : 
                              14752             218 :     systable_endscan(scan);
                              14753                 : 
 6589                         14754             218 :     relation_close(depRel, AccessShareLock);
 6772                         14755             218 : }
                              14756                 : 
                              14757                 : /*
                              14758                 :  * ALTER TABLE CLUSTER ON
 7325 bruce                   14759 ECB             :  *
                              14760                 :  * The only thing we have to do is to change the indisclustered bits.
                              14761                 :  *
                              14762                 :  * Return the address of the new clustering index.
                              14763                 :  */
                              14764                 : static ObjectAddress
 4638 simon                   14765 GIC          32 : ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
                              14766                 : {
                              14767                 :     Oid         indexOid;
 2937 alvherre                14768 ECB             :     ObjectAddress address;
 7188 bruce                   14769                 : 
 7325 bruce                   14770 CBC          32 :     indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
                              14771                 : 
 7325 bruce                   14772 GIC          32 :     if (!OidIsValid(indexOid))
 7203 tgl                     14773 LBC           0 :         ereport(ERROR,
 7203 tgl                     14774 ECB             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              14775                 :                  errmsg("index \"%s\" for table \"%s\" does not exist",
 6913                         14776                 :                         indexName, RelationGetRelationName(rel))));
 7325 bruce                   14777                 : 
 6912 tgl                     14778                 :     /* Check index is valid to cluster on */
  361 michael                 14779 GIC          32 :     check_index_is_clusterable(rel, indexOid, lockmode);
                              14780                 : 
                              14781                 :     /* And do the work */
 3675 rhaas                   14782              32 :     mark_index_clustered(rel, indexOid, false);
                              14783                 : 
 2937 alvherre                14784 CBC          29 :     ObjectAddressSet(address,
 2937 alvherre                14785 ECB             :                      RelationRelationId, indexOid);
                              14786                 : 
 2937 alvherre                14787 GIC          29 :     return address;
                              14788                 : }
 7325 bruce                   14789 ECB             : 
                              14790                 : /*
                              14791                 :  * ALTER TABLE SET WITHOUT CLUSTER
 6885                         14792                 :  *
                              14793                 :  * We have to find any indexes on the table that have indisclustered bit
                              14794                 :  * set and turn it off.
                              14795                 :  */
                              14796                 : static void
 4638 simon                   14797 GIC           9 : ATExecDropCluster(Relation rel, LOCKMODE lockmode)
                              14798                 : {
 3675 rhaas                   14799               9 :     mark_index_clustered(rel, InvalidOid, false);
 6885 bruce                   14800               6 : }
                              14801                 : 
                              14802                 : /*
  620 michael                 14803 ECB             :  * Preparation phase for SET ACCESS METHOD
                              14804                 :  *
                              14805                 :  * Check that access method exists.  If it is the same as the table's current
                              14806                 :  * access method, it is a no-op.  Otherwise, a table rewrite is necessary.
                              14807                 :  */
                              14808                 : static void
  620 michael                 14809 GIC          15 : ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
  620 michael                 14810 ECB             : {
                              14811                 :     Oid         amoid;
                              14812                 : 
                              14813                 :     /* Check that the table access method exists */
  620 michael                 14814 GIC          15 :     amoid = get_table_am_oid(amname, false);
  620 michael                 14815 ECB             : 
  620 michael                 14816 CBC          15 :     if (rel->rd_rel->relam == amoid)
  620 michael                 14817 LBC           0 :         return;
                              14818                 : 
  620 michael                 14819 ECB             :     /* Save info for Phase 3 to do the real work */
  620 michael                 14820 GIC          15 :     tab->rewrite |= AT_REWRITE_ACCESS_METHOD;
  620 michael                 14821 CBC          15 :     tab->newAccessMethod = amoid;
                              14822                 : }
                              14823                 : 
                              14824                 : /*
                              14825                 :  * ALTER TABLE SET TABLESPACE
                              14826                 :  */
                              14827                 : static void
 1986 peter_e                 14828 GIC          79 : ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
                              14829                 : {
                              14830                 :     Oid         tablespaceId;
 6846 tgl                     14831 ECB             : 
                              14832                 :     /* Check that the tablespace exists */
 4630 rhaas                   14833 GIC          79 :     tablespaceId = get_tablespace_oid(tablespacename, false);
                              14834                 : 
                              14835                 :     /* Check permissions except when moving to database's default */
 3368 sfrost                  14836              79 :     if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
                              14837                 :     {
                              14838                 :         AclResult   aclresult;
                              14839                 : 
  147 peter                   14840 GNC          33 :         aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(), ACL_CREATE);
 3368 sfrost                  14841 CBC          33 :         if (aclresult != ACLCHECK_OK)
 1954 peter_e                 14842 UIC           0 :             aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
 3368 sfrost                  14843 ECB             :     }
 6846 tgl                     14844                 : 
 6846 tgl                     14845 EUB             :     /* Save info for Phase 3 to do the real work */
 6846 tgl                     14846 GIC          79 :     if (OidIsValid(tab->newTableSpace))
 6846 tgl                     14847 LBC           0 :         ereport(ERROR,
                              14848                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
 6385 bruce                   14849 ECB             :                  errmsg("cannot have multiple SET TABLESPACE subcommands")));
 3368 sfrost                  14850                 : 
 6846 tgl                     14851 GIC          79 :     tab->newTableSpace = tablespaceId;
 6846 tgl                     14852 CBC          79 : }
 6846 tgl                     14853 ECB             : 
 6125 bruce                   14854                 : /*
 4126 rhaas                   14855 EUB             :  * Set, reset, or replace reloptions.
 6125 bruce                   14856 ECB             :  */
                              14857                 : static void
 4126 rhaas                   14858 GIC         464 : ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 4126 rhaas                   14859 ECB             :                     LOCKMODE lockmode)
 6125 bruce                   14860                 : {
                              14861                 :     Oid         relid;
                              14862                 :     Relation    pgclass;
                              14863                 :     HeapTuple   tuple;
                              14864                 :     HeapTuple   newtuple;
                              14865                 :     Datum       datum;
                              14866                 :     bool        isnull;
                              14867                 :     Datum       newOptions;
                              14868                 :     Datum       repl_val[Natts_pg_class];
                              14869                 :     bool        repl_null[Natts_pg_class];
                              14870                 :     bool        repl_repl[Natts_pg_class];
 5050                         14871                 :     static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
                              14872                 : 
 4126 rhaas                   14873 GIC         464 :     if (defList == NIL && operation != AT_ReplaceRelOptions)
 6124 tgl                     14874 UIC           0 :         return;                 /* nothing to do */
                              14875                 : 
 1539 andres                  14876 GIC         464 :     pgclass = table_open(RelationRelationId, RowExclusiveLock);
                              14877                 : 
                              14878                 :     /* Fetch heap tuple */
 6124 tgl                     14879             464 :     relid = RelationGetRelid(rel);
 4802 rhaas                   14880             464 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
 6125 bruce                   14881             464 :     if (!HeapTupleIsValid(tuple))
 6125 bruce                   14882 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
                              14883                 : 
 4126 rhaas                   14884 GIC         464 :     if (operation == AT_ReplaceRelOptions)
                              14885                 :     {
                              14886                 :         /*
                              14887                 :          * If we're supposed to replace the reloptions list, we just pretend
                              14888                 :          * there were none before.
                              14889                 :          */
                              14890              97 :         datum = (Datum) 0;
                              14891              97 :         isnull = true;
 4126 rhaas                   14892 ECB             :     }
 4126 rhaas                   14893 EUB             :     else
                              14894                 :     {
                              14895                 :         /* Get the old reloptions */
 4126 rhaas                   14896 CBC         367 :         datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
 4126 rhaas                   14897 ECB             :                                 &isnull);
                              14898                 :     }
 6125 bruce                   14899 EUB             : 
                              14900                 :     /* Generate new proposed reloptions (text array) */
 6124 tgl                     14901 GIC         464 :     newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
                              14902                 :                                      defList, NULL, validnsps, false,
 3955 bruce                   14903 ECB             :                                      operation == AT_ResetRelOptions);
 6125                         14904                 : 
 6124 tgl                     14905                 :     /* Validate */
 6125 bruce                   14906 GIC         461 :     switch (rel->rd_rel->relkind)
 6125 bruce                   14907 ECB             :     {
 6125 bruce                   14908 CBC         253 :         case RELKIND_RELATION:
                              14909                 :         case RELKIND_TOASTVALUE:
 3689 kgrittn                 14910 ECB             :         case RELKIND_MATVIEW:
 6124 tgl                     14911 CBC         253 :             (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
 6125 bruce                   14912             253 :             break;
 1242 michael                 14913 GBC           3 :         case RELKIND_PARTITIONED_TABLE:
 1242 michael                 14914 GIC           3 :             (void) partitioned_table_reloptions(newOptions, true);
 1242 michael                 14915 UIC           0 :             break;
 3191 alvherre                14916 GIC         148 :         case RELKIND_VIEW:
                              14917             148 :             (void) view_reloptions(newOptions, true);
                              14918             139 :             break;
 6125 bruce                   14919 CBC          57 :         case RELKIND_INDEX:
 1906 alvherre                14920 ECB             :         case RELKIND_PARTITIONED_INDEX:
 1539 andres                  14921 CBC          57 :             (void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
 6125 bruce                   14922              46 :             break;
 6125 bruce                   14923 UIC           0 :         default:
 6124 tgl                     14924               0 :             ereport(ERROR,
                              14925                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              14926                 :                      errmsg("cannot set options for relation \"%s\"",
                              14927                 :                             RelationGetRelationName(rel)),
  640 peter                   14928 ECB             :                      errdetail_relkind_not_supported(rel->rd_rel->relkind)));
 6125 bruce                   14929                 :             break;
                              14930                 :     }
                              14931                 : 
                              14932                 :     /* Special-case validation of view options */
 3552 sfrost                  14933 CBC         438 :     if (rel->rd_rel->relkind == RELKIND_VIEW)
                              14934                 :     {
 3552 sfrost                  14935 GIC         139 :         Query      *view_query = get_view_query(rel);
                              14936             139 :         List       *view_options = untransformRelOptions(newOptions);
 3552 sfrost                  14937 ECB             :         ListCell   *cell;
 3552 sfrost                  14938 CBC         139 :         bool        check_option = false;
                              14939                 : 
 3552 sfrost                  14940 GIC         190 :         foreach(cell, view_options)
 3552 sfrost                  14941 ECB             :         {
 3552 sfrost                  14942 GIC          51 :             DefElem    *defel = (DefElem *) lfirst(cell);
                              14943                 : 
 1899 tgl                     14944              51 :             if (strcmp(defel->defname, "check_option") == 0)
 3552 sfrost                  14945              12 :                 check_option = true;
 3552 sfrost                  14946 ECB             :         }
                              14947                 : 
                              14948                 :         /*
 3552 sfrost                  14949 EUB             :          * If the check option is specified, look to see if the view is
                              14950                 :          * actually auto-updatable or not.
 3552 sfrost                  14951 ECB             :          */
 3552 sfrost                  14952 GIC         139 :         if (check_option)
                              14953                 :         {
                              14954                 :             const char *view_updatable_error =
 3260 bruce                   14955 CBC          12 :             view_query_is_auto_updatable(view_query, true);
                              14956                 : 
 3552 sfrost                  14957 GIC          12 :             if (view_updatable_error)
 3552 sfrost                  14958 LBC           0 :                 ereport(ERROR,
                              14959                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 3101 peter_e                 14960 ECB             :                          errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
                              14961                 :                          errhint("%s", _(view_updatable_error))));
                              14962                 :         }
 3552 sfrost                  14963                 :     }
                              14964                 : 
                              14965                 :     /*
 6124 tgl                     14966                 :      * All we need do here is update the pg_class row; the new options will be
                              14967                 :      * propagated into relcaches during post-commit cache inval.
                              14968                 :      */
 6124 tgl                     14969 GIC         438 :     memset(repl_val, 0, sizeof(repl_val));
 5271 tgl                     14970 CBC         438 :     memset(repl_null, false, sizeof(repl_null));
 5271 tgl                     14971 GIC         438 :     memset(repl_repl, false, sizeof(repl_repl));
 6125 bruce                   14972 ECB             : 
 6124 tgl                     14973 GIC         438 :     if (newOptions != (Datum) 0)
                              14974             294 :         repl_val[Anum_pg_class_reloptions - 1] = newOptions;
                              14975                 :     else
 5271                         14976             144 :         repl_null[Anum_pg_class_reloptions - 1] = true;
                              14977                 : 
                              14978             438 :     repl_repl[Anum_pg_class_reloptions - 1] = true;
                              14979                 : 
                              14980             438 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
                              14981                 :                                  repl_val, repl_null, repl_repl);
                              14982                 : 
 2259 alvherre                14983             438 :     CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
                              14984                 : 
 3675 rhaas                   14985             438 :     InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
                              14986                 : 
 6124 tgl                     14987             438 :     heap_freetuple(newtuple);
 6125 bruce                   14988 ECB             : 
 6125 bruce                   14989 GIC         438 :     ReleaseSysCache(tuple);
                              14990                 : 
                              14991                 :     /* repeat the whole exercise for the toast table, if there's one */
 5179 alvherre                14992             438 :     if (OidIsValid(rel->rd_rel->reltoastrelid))
                              14993                 :     {
                              14994                 :         Relation    toastrel;
                              14995             128 :         Oid         toastid = rel->rd_rel->reltoastrelid;
                              14996                 : 
 1539 andres                  14997             128 :         toastrel = table_open(toastid, lockmode);
                              14998                 : 
 4126 rhaas                   14999 ECB             :         /* Fetch heap tuple */
 4802 rhaas                   15000 GIC         128 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
 5179 alvherre                15001             128 :         if (!HeapTupleIsValid(tuple))
 5179 alvherre                15002 LBC           0 :             elog(ERROR, "cache lookup failed for relation %u", toastid);
                              15003                 : 
 4126 rhaas                   15004 CBC         128 :         if (operation == AT_ReplaceRelOptions)
 4126 rhaas                   15005 ECB             :         {
 4126 rhaas                   15006 EUB             :             /*
 4126 rhaas                   15007 ECB             :              * If we're supposed to replace the reloptions list, we just
                              15008                 :              * pretend there were none before.
                              15009                 :              */
 4126 rhaas                   15010 LBC           0 :             datum = (Datum) 0;
 4126 rhaas                   15011 UIC           0 :             isnull = true;
 4126 rhaas                   15012 ECB             :         }
                              15013                 :         else
                              15014                 :         {
                              15015                 :             /* Get the old reloptions */
 4126 rhaas                   15016 GIC         128 :             datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
                              15017                 :                                     &isnull);
 4126 rhaas                   15018 ECB             :         }
 5179 alvherre                15019                 : 
 5179 alvherre                15020 CBC         128 :         newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
                              15021                 :                                          defList, "toast", validnsps, false,
                              15022                 :                                          operation == AT_ResetRelOptions);
                              15023                 : 
 5179 alvherre                15024 GIC         128 :         (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
                              15025                 : 
                              15026             128 :         memset(repl_val, 0, sizeof(repl_val));
                              15027             128 :         memset(repl_null, false, sizeof(repl_null));
                              15028             128 :         memset(repl_repl, false, sizeof(repl_repl));
 5179 alvherre                15029 EUB             : 
 5179 alvherre                15030 GBC         128 :         if (newOptions != (Datum) 0)
 5179 alvherre                15031 GIC          21 :             repl_val[Anum_pg_class_reloptions - 1] = newOptions;
                              15032                 :         else
                              15033             107 :             repl_null[Anum_pg_class_reloptions - 1] = true;
                              15034                 : 
                              15035             128 :         repl_repl[Anum_pg_class_reloptions - 1] = true;
 5179 alvherre                15036 EUB             : 
 5179 alvherre                15037 GIC         128 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
 5179 alvherre                15038 ECB             :                                      repl_val, repl_null, repl_repl);
                              15039                 : 
 2259 alvherre                15040 CBC         128 :         CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
 5179 alvherre                15041 ECB             : 
 3675 rhaas                   15042 GBC         128 :         InvokeObjectPostAlterHookArg(RelationRelationId,
                              15043                 :                                      RelationGetRelid(toastrel), 0,
                              15044                 :                                      InvalidOid, true);
                              15045                 : 
 5179 alvherre                15046 GIC         128 :         heap_freetuple(newtuple);
                              15047                 : 
 5179 alvherre                15048 CBC         128 :         ReleaseSysCache(tuple);
 5179 alvherre                15049 ECB             : 
 1539 andres                  15050 CBC         128 :         table_close(toastrel, NoLock);
                              15051                 :     }
                              15052                 : 
 1539 andres                  15053 GIC         438 :     table_close(pgclass, RowExclusiveLock);
                              15054                 : }
                              15055                 : 
 6846 tgl                     15056 EUB             : /*
                              15057                 :  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
                              15058                 :  * rewriting to be done, so we just want to copy the data as fast as possible.
                              15059                 :  */
                              15060                 : static void
 4638 simon                   15061 GIC          81 : ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
                              15062                 : {
                              15063                 :     Relation    rel;
                              15064                 :     Oid         reltoastrelid;
                              15065                 :     RelFileNumber newrelfilenumber;
                              15066                 :     RelFileLocator newrlocator;
 3566 fujii                   15067 CBC          81 :     List       *reltoastidxids = NIL;
 3566 fujii                   15068 ECB             :     ListCell   *lc;
 6846 tgl                     15069                 : 
 6096 tgl                     15070 EUB             :     /*
                              15071                 :      * Need lock here in case we are recursing to toast table or index
                              15072                 :      */
 4638 simon                   15073 GIC          81 :     rel = relation_open(tableOid, lockmode);
                              15074                 : 
                              15075                 :     /* Check first if relation can be moved to new tablespace */
  802 michael                 15076 CBC          81 :     if (!CheckRelationTableSpaceMove(rel, newTableSpace))
 4809 tgl                     15077 ECB             :     {
 3675 rhaas                   15078 CBC           1 :         InvokeObjectPostAlterHook(RelationRelationId,
                              15079                 :                                   RelationGetRelid(rel), 0);
 4809 tgl                     15080 GIC           1 :         relation_close(rel, NoLock);
 4809 tgl                     15081 GBC           1 :         return;
                              15082                 :     }
                              15083                 : 
 6846 tgl                     15084 GIC          80 :     reltoastrelid = rel->rd_rel->reltoastrelid;
                              15085                 :     /* Fetch the list of indexes on toast relation if necessary */
 3566 fujii                   15086              80 :     if (OidIsValid(reltoastrelid))
                              15087                 :     {
 3260 bruce                   15088              10 :         Relation    toastRel = relation_open(reltoastrelid, lockmode);
                              15089                 : 
 3566 fujii                   15090              10 :         reltoastidxids = RelationGetIndexList(toastRel);
                              15091              10 :         relation_close(toastRel, lockmode);
 3566 fujii                   15092 ECB             :     }
                              15093                 : 
                              15094                 :     /*
                              15095                 :      * Relfilenumbers are not unique in databases across tablespaces, so we
                              15096                 :      * need to allocate a new one in the new tablespace.
                              15097                 :      */
  193 rhaas                   15098 GNC          80 :     newrelfilenumber = GetNewRelFileNumber(newTableSpace, NULL,
  277                         15099              80 :                                            rel->rd_rel->relpersistence);
                              15100                 : 
                              15101                 :     /* Open old and new relation */
                              15102              80 :     newrlocator = rel->rd_locator;
                              15103              80 :     newrlocator.relNumber = newrelfilenumber;
                              15104              80 :     newrlocator.spcOid = newTableSpace;
                              15105                 : 
                              15106                 :     /* hand off to AM to actually create new rel storage and copy the data */
 1473 andres                  15107 GIC          80 :     if (rel->rd_rel->relkind == RELKIND_INDEX)
 5354 heikki.linnakangas      15108 ECB             :     {
  277 rhaas                   15109 GNC          31 :         index_copy_data(rel, newrlocator);
                              15110                 :     }
                              15111                 :     else
 1473 andres                  15112 ECB             :     {
  492 peter                   15113 GBC          49 :         Assert(RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind));
  277 rhaas                   15114 GNC          49 :         table_relation_copy_data(rel, &newrlocator);
                              15115                 :     }
                              15116                 : 
 1441 andres                  15117 ECB             :     /*
                              15118                 :      * Update the pg_class row.
                              15119                 :      *
                              15120                 :      * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
                              15121                 :      * executed on pg_class or its indexes (the above copy wouldn't contain
  802 michael                 15122                 :      * the updated pg_class entry), but that's forbidden with
  802 michael                 15123 EUB             :      * CheckRelationTableSpaceMove().
 1441 andres                  15124                 :      */
  277 rhaas                   15125 GNC          80 :     SetRelationTableSpace(rel, newTableSpace, newrelfilenumber);
                              15126                 : 
 3675 rhaas                   15127 GIC          80 :     InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
 3675 rhaas                   15128 ECB             : 
  277 rhaas                   15129 GNC          80 :     RelationAssumeNewRelfilelocator(rel);
                              15130                 : 
 6846 tgl                     15131 CBC          80 :     relation_close(rel, NoLock);
 6846 tgl                     15132 ECB             : 
                              15133                 :     /* Make sure the reltablespace change is visible */
 6846 tgl                     15134 GIC          80 :     CommandCounterIncrement();
                              15135                 : 
                              15136                 :     /* Move associated toast relation and/or indexes, too */
                              15137              80 :     if (OidIsValid(reltoastrelid))
 4638 simon                   15138 CBC          10 :         ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
 3566 fujii                   15139 GIC          90 :     foreach(lc, reltoastidxids)
                              15140              10 :         ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
 3566 fujii                   15141 ECB             : 
                              15142                 :     /* Clean up */
 3566 fujii                   15143 CBC          80 :     list_free(reltoastidxids);
                              15144                 : }
 6846 tgl                     15145 ECB             : 
 1618 alvherre                15146                 : /*
                              15147                 :  * Special handling of ALTER TABLE SET TABLESPACE for relations with no
                              15148                 :  * storage that have an interest in preserving tablespace.
 1574                         15149                 :  *
                              15150                 :  * Since these have no storage the tablespace can be updated with a simple
                              15151                 :  * metadata only operation to update the tablespace.
                              15152                 :  */
 1618                         15153                 : static void
 1574 alvherre                15154 GIC          18 : ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
                              15155                 : {
                              15156                 :     /*
                              15157                 :      * Shouldn't be called on relations having storage; these are processed in
                              15158                 :      * phase 3.
 1574 alvherre                15159 ECB             :      */
 1556 alvherre                15160 GIC          18 :     Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
                              15161                 : 
                              15162                 :     /* check if relation can be moved to its new tablespace */
  802 michael                 15163              18 :     if (!CheckRelationTableSpaceMove(rel, newTableSpace))
                              15164                 :     {
  802 michael                 15165 UIC           0 :         InvokeObjectPostAlterHook(RelationRelationId,
                              15166                 :                                   RelationGetRelid(rel),
                              15167                 :                                   0);
 1618 alvherre                15168 LBC           0 :         return;
 1618 alvherre                15169 ECB             :     }
                              15170                 : 
  802 michael                 15171                 :     /* Update can be done, so change reltablespace */
  802 michael                 15172 CBC          15 :     SetRelationTableSpace(rel, newTableSpace, InvalidOid);
                              15173                 : 
  802 michael                 15174 GIC          15 :     InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
                              15175                 : 
                              15176                 :     /* Make sure the reltablespace change is visible */
 1618 alvherre                15177              15 :     CommandCounterIncrement();
 1618 alvherre                15178 ECB             : }
                              15179                 : 
                              15180                 : /*
                              15181                 :  * Alter Table ALL ... SET TABLESPACE
                              15182                 :  *
                              15183                 :  * Allows a user to move all objects of some type in a given tablespace in the
                              15184                 :  * current database to another tablespace.  Objects can be chosen based on the
                              15185                 :  * owner of the object also, to allow users to move only their objects.
 3153 sfrost                  15186                 :  * The user must have CREATE rights on the new tablespace, as usual.   The main
                              15187                 :  * permissions handling is done by the lower-level table move function.
                              15188                 :  *
                              15189                 :  * All to-be-moved objects are locked first. If NOWAIT is specified and the
                              15190                 :  * lock can't be acquired then we ereport(ERROR).
                              15191                 :  */
                              15192                 : Oid
 3153 sfrost                  15193 GIC          15 : AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
                              15194                 : {
 3153 sfrost                  15195 CBC          15 :     List       *relations = NIL;
                              15196                 :     ListCell   *l;
                              15197                 :     ScanKeyData key[1];
 3153 sfrost                  15198 ECB             :     Relation    rel;
 1490 andres                  15199                 :     TableScanDesc scan;
                              15200                 :     HeapTuple   tuple;
 3153 sfrost                  15201                 :     Oid         orig_tablespaceoid;
                              15202                 :     Oid         new_tablespaceoid;
 2953 alvherre                15203 GIC          15 :     List       *role_oids = roleSpecsToIds(stmt->roles);
                              15204                 : 
 3153 sfrost                  15205 ECB             :     /* Ensure we were not asked to move something we can't */
 3153 sfrost                  15206 CBC          15 :     if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
 3153 sfrost                  15207 GIC           6 :         stmt->objtype != OBJECT_MATVIEW)
 3153 sfrost                  15208 UIC           0 :         ereport(ERROR,
                              15209                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 3153 sfrost                  15210 ECB             :                  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
                              15211                 : 
                              15212                 :     /* Get the orig and new tablespace OIDs */
 3153 sfrost                  15213 CBC          15 :     orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
 3153 sfrost                  15214 GIC          15 :     new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
 3153 sfrost                  15215 ECB             : 
                              15216                 :     /* Can't move shared relations in to or out of pg_global */
                              15217                 :     /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
 3153 sfrost                  15218 CBC          15 :     if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
                              15219                 :         new_tablespaceoid == GLOBALTABLESPACE_OID)
 3153 sfrost                  15220 UIC           0 :         ereport(ERROR,
                              15221                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                              15222                 :                  errmsg("cannot move relations in to or out of pg_global tablespace")));
                              15223                 : 
                              15224                 :     /*
                              15225                 :      * Must have CREATE rights on the new tablespace, unless it is the
                              15226                 :      * database default tablespace (which all users implicitly have CREATE
 3153 sfrost                  15227 ECB             :      * rights on).
                              15228                 :      */
 3153 sfrost                  15229 GIC          15 :     if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
                              15230                 :     {
                              15231                 :         AclResult   aclresult;
                              15232                 : 
  147 peter                   15233 UNC           0 :         aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
 3153 sfrost                  15234 ECB             :                                            ACL_CREATE);
 3153 sfrost                  15235 LBC           0 :         if (aclresult != ACLCHECK_OK)
 1954 peter_e                 15236 UIC           0 :             aclcheck_error(aclresult, OBJECT_TABLESPACE,
 3153 sfrost                  15237               0 :                            get_tablespace_name(new_tablespaceoid));
                              15238                 :     }
 3153 sfrost                  15239 ECB             : 
                              15240                 :     /*
                              15241                 :      * Now that the checks are done, check if we should set either to
                              15242                 :      * InvalidOid because it is our database's default tablespace.
                              15243                 :      */
 3153 sfrost                  15244 GIC          15 :     if (orig_tablespaceoid == MyDatabaseTableSpace)
 3153 sfrost                  15245 UIC           0 :         orig_tablespaceoid = InvalidOid;
                              15246                 : 
 3153 sfrost                  15247 GIC          15 :     if (new_tablespaceoid == MyDatabaseTableSpace)
                              15248              15 :         new_tablespaceoid = InvalidOid;
                              15249                 : 
                              15250                 :     /* no-op */
                              15251              15 :     if (orig_tablespaceoid == new_tablespaceoid)
 3153 sfrost                  15252 UIC           0 :         return new_tablespaceoid;
 3153 sfrost                  15253 ECB             : 
                              15254                 :     /*
                              15255                 :      * Walk the list of objects in the tablespace and move them. This will
                              15256                 :      * only find objects in our database, of course.
                              15257                 :      */
 3153 sfrost                  15258 GIC          15 :     ScanKeyInit(&key[0],
                              15259                 :                 Anum_pg_class_reltablespace,
                              15260                 :                 BTEqualStrategyNumber, F_OIDEQ,
 3153 sfrost                  15261 ECB             :                 ObjectIdGetDatum(orig_tablespaceoid));
                              15262                 : 
 1539 andres                  15263 GIC          15 :     rel = table_open(RelationRelationId, AccessShareLock);
 1490 andres                  15264 GBC          15 :     scan = table_beginscan_catalog(rel, 1, key);
 3153 sfrost                  15265              66 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
                              15266                 :     {
 1601 andres                  15267              51 :         Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
 1601 andres                  15268 GIC          51 :         Oid         relOid = relForm->oid;
 3153 sfrost                  15269 EUB             : 
                              15270                 :         /*
                              15271                 :          * Do not move objects in pg_catalog as part of this, if an admin
                              15272                 :          * really wishes to do so, they can issue the individual ALTER
                              15273                 :          * commands directly.
                              15274                 :          *
                              15275                 :          * Also, explicitly avoid any shared tables, temp tables, or TOAST
                              15276                 :          * (TOAST will be moved with the main table).
                              15277                 :          */
 1432 tgl                     15278 GBC          51 :         if (IsCatalogNamespace(relForm->relnamespace) ||
 1432 tgl                     15279 GIC         102 :             relForm->relisshared ||
 3153 sfrost                  15280 CBC         102 :             isAnyTempNamespace(relForm->relnamespace) ||
 1432 tgl                     15281              51 :             IsToastNamespace(relForm->relnamespace))
 3153 sfrost                  15282 LBC           0 :             continue;
                              15283                 : 
                              15284                 :         /* Only move the object type requested */
 3153 sfrost                  15285 GIC          51 :         if ((stmt->objtype == OBJECT_TABLE &&
 2314 rhaas                   15286              30 :              relForm->relkind != RELKIND_RELATION &&
                              15287              18 :              relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
 3153 sfrost                  15288              33 :             (stmt->objtype == OBJECT_INDEX &&
 1906 alvherre                15289              18 :              relForm->relkind != RELKIND_INDEX &&
                              15290               3 :              relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
 3153 sfrost                  15291              30 :             (stmt->objtype == OBJECT_MATVIEW &&
 3153 sfrost                  15292 CBC           3 :              relForm->relkind != RELKIND_MATVIEW))
 3153 sfrost                  15293 GIC          21 :             continue;
                              15294                 : 
                              15295                 :         /* Check if we are only moving objects owned by certain roles */
                              15296              30 :         if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
 3153 sfrost                  15297 UIC           0 :             continue;
                              15298                 : 
                              15299                 :         /*
                              15300                 :          * Handle permissions-checking here since we are locking the tables
                              15301                 :          * and also to avoid doing a bunch of work only to fail part-way. Note
                              15302                 :          * that permissions will also be checked by AlterTableInternal().
 3153 sfrost                  15303 ECB             :          *
                              15304                 :          * Caller must be considered an owner on the table to move it.
                              15305                 :          */
  147 peter                   15306 GNC          30 :         if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
 1954 peter_e                 15307 UIC           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)),
 3153 sfrost                  15308               0 :                            NameStr(relForm->relname));
 3153 sfrost                  15309 ECB             : 
 3153 sfrost                  15310 GIC          30 :         if (stmt->nowait &&
 3153 sfrost                  15311 UIC           0 :             !ConditionalLockRelationOid(relOid, AccessExclusiveLock))
                              15312               0 :             ereport(ERROR,
                              15313                 :                     (errcode(ERRCODE_OBJECT_IN_USE),
                              15314                 :                      errmsg("aborting because lock on relation \"%s.%s\" is not available",
 2878 bruce                   15315 ECB             :                             get_namespace_name(relForm->relnamespace),
                              15316                 :                             NameStr(relForm->relname))));
                              15317                 :         else
 3153 sfrost                  15318 CBC          30 :             LockRelationOid(relOid, AccessExclusiveLock);
                              15319                 : 
 3153 sfrost                  15320 ECB             :         /* Add to our list of objects to move */
 3153 sfrost                  15321 GIC          30 :         relations = lappend_oid(relations, relOid);
                              15322                 :     }
                              15323                 : 
 1490 andres                  15324 CBC          15 :     table_endscan(scan);
 1539                         15325              15 :     table_close(rel, AccessShareLock);
 3153 sfrost                  15326 ECB             : 
 3153 sfrost                  15327 CBC          15 :     if (relations == NIL)
                              15328               6 :         ereport(NOTICE,
                              15329                 :                 (errcode(ERRCODE_NO_DATA_FOUND),
                              15330                 :                  errmsg("no matching relations in tablespace \"%s\" found",
 2118 tgl                     15331 ECB             :                         orig_tablespaceoid == InvalidOid ? "(database default)" :
                              15332                 :                         get_tablespace_name(orig_tablespaceoid))));
                              15333                 : 
 3153 sfrost                  15334                 :     /* Everything is locked, loop through and move all of the relations. */
 3153 sfrost                  15335 GIC          45 :     foreach(l, relations)
                              15336                 :     {
 3153 sfrost                  15337 CBC          30 :         List       *cmds = NIL;
                              15338              30 :         AlterTableCmd *cmd = makeNode(AlterTableCmd);
                              15339                 : 
 3153 sfrost                  15340 GIC          30 :         cmd->subtype = AT_SetTableSpace;
                              15341              30 :         cmd->name = stmt->new_tablespacename;
 3153 sfrost                  15342 ECB             : 
 3153 sfrost                  15343 GIC          30 :         cmds = lappend(cmds, cmd);
                              15344                 : 
 2890 alvherre                15345 CBC          30 :         EventTriggerAlterTableStart((Node *) stmt);
                              15346                 :         /* OID is set by AlterTableInternal */
 3153 sfrost                  15347 GIC          30 :         AlterTableInternal(lfirst_oid(l), cmds, false);
 2890 alvherre                15348 CBC          30 :         EventTriggerAlterTableEnd();
                              15349                 :     }
 3153 sfrost                  15350 ECB             : 
 3153 sfrost                  15351 CBC          15 :     return new_tablespaceoid;
                              15352                 : }
                              15353                 : 
                              15354                 : static void
  277 rhaas                   15355 GNC          31 : index_copy_data(Relation rel, RelFileLocator newrlocator)
                              15356                 : {
                              15357                 :     SMgrRelation dstrel;
                              15358                 : 
                              15359              31 :     dstrel = smgropen(newrlocator, rel->rd_backend);
                              15360                 : 
 1441 andres                  15361 ECB             :     /*
                              15362                 :      * Since we copy the file directly without looking at the shared buffers,
                              15363                 :      * we'd better first flush out any pages of the source relation that are
                              15364                 :      * in shared buffers.  We assume no new changes will be made while we are
                              15365                 :      * holding exclusive lock on the rel.
                              15366                 :      */
 1441 andres                  15367 GIC          31 :     FlushRelationBuffers(rel);
 1441 andres                  15368 ECB             : 
 6846 tgl                     15369 EUB             :     /*
                              15370                 :      * Create and copy all forks of the relation, and schedule unlinking of
                              15371                 :      * old physical files.
                              15372                 :      *
                              15373                 :      * NOTE: any conflict in relfilenumber value will be caught in
                              15374                 :      * RelationCreateStorage().
 6846 tgl                     15375 ECB             :      */
  277 rhaas                   15376 GNC          31 :     RelationCreateStorage(newrlocator, rel->rd_rel->relpersistence, true);
                              15377                 : 
 1473 andres                  15378 ECB             :     /* copy main fork */
  636 tgl                     15379 GIC          31 :     RelationCopyStorage(RelationGetSmgr(rel), dstrel, MAIN_FORKNUM,
 1473 andres                  15380 CBC          31 :                         rel->rd_rel->relpersistence);
                              15381                 : 
                              15382                 :     /* copy those extra forks that exist */
                              15383              31 :     for (ForkNumber forkNum = MAIN_FORKNUM + 1;
 1473 andres                  15384 GIC         124 :          forkNum <= MAX_FORKNUM; forkNum++)
                              15385                 :     {
  636 tgl                     15386              93 :         if (smgrexists(RelationGetSmgr(rel), forkNum))
                              15387                 :         {
 1473 andres                  15388 UIC           0 :             smgrcreate(dstrel, forkNum, false);
                              15389                 : 
                              15390                 :             /*
                              15391                 :              * WAL log creation if the relation is persistent, or this is the
                              15392                 :              * init fork of an unlogged relation.
 1473 andres                  15393 ECB             :              */
  748 bruce                   15394 UIC           0 :             if (RelationIsPermanent(rel) ||
 1473 andres                  15395 LBC           0 :                 (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
 1473 andres                  15396 ECB             :                  forkNum == INIT_FORKNUM))
  277 rhaas                   15397 UNC           0 :                 log_smgrcreate(&newrlocator, forkNum);
  636 tgl                     15398 UIC           0 :             RelationCopyStorage(RelationGetSmgr(rel), dstrel, forkNum,
 1473 andres                  15399               0 :                                 rel->rd_rel->relpersistence);
                              15400                 :         }
                              15401                 :     }
                              15402                 : 
                              15403                 :     /* drop old relation, and close new one */
 1473 andres                  15404 GIC          31 :     RelationDropStorage(rel);
 1473 andres                  15405 CBC          31 :     smgrclose(dstrel);
 6846 tgl                     15406 GIC          31 : }
                              15407                 : 
                              15408                 : /*
                              15409                 :  * ALTER TABLE ENABLE/DISABLE TRIGGER
 6438 tgl                     15410 ECB             :  *
                              15411                 :  * We just pass this off to trigger.c.
                              15412                 :  */
 6438 tgl                     15413 EUB             : static void
 1986 peter_e                 15414 GIC         168 : ATExecEnableDisableTrigger(Relation rel, const char *trigname,
                              15415                 :                            char fires_when, bool skip_system, bool recurse,
  248 alvherre                15416 ECB             :                            LOCKMODE lockmode)
 5865 JanWieck                15417                 : {
   36 tgl                     15418 GNC         168 :     EnableDisableTrigger(rel, trigname, InvalidOid,
                              15419                 :                          fires_when, skip_system, recurse,
                              15420                 :                          lockmode);
 5865 JanWieck                15421 GIC         168 : }
                              15422                 : 
                              15423                 : /*
 5865 JanWieck                15424 ECB             :  * ALTER TABLE ENABLE/DISABLE RULE
                              15425                 :  *
                              15426                 :  * We just pass this off to rewriteDefine.c.
                              15427                 :  */
                              15428                 : static void
 1986 peter_e                 15429 CBC           9 : ATExecEnableDisableRule(Relation rel, const char *rulename,
                              15430                 :                         char fires_when, LOCKMODE lockmode)
                              15431                 : {
 2228                         15432               9 :     EnableDisableRule(rel, rulename, fires_when);
 6438 tgl                     15433 GIC           9 : }
                              15434                 : 
                              15435                 : /*
 6125 neilc                   15436 ECB             :  * ALTER TABLE INHERIT
                              15437                 :  *
 6125 neilc                   15438 EUB             :  * Add a parent to the child's parents. This verifies that all the columns and
                              15439                 :  * check constraints of the parent appear in the child and that they have the
                              15440                 :  * same data types and expressions.
                              15441                 :  */
 4643 peter_e                 15442 ECB             : static void
 4643 peter_e                 15443 GBC         143 : ATPrepAddInherit(Relation child_rel)
                              15444                 : {
 4643 peter_e                 15445 GIC         143 :     if (child_rel->rd_rel->reloftype)
                              15446               3 :         ereport(ERROR,
 4643 peter_e                 15447 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15448                 :                  errmsg("cannot change inheritance of typed table")));
                              15449                 : 
 2314 rhaas                   15450 GIC         140 :     if (child_rel->rd_rel->relispartition)
                              15451               3 :         ereport(ERROR,
                              15452                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15453                 :                  errmsg("cannot change inheritance of a partition")));
 2314 rhaas                   15454 ECB             : 
 2314 rhaas                   15455 GIC         137 :     if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              15456               3 :         ereport(ERROR,
                              15457                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15458                 :                  errmsg("cannot change inheritance of partitioned table")));
 4643 peter_e                 15459             134 : }
                              15460                 : 
                              15461                 : /*
                              15462                 :  * Return the address of the new parent relation.
                              15463                 :  */
                              15464                 : static ObjectAddress
 4638 simon                   15465             134 : ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
                              15466                 : {
                              15467                 :     Relation    parent_rel;
                              15468                 :     List       *children;
 2937 alvherre                15469 ECB             :     ObjectAddress address;
 2111 rhodiumtoad             15470 EUB             :     const char *trigger_name;
                              15471                 : 
 6022 tgl                     15472 ECB             :     /*
                              15473                 :      * A self-exclusive lock is needed here.  See the similar case in
                              15474                 :      * MergeAttributes() for a full explanation.
                              15475                 :      */
 1539 andres                  15476 CBC         134 :     parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
 6125 bruce                   15477 ECB             : 
 6125 bruce                   15478 EUB             :     /*
                              15479                 :      * Must be owner of both parent and child -- child was checked by
 6125 bruce                   15480 ECB             :      * ATSimplePermissions call in ATPrepCmd
                              15481                 :      */
  640 peter                   15482 GIC         134 :     ATSimplePermissions(AT_AddInherit, parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                              15483                 : 
                              15484                 :     /* Permanent rels cannot inherit from temporary ones */
 3765 tgl                     15485             134 :     if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
 3765 tgl                     15486 CBC           3 :         child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
 6125 bruce                   15487 LBC           0 :         ereport(ERROR,
                              15488                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15489                 :                  errmsg("cannot inherit from temporary relation \"%s\"",
                              15490                 :                         RelationGetRelationName(parent_rel))));
                              15491                 : 
 3765 tgl                     15492 ECB             :     /* If parent rel is temp, it must belong to this session */
 3765 tgl                     15493 GIC         134 :     if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              15494               3 :         !parent_rel->rd_islocaltemp)
 3765 tgl                     15495 UIC           0 :         ereport(ERROR,
                              15496                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 2118 tgl                     15497 ECB             :                  errmsg("cannot inherit from temporary relation of another session")));
                              15498                 : 
                              15499                 :     /* Ditto for the child */
 3765 tgl                     15500 GIC         134 :     if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              15501               3 :         !child_rel->rd_islocaltemp)
 3765 tgl                     15502 LBC           0 :         ereport(ERROR,
                              15503                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 2118 tgl                     15504 ECB             :                  errmsg("cannot inherit to temporary relation of another session")));
                              15505                 : 
                              15506                 :     /* Prevent partitioned tables from becoming inheritance parents */
 2314 rhaas                   15507 CBC         134 :     if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              15508               3 :         ereport(ERROR,
 2314 rhaas                   15509 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15510                 :                  errmsg("cannot inherit from partitioned table \"%s\"",
 2314 rhaas                   15511 EUB             :                         parent->relname)));
 2314 rhaas                   15512 ECB             : 
                              15513                 :     /* Likewise for partitions */
 2314 rhaas                   15514 CBC         131 :     if (parent_rel->rd_rel->relispartition)
                              15515               3 :         ereport(ERROR,
                              15516                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 2314 rhaas                   15517 ECB             :                  errmsg("cannot inherit from a partition")));
                              15518                 : 
 6125 bruce                   15519 EUB             :     /*
 2314 rhaas                   15520                 :      * Prevent circularity by seeing if proposed parent inherits from child.
                              15521                 :      * (In particular, this disallows making a rel inherit from itself.)
                              15522                 :      *
                              15523                 :      * This is not completely bulletproof because of race conditions: in
                              15524                 :      * multi-level inheritance trees, someone else could concurrently be
                              15525                 :      * making another inheritance link that closes the loop but does not join
                              15526                 :      * either of the rels we have locked.  Preventing that seems to require
                              15527                 :      * exclusive locks on the entire inheritance tree, which is a cure worse
                              15528                 :      * than the disease.  find_all_inheritors() will cope with circularity
 2314 rhaas                   15529 ECB             :      * anyway, so don't sweat it too much.
                              15530                 :      *
                              15531                 :      * We use weakest lock we can on child's children, namely AccessShareLock.
 6125 bruce                   15532                 :      */
 2314 rhaas                   15533 GIC         128 :     children = find_all_inheritors(RelationGetRelid(child_rel),
 2314 rhaas                   15534 ECB             :                                    AccessShareLock, NULL);
                              15535                 : 
 2314 rhaas                   15536 CBC         128 :     if (list_member_oid(children, RelationGetRelid(parent_rel)))
 2314 rhaas                   15537 GIC           6 :         ereport(ERROR,
 2314 rhaas                   15538 ECB             :                 (errcode(ERRCODE_DUPLICATE_TABLE),
                              15539                 :                  errmsg("circular inheritance not allowed"),
                              15540                 :                  errdetail("\"%s\" is already a child of \"%s\".",
                              15541                 :                            parent->relname,
                              15542                 :                            RelationGetRelationName(child_rel))));
                              15543                 : 
                              15544                 :     /*
                              15545                 :      * If child_rel has row-level triggers with transition tables, we
                              15546                 :      * currently don't allow it to become an inheritance child.  See also
                              15547                 :      * prohibitions in ATExecAttachPartition() and CreateTrigger().
 2111 rhodiumtoad             15548                 :      */
 2111 rhodiumtoad             15549 GIC         122 :     trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
                              15550             122 :     if (trigger_name != NULL)
 2111 rhodiumtoad             15551 CBC           3 :         ereport(ERROR,
                              15552                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 2111 rhodiumtoad             15553 ECB             :                  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
 2111 rhodiumtoad             15554 EUB             :                         trigger_name, RelationGetRelationName(child_rel)),
                              15555                 :                  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
                              15556                 : 
                              15557                 :     /* OK to create inheritance */
 2314 rhaas                   15558 GIC         119 :     CreateInheritance(child_rel, parent_rel);
                              15559                 : 
                              15560              95 :     ObjectAddressSet(address, RelationRelationId,
                              15561                 :                      RelationGetRelid(parent_rel));
                              15562                 : 
                              15563                 :     /* keep our lock on the parent relation until commit */
 1539 andres                  15564              95 :     table_close(parent_rel, NoLock);
 2314 rhaas                   15565 ECB             : 
 2314 rhaas                   15566 CBC          95 :     return address;
 2314 rhaas                   15567 ECB             : }
                              15568                 : 
                              15569                 : /*
                              15570                 :  * CreateInheritance
                              15571                 :  *      Catalog manipulation portion of creating inheritance between a child
                              15572                 :  *      table and a parent table.
                              15573                 :  *
                              15574                 :  * Common to ATExecAddInherit() and ATExecAttachPartition().
                              15575                 :  */
                              15576                 : static void
 2314 rhaas                   15577 GIC        1087 : CreateInheritance(Relation child_rel, Relation parent_rel)
                              15578                 : {
 2314 rhaas                   15579 ECB             :     Relation    catalogRelation;
                              15580                 :     SysScanDesc scan;
                              15581                 :     ScanKeyData key;
                              15582                 :     HeapTuple   inheritsTuple;
                              15583                 :     int32       inhseqno;
                              15584                 : 
                              15585                 :     /* Note: get RowExclusiveLock because we will write pg_inherits below. */
 1539 andres                  15586 GIC        1087 :     catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
                              15587                 : 
 2314 rhaas                   15588 ECB             :     /*
                              15589                 :      * Check for duplicates in the list of parents, and determine the highest
                              15590                 :      * inhseqno already present; we'll use the next one for the new parent.
 2308                         15591                 :      * Also, if proposed child is a partition, it cannot already be
                              15592                 :      * inheriting.
 2314                         15593                 :      *
                              15594                 :      * Note: we do not reject the case where the child already inherits from
                              15595                 :      * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
                              15596                 :      */
 2314 rhaas                   15597 CBC        1087 :     ScanKeyInit(&key,
 2314 rhaas                   15598 EUB             :                 Anum_pg_inherits_inhrelid,
                              15599                 :                 BTEqualStrategyNumber, F_OIDEQ,
 6125 neilc                   15600 ECB             :                 ObjectIdGetDatum(RelationGetRelid(child_rel)));
 6125 bruce                   15601 GIC        1087 :     scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
                              15602                 :                               true, NULL, 1, &key);
                              15603                 : 
                              15604                 :     /* inhseqno sequences start at 1 */
      neilc                   15605            1087 :     inhseqno = 0;
 6125 bruce                   15606 GBC        1108 :     while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
 6125 bruce                   15607 EUB             :     {
 6125 bruce                   15608 GIC          24 :         Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
                              15609                 : 
      neilc                   15610              24 :         if (inh->inhparent == RelationGetRelid(parent_rel))
      bruce                   15611               3 :             ereport(ERROR,
 6125 bruce                   15612 ECB             :                     (errcode(ERRCODE_DUPLICATE_TABLE),
                              15613                 :                      errmsg("relation \"%s\" would be inherited from more than once",
                              15614                 :                             RelationGetRelationName(parent_rel))));
                              15615                 : 
 6022 tgl                     15616 CBC          21 :         if (inh->inhseqno > inhseqno)
 6125 bruce                   15617 GIC          21 :             inhseqno = inh->inhseqno;
                              15618                 :     }
                              15619            1084 :     systable_endscan(scan);
 6125 bruce                   15620 ECB             : 
                              15621                 :     /* Match up the columns and bump attinhcount as needed */
 6125 neilc                   15622 CBC        1084 :     MergeAttributesIntoExisting(child_rel, parent_rel);
 6125 bruce                   15623 ECB             : 
 5448 tgl                     15624                 :     /* Match up the constraints and bump coninhcount as needed */
 6125 neilc                   15625 GIC        1045 :     MergeConstraintsIntoExisting(child_rel, parent_rel);
 6125 bruce                   15626 ECB             : 
 6022 tgl                     15627                 :     /*
                              15628                 :      * OK, it looks valid.  Make the catalog entries that show inheritance.
                              15629                 :      */
 6125 neilc                   15630 GIC        1030 :     StoreCatalogInheritance1(RelationGetRelid(child_rel),
 6125 neilc                   15631 ECB             :                              RelationGetRelid(parent_rel),
                              15632                 :                              inhseqno + 1,
 2225 simon                   15633                 :                              catalogRelation,
 2225 simon                   15634 GIC        1030 :                              parent_rel->rd_rel->relkind ==
                              15635                 :                              RELKIND_PARTITIONED_TABLE);
 6022 tgl                     15636 ECB             : 
                              15637                 :     /* Now we're done with pg_inherits */
 1539 andres                  15638 CBC        1030 :     table_close(catalogRelation, RowExclusiveLock);
 6125 bruce                   15639 GIC        1030 : }
                              15640                 : 
                              15641                 : /*
 6022 tgl                     15642 ECB             :  * Obtain the source-text form of the constraint expression for a check
                              15643                 :  * constraint, given its pg_constraint tuple
                              15644                 :  */
                              15645                 : static char *
 6022 tgl                     15646 CBC          66 : decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
                              15647                 : {
                              15648                 :     Form_pg_constraint con;
 6022 tgl                     15649 ECB             :     bool        isnull;
                              15650                 :     Datum       attr;
                              15651                 :     Datum       expr;
                              15652                 : 
 6022 tgl                     15653 GIC          66 :     con = (Form_pg_constraint) GETSTRUCT(contup);
                              15654              66 :     attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
                              15655              66 :     if (isnull)
 1601 andres                  15656 UIC           0 :         elog(ERROR, "null conbin for constraint %u", con->oid);
 6022 tgl                     15657 ECB             : 
 6022 tgl                     15658 GIC          66 :     expr = DirectFunctionCall2(pg_get_expr, attr,
                              15659                 :                                ObjectIdGetDatum(con->conrelid));
 5493                         15660              66 :     return TextDatumGetCString(expr);
                              15661                 : }
                              15662                 : 
 5448 tgl                     15663 ECB             : /*
                              15664                 :  * Determine whether two check constraints are functionally equivalent
                              15665                 :  *
                              15666                 :  * The test we apply is to see whether they reverse-compile to the same
                              15667                 :  * source string.  This insulates us from issues like whether attributes
                              15668                 :  * have the same physical column numbers in parent and child relations.
                              15669                 :  */
                              15670                 : static bool
 5448 tgl                     15671 GIC          33 : constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
 5448 tgl                     15672 ECB             : {
 5448 tgl                     15673 GIC          33 :     Form_pg_constraint acon = (Form_pg_constraint) GETSTRUCT(a);
 5448 tgl                     15674 CBC          33 :     Form_pg_constraint bcon = (Form_pg_constraint) GETSTRUCT(b);
                              15675                 : 
                              15676              33 :     if (acon->condeferrable != bcon->condeferrable ||
                              15677              33 :         acon->condeferred != bcon->condeferred ||
 5448 tgl                     15678 GIC          33 :         strcmp(decompile_conbin(a, tupleDesc),
                              15679              33 :                decompile_conbin(b, tupleDesc)) != 0)
 5448 tgl                     15680 CBC           3 :         return false;
                              15681                 :     else
                              15682              30 :         return true;
                              15683                 : }
 5448 tgl                     15684 ECB             : 
                              15685                 : /*
 6022                         15686                 :  * Check columns in child table match up with columns in parent, and increment
                              15687                 :  * their attinhcount.
                              15688                 :  *
                              15689                 :  * Called by CreateInheritance
                              15690                 :  *
                              15691                 :  * Currently all parent columns must be found in child. Missing columns are an
                              15692                 :  * error.  One day we might consider creating new columns like CREATE TABLE
                              15693                 :  * does.  However, that is widely unpopular --- in the common use case of
                              15694                 :  * partitioned tables it's a foot-gun.
 6125 bruce                   15695                 :  *
                              15696                 :  * The data type must match exactly. If the parent column is NOT NULL then
                              15697                 :  * the child must be as well. Defaults are not compared, however.
                              15698                 :  */
                              15699                 : static void
 6125 neilc                   15700 CBC        1084 : MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
                              15701                 : {
                              15702                 :     Relation    attrrel;
 6031 bruce                   15703 ECB             :     AttrNumber  parent_attno;
                              15704                 :     int         parent_natts;
                              15705                 :     TupleDesc   tupleDesc;
                              15706                 :     HeapTuple   tuple;
 2314 rhaas                   15707 GIC        1084 :     bool        child_is_partition = false;
                              15708                 : 
 1539 andres                  15709 CBC        1084 :     attrrel = table_open(AttributeRelationId, RowExclusiveLock);
 6022 tgl                     15710 ECB             : 
 6125 neilc                   15711 GIC        1084 :     tupleDesc = RelationGetDescr(parent_rel);
                              15712            1084 :     parent_natts = tupleDesc->natts;
                              15713                 : 
                              15714                 :     /* If parent_rel is a partitioned table, child_rel must be a partition */
 2314 rhaas                   15715            1084 :     if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              15716             968 :         child_is_partition = true;
                              15717                 : 
 6125 neilc                   15718            3533 :     for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++)
                              15719                 :     {
 2058 andres                  15720            2488 :         Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
 2058 andres                  15721 ECB             :                                                     parent_attno - 1);
 6125 bruce                   15722 GIC        2488 :         char       *attributeName = NameStr(attribute->attname);
 6125 bruce                   15723 ECB             : 
                              15724                 :         /* Ignore dropped columns in the parent. */
 6125 bruce                   15725 CBC        2488 :         if (attribute->attisdropped)
 6125 bruce                   15726 GIC         148 :             continue;
 6125 bruce                   15727 ECB             : 
                              15728                 :         /* Find same column in child (matching on column name). */
 6125 neilc                   15729 GIC        2340 :         tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel),
 6125 neilc                   15730 ECB             :                                           attributeName);
 6125 bruce                   15731 GIC        2340 :         if (HeapTupleIsValid(tuple))
                              15732                 :         {
 4375 tgl                     15733 ECB             :             /* Check they are same type, typmod, and collation */
 6125 bruce                   15734 CBC        2334 :             Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
 6125 bruce                   15735 ECB             : 
 6125 bruce                   15736 CBC        2334 :             if (attribute->atttypid != childatt->atttypid ||
 6125 neilc                   15737 GIC        2331 :                 attribute->atttypmod != childatt->atttypmod)
      bruce                   15738               6 :                 ereport(ERROR,
 6125 bruce                   15739 ECB             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              15740                 :                          errmsg("child table \"%s\" has different type for column \"%s\"",
                              15741                 :                                 RelationGetRelationName(child_rel),
                              15742                 :                                 attributeName)));
                              15743                 : 
 4375 tgl                     15744 GIC        2328 :             if (attribute->attcollation != childatt->attcollation)
                              15745               3 :                 ereport(ERROR,
                              15746                 :                         (errcode(ERRCODE_COLLATION_MISMATCH),
                              15747                 :                          errmsg("child table \"%s\" has different collation for column \"%s\"",
                              15748                 :                                 RelationGetRelationName(child_rel),
                              15749                 :                                 attributeName)));
 4375 tgl                     15750 ECB             : 
                              15751                 :             /*
                              15752                 :              * Check child doesn't discard NOT NULL property.  (Other
                              15753                 :              * constraints are checked elsewhere.)
                              15754                 :              */
 6125 neilc                   15755 GIC        2325 :             if (attribute->attnotnull && !childatt->attnotnull)
 6125 neilc                   15756 CBC           6 :                 ereport(ERROR,
                              15757                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              15758                 :                          errmsg("column \"%s\" in child table must be marked NOT NULL",
 2118 tgl                     15759 ECB             :                                 attributeName)));
                              15760                 : 
  705 peter                   15761 EUB             :             /*
                              15762                 :              * Child column must be generated if and only if parent column is.
                              15763                 :              */
  705 peter                   15764 GBC        2319 :             if (attribute->attgenerated && !childatt->attgenerated)
  705 peter                   15765 GIC          12 :                 ereport(ERROR,
                              15766                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              15767                 :                          errmsg("column \"%s\" in child table must be a generated column",
  705 peter                   15768 ECB             :                                 attributeName)));
   88 tgl                     15769 GNC        2307 :             if (childatt->attgenerated && !attribute->attgenerated)
                              15770               6 :                 ereport(ERROR,
                              15771                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              15772                 :                          errmsg("column \"%s\" in child table must not be a generated column",
                              15773                 :                                 attributeName)));
                              15774                 : 
                              15775                 :             /*
                              15776                 :              * OK, bump the child column's inheritance count.  (If we fail
                              15777                 :              * later on, this change will just roll back.)
                              15778                 :              */
 6022 tgl                     15779 CBC        2301 :             childatt->attinhcount++;
   12 peter                   15780 GNC        2301 :             if (childatt->attinhcount < 0)
   12 peter                   15781 UNC           0 :                 ereport(ERROR,
                              15782                 :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                              15783                 :                         errmsg("too many inheritance parents"));
                              15784                 : 
                              15785                 :             /*
                              15786                 :              * In case of partitions, we must enforce that value of attislocal
 2314 rhaas                   15787 EUB             :              * is same in all partitions. (Note: there are only inherited
                              15788                 :              * attributes in partitions)
                              15789                 :              */
 2314 rhaas                   15790 GBC        2301 :             if (child_is_partition)
 2314 rhaas                   15791 EUB             :             {
 2314 rhaas                   15792 GIC        2067 :                 Assert(childatt->attinhcount == 1);
                              15793            2067 :                 childatt->attislocal = false;
                              15794                 :             }
                              15795                 : 
 2259 alvherre                15796            2301 :             CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
 6022 tgl                     15797            2301 :             heap_freetuple(tuple);
 6125 bruce                   15798 ECB             :         }
 6125 bruce                   15799 EUB             :         else
                              15800                 :         {
 6125 bruce                   15801 CBC           6 :             ereport(ERROR,
 6125 bruce                   15802 ECB             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              15803                 :                      errmsg("child table is missing column \"%s\"",
                              15804                 :                             attributeName)));
                              15805                 :         }
 6125 bruce                   15806 EUB             :     }
                              15807                 : 
 1539 andres                  15808 GIC        1045 :     table_close(attrrel, RowExclusiveLock);
 6125 bruce                   15809            1045 : }
                              15810                 : 
                              15811                 : /*
 5448 tgl                     15812 ECB             :  * Check constraints in child table match up with constraints in parent,
                              15813                 :  * and increment their coninhcount.
                              15814                 :  *
                              15815                 :  * Constraints that are marked ONLY in the parent are ignored.
                              15816                 :  *
 2314 rhaas                   15817                 :  * Called by CreateInheritance
 6125 bruce                   15818                 :  *
                              15819                 :  * Currently all constraints in parent must be present in the child. One day we
                              15820                 :  * may consider adding new constraints like CREATE TABLE does.
                              15821                 :  *
 6022 tgl                     15822                 :  * XXX This is O(N^2) which may be an issue with tables with hundreds of
                              15823                 :  * constraints. As long as tables have more like 10 constraints it shouldn't be
                              15824                 :  * a problem though. Even 100 constraints ought not be the end of the world.
                              15825                 :  *
                              15826                 :  * XXX See MergeWithExistingConstraint too if you change this code.
                              15827                 :  */
                              15828                 : static void
 6125 neilc                   15829 GIC        1045 : MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
                              15830                 : {
                              15831                 :     Relation    catalog_relation;
 5448 tgl                     15832 ECB             :     TupleDesc   tuple_desc;
                              15833                 :     SysScanDesc parent_scan;
                              15834                 :     ScanKeyData parent_key;
                              15835                 :     HeapTuple   parent_tuple;
    2 alvherre                15836 GNC        1045 :     Oid         parent_relid = RelationGetRelid(parent_rel);
 2314 rhaas                   15837 GBC        1045 :     bool        child_is_partition = false;
                              15838                 : 
 1539 andres                  15839 GIC        1045 :     catalog_relation = table_open(ConstraintRelationId, RowExclusiveLock);
 5448 tgl                     15840 CBC        1045 :     tuple_desc = RelationGetDescr(catalog_relation);
 6125 bruce                   15841 ECB             : 
 2314 rhaas                   15842                 :     /* If parent_rel is a partitioned table, child_rel must be a partition */
 2314 rhaas                   15843 CBC        1045 :     if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              15844             944 :         child_is_partition = true;
 2314 rhaas                   15845 ECB             : 
 5448 tgl                     15846                 :     /* Outer loop scans through the parent's constraint definitions */
 5448 tgl                     15847 CBC        1045 :     ScanKeyInit(&parent_key,
 6125 bruce                   15848 ECB             :                 Anum_pg_constraint_conrelid,
                              15849                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              15850                 :                 ObjectIdGetDatum(parent_relid));
 1678 tgl                     15851 CBC        1045 :     parent_scan = systable_beginscan(catalog_relation, ConstraintRelidTypidNameIndexId,
 3568 rhaas                   15852 EUB             :                                      true, NULL, 1, &parent_key);
                              15853                 : 
 5448 tgl                     15854 GIC        1549 :     while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
                              15855                 :     {
 5050 bruce                   15856             519 :         Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
                              15857                 :         SysScanDesc child_scan;
                              15858                 :         ScanKeyData child_key;
                              15859                 :         HeapTuple   child_tuple;
                              15860             519 :         bool        found = false;
 6125 bruce                   15861 ECB             : 
    2 alvherre                15862 GNC         519 :         if (parent_con->contype != CONSTRAINT_CHECK &&
                              15863             464 :             parent_con->contype != CONSTRAINT_NOTNULL)
 6125 bruce                   15864 GBC         284 :             continue;
                              15865                 : 
 4006 alvherre                15866 ECB             :         /* if the parent's constraint is marked NO INHERIT, it's not inherited */
 4006 alvherre                15867 GBC         245 :         if (parent_con->connoinherit)
 4101                         15868              10 :             continue;
                              15869                 : 
                              15870                 :         /* Search for a child constraint matching this one */
 5448 tgl                     15871 GIC         235 :         ScanKeyInit(&child_key,
                              15872                 :                     Anum_pg_constraint_conrelid,
                              15873                 :                     BTEqualStrategyNumber, F_OIDEQ,
 5448 tgl                     15874 ECB             :                     ObjectIdGetDatum(RelationGetRelid(child_rel)));
 1678 tgl                     15875 GIC         235 :         child_scan = systable_beginscan(catalog_relation, ConstraintRelidTypidNameIndexId,
                              15876                 :                                         true, NULL, 1, &child_key);
 6022 tgl                     15877 ECB             : 
 5448 tgl                     15878 GIC         432 :         while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
                              15879                 :         {
 5050 bruce                   15880 CBC         420 :             Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
 5050 bruce                   15881 ECB             :             HeapTuple   child_copy;
                              15882                 : 
    2 alvherre                15883 GNC         420 :             if (child_con->contype != parent_con->contype)
 5448 tgl                     15884 CBC         105 :                 continue;
                              15885                 : 
                              15886                 :             /*
                              15887                 :              * CHECK constraint are matched by name, NOT NULL ones by
                              15888                 :              * attribute number
                              15889                 :              */
    2 alvherre                15890 GNC         315 :             if (child_con->contype == CONSTRAINT_CHECK &&
                              15891              48 :                 strcmp(NameStr(parent_con->conname),
 5448 tgl                     15892 GIC          48 :                        NameStr(child_con->conname)) != 0)
                              15893              15 :                 continue;
    2 alvherre                15894 GNC         300 :             else if (child_con->contype == CONSTRAINT_NOTNULL)
                              15895                 :             {
                              15896             267 :                 AttrNumber  parent_attno = extractNotNullColumn(parent_tuple);
                              15897             267 :                 AttrNumber  child_attno = extractNotNullColumn(child_tuple);
                              15898                 : 
                              15899             267 :                 if (strcmp(get_attname(parent_relid, parent_attno, false),
                              15900             267 :                            get_attname(RelationGetRelid(child_rel), child_attno,
                              15901                 :                                        false)) != 0)
                              15902              77 :                     continue;
                              15903                 :             }
                              15904                 : 
                              15905             223 :             if (child_con->contype == CONSTRAINT_CHECK &&
                              15906              33 :                 !constraints_equivalent(parent_tuple, child_tuple, tuple_desc))
 5448 tgl                     15907 CBC           3 :                 ereport(ERROR,
                              15908                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
 5448 tgl                     15909 ECB             :                          errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
                              15910                 :                                 RelationGetRelationName(child_rel),
                              15911                 :                                 NameStr(parent_con->conname))));
 6125 bruce                   15912                 : 
 2374 tgl                     15913                 :             /* If the child constraint is "no inherit" then cannot merge */
 4006 alvherre                15914 GIC         220 :             if (child_con->connoinherit)
 4101 alvherre                15915 LBC           0 :                 ereport(ERROR,
                              15916                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 4101 alvherre                15917 ECB             :                          errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
                              15918                 :                                 NameStr(child_con->conname),
                              15919                 :                                 RelationGetRelationName(child_rel))));
                              15920                 : 
                              15921                 :             /*
                              15922                 :              * If the child constraint is "not valid" then cannot merge with a
 2374 tgl                     15923                 :              * valid parent constraint
                              15924                 :              */
 2374 tgl                     15925 GIC         220 :             if (parent_con->convalidated && !child_con->convalidated)
 2374 tgl                     15926 UIC           0 :                 ereport(ERROR,
 2374 tgl                     15927 ECB             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              15928                 :                          errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
                              15929                 :                                 NameStr(child_con->conname),
                              15930                 :                                 RelationGetRelationName(child_rel))));
                              15931                 : 
                              15932                 :             /*
                              15933                 :              * OK, bump the child constraint's inheritance count.  (If we fail
                              15934                 :              * later on, this change will just roll back.)
                              15935                 :              */
 5448 tgl                     15936 GIC         220 :             child_copy = heap_copytuple(child_tuple);
                              15937             220 :             child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
                              15938             220 :             child_con->coninhcount++;
   12 peter                   15939 GNC         220 :             if (child_con->coninhcount < 0)
   12 peter                   15940 UNC           0 :                 ereport(ERROR,
                              15941                 :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                              15942                 :                         errmsg("too many inheritance parents"));
 2314 rhaas                   15943 ECB             : 
                              15944                 :             /*
                              15945                 :              * In case of partitions, an inherited constraint must be
                              15946                 :              * inherited only once since it cannot have multiple parents and
                              15947                 :              * it is never considered local.
                              15948                 :              */
 2314 rhaas                   15949 GIC         220 :             if (child_is_partition)
                              15950                 :             {
                              15951             187 :                 Assert(child_con->coninhcount == 1);
 2314 rhaas                   15952 CBC         187 :                 child_con->conislocal = false;
                              15953                 :             }
                              15954                 : 
 2259 alvherre                15955             220 :             CatalogTupleUpdate(catalog_relation, &child_copy->t_self, child_copy);
 5448 tgl                     15956             220 :             heap_freetuple(child_copy);
                              15957                 : 
 5448 tgl                     15958 GIC         220 :             found = true;
 5448 tgl                     15959 CBC         220 :             break;
 6125 bruce                   15960 ECB             :         }
                              15961                 : 
 5448 tgl                     15962 CBC         232 :         systable_endscan(child_scan);
                              15963                 : 
 6125 bruce                   15964 GBC         232 :         if (!found)
 6125 bruce                   15965 GIC          12 :             ereport(ERROR,
                              15966                 :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              15967                 :                      errmsg("child table is missing constraint \"%s\"",
                              15968                 :                             NameStr(parent_con->conname))));
                              15969                 :     }
 6125 neilc                   15970 EUB             : 
 5448 tgl                     15971 GBC        1030 :     systable_endscan(parent_scan);
 1539 andres                  15972 GIC        1030 :     table_close(catalog_relation, RowExclusiveLock);
 6125 bruce                   15973 GBC        1030 : }
 6125 bruce                   15974 EUB             : 
      neilc                   15975                 : /*
                              15976                 :  * ALTER TABLE NO INHERIT
                              15977                 :  *
                              15978                 :  * Return value is the address of the relation that is no longer parent.
                              15979                 :  */
 2314 rhaas                   15980 ECB             : static ObjectAddress
 2314 rhaas                   15981 CBC          22 : ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 2314 rhaas                   15982 ECB             : {
                              15983                 :     ObjectAddress address;
                              15984                 :     Relation    parent_rel;
                              15985                 : 
 2314 rhaas                   15986 GIC          22 :     if (rel->rd_rel->relispartition)
 2314 rhaas                   15987 UIC           0 :         ereport(ERROR,
                              15988                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15989                 :                  errmsg("cannot change inheritance of a partition")));
 2314 rhaas                   15990 ECB             : 
                              15991                 :     /*
                              15992                 :      * AccessShareLock on the parent is probably enough, seeing that DROP
                              15993                 :      * TABLE doesn't lock parent tables at all.  We need some lock since we'll
                              15994                 :      * be inspecting the parent's schema.
                              15995                 :      */
 1539 andres                  15996 GIC          22 :     parent_rel = table_openrv(parent, AccessShareLock);
 2314 rhaas                   15997 ECB             : 
                              15998                 :     /*
                              15999                 :      * We don't bother to check ownership of the parent table --- ownership of
                              16000                 :      * the child is presumed enough rights.
                              16001                 :      */
                              16002                 : 
                              16003                 :     /* Off to RemoveInheritance() where most of the work happens */
  745 alvherre                16004 GIC          22 :     RemoveInheritance(rel, parent_rel, false);
 2314 rhaas                   16005 ECB             : 
 2314 rhaas                   16006 GIC          19 :     ObjectAddressSet(address, RelationRelationId,
                              16007                 :                      RelationGetRelid(parent_rel));
 2314 rhaas                   16008 ECB             : 
 1763 tgl                     16009                 :     /* keep our lock on the parent relation until commit */
 1539 andres                  16010 GIC          19 :     table_close(parent_rel, NoLock);
                              16011                 : 
 2314 rhaas                   16012              19 :     return address;
                              16013                 : }
                              16014                 : 
                              16015                 : /*
                              16016                 :  * MarkInheritDetached
                              16017                 :  *
                              16018                 :  * Set inhdetachpending for a partition, for ATExecDetachPartition
  711 alvherre                16019 ECB             :  * in concurrent mode.  While at it, verify that no other partition is
                              16020                 :  * already pending detach.
  745                         16021                 :  */
                              16022                 : static void
  745 alvherre                16023 GIC          73 : MarkInheritDetached(Relation child_rel, Relation parent_rel)
                              16024                 : {
                              16025                 :     Relation    catalogRelation;
  697 tgl                     16026 ECB             :     SysScanDesc scan;
  745 alvherre                16027                 :     ScanKeyData key;
                              16028                 :     HeapTuple   inheritsTuple;
  745 alvherre                16029 GIC          73 :     bool        found = false;
                              16030                 : 
  745 alvherre                16031 CBC          73 :     Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
  745 alvherre                16032 ECB             : 
                              16033                 :     /*
                              16034                 :      * Find pg_inherits entries by inhparent.  (We need to scan them all in
  711                         16035                 :      * order to verify that no other partition is pending detach.)
                              16036                 :      */
  745 alvherre                16037 GIC          73 :     catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
                              16038              73 :     ScanKeyInit(&key,
                              16039                 :                 Anum_pg_inherits_inhparent,
                              16040                 :                 BTEqualStrategyNumber, F_OIDEQ,
  711 alvherre                16041 ECB             :                 ObjectIdGetDatum(RelationGetRelid(parent_rel)));
  711 alvherre                16042 GIC          73 :     scan = systable_beginscan(catalogRelation, InheritsParentIndexId,
                              16043                 :                               true, NULL, 1, &key);
                              16044                 : 
  745                         16045             288 :     while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
                              16046                 :     {
                              16047                 :         Form_pg_inherits inhForm;
                              16048                 : 
  711                         16049             143 :         inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
                              16050             143 :         if (inhForm->inhdetachpending)
                              16051               1 :             ereport(ERROR,
  711 alvherre                16052 ECB             :                     errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              16053                 :                     errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"",
                              16054                 :                            get_rel_name(inhForm->inhrelid),
                              16055                 :                            get_namespace_name(parent_rel->rd_rel->relnamespace),
                              16056                 :                            RelationGetRelationName(parent_rel)),
                              16057                 :                     errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
  745                         16058                 : 
  711 alvherre                16059 GIC         142 :         if (inhForm->inhrelid == RelationGetRelid(child_rel))
                              16060                 :         {
  711 alvherre                16061 ECB             :             HeapTuple   newtup;
  745                         16062                 : 
  711 alvherre                16063 GBC          72 :             newtup = heap_copytuple(inheritsTuple);
  711 alvherre                16064 GIC          72 :             ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
                              16065                 : 
                              16066              72 :             CatalogTupleUpdate(catalogRelation,
                              16067                 :                                &inheritsTuple->t_self,
                              16068                 :                                newtup);
  711 alvherre                16069 CBC          72 :             found = true;
                              16070              72 :             heap_freetuple(newtup);
  711 alvherre                16071 EUB             :             /* keep looking, to ensure we catch others pending detach */
                              16072                 :         }
                              16073                 :     }
                              16074                 : 
                              16075                 :     /* Done */
  745 alvherre                16076 CBC          72 :     systable_endscan(scan);
                              16077              72 :     table_close(catalogRelation, RowExclusiveLock);
  745 alvherre                16078 EUB             : 
  745 alvherre                16079 GIC          72 :     if (!found)
  745 alvherre                16080 UIC           0 :         ereport(ERROR,
                              16081                 :                 (errcode(ERRCODE_UNDEFINED_TABLE),
                              16082                 :                  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
  745 alvherre                16083 ECB             :                         RelationGetRelationName(child_rel),
                              16084                 :                         RelationGetRelationName(parent_rel))));
  745 alvherre                16085 GIC          72 : }
                              16086                 : 
                              16087                 : /*
                              16088                 :  * RemoveInheritance
                              16089                 :  *
 6125 neilc                   16090 ECB             :  * Drop a parent from the child's parents. This just adjusts the attinhcount
      bruce                   16091                 :  * and attislocal of the columns and removes the pg_inherit and pg_depend
                              16092                 :  * entries.  expect_detached is passed down to DeleteInheritsTuple, q.v..
                              16093                 :  *
                              16094                 :  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
                              16095                 :  * up attislocal stays true, which means if a child is ever removed from a
                              16096                 :  * parent then its columns will never be automatically dropped which may
                              16097                 :  * surprise. But at least we'll never surprise by dropping columns someone
                              16098                 :  * isn't expecting to be dropped which would actually mean data loss.
                              16099                 :  *
                              16100                 :  * coninhcount and conislocal for inherited constraints are adjusted in
                              16101                 :  * exactly the same way.
                              16102                 :  *
                              16103                 :  * Common to ATExecDropInherit() and ATExecDetachPartition().
                              16104                 :  */
                              16105                 : static void
  745 alvherre                16106 GIC         241 : RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
                              16107                 : {
                              16108                 :     Relation    catalogRelation;
 6125 bruce                   16109 ECB             :     SysScanDesc scan;
                              16110                 :     ScanKeyData key[3];
                              16111                 :     HeapTuple   attributeTuple,
 4372 rhaas                   16112                 :                 constraintTuple;
 5448 tgl                     16113                 :     List       *connames;
                              16114                 :     List       *nncolumns;
                              16115                 :     bool        found;
 2314 rhaas                   16116 GIC         241 :     bool        child_is_partition = false;
                              16117                 : 
                              16118                 :     /* If parent_rel is a partitioned table, child_rel must be a partition */
                              16119             241 :     if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              16120             219 :         child_is_partition = true;
                              16121                 : 
 1906 alvherre                16122             241 :     found = DeleteInheritsTuple(RelationGetRelid(child_rel),
                              16123                 :                                 RelationGetRelid(parent_rel),
                              16124                 :                                 expect_detached,
  745                         16125             241 :                                 RelationGetRelationName(child_rel));
 6125 bruce                   16126 CBC         241 :     if (!found)
 2314 rhaas                   16127 ECB             :     {
 2314 rhaas                   16128 CBC          12 :         if (child_is_partition)
 2314 rhaas                   16129 GIC           9 :             ereport(ERROR,
                              16130                 :                     (errcode(ERRCODE_UNDEFINED_TABLE),
                              16131                 :                      errmsg("relation \"%s\" is not a partition of relation \"%s\"",
                              16132                 :                             RelationGetRelationName(child_rel),
                              16133                 :                             RelationGetRelationName(parent_rel))));
                              16134                 :         else
 2314 rhaas                   16135 CBC           3 :             ereport(ERROR,
                              16136                 :                     (errcode(ERRCODE_UNDEFINED_TABLE),
 2118 tgl                     16137 ECB             :                      errmsg("relation \"%s\" is not a parent of relation \"%s\"",
                              16138                 :                             RelationGetRelationName(parent_rel),
                              16139                 :                             RelationGetRelationName(child_rel))));
                              16140                 :     }
 6125 bruce                   16141                 : 
                              16142                 :     /*
 6022 tgl                     16143                 :      * Search through child columns looking for ones matching parent rel
                              16144                 :      */
 1539 andres                  16145 GIC         229 :     catalogRelation = table_open(AttributeRelationId, RowExclusiveLock);
 6022 tgl                     16146             229 :     ScanKeyInit(&key[0],
                              16147                 :                 Anum_pg_attribute_attrelid,
                              16148                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              16149                 :                 ObjectIdGetDatum(RelationGetRelid(child_rel)));
 6125 bruce                   16150             229 :     scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
                              16151                 :                               true, NULL, 1, key);
                              16152            2011 :     while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
                              16153                 :     {
 6125 neilc                   16154 CBC        1782 :         Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
                              16155                 : 
                              16156                 :         /* Ignore if dropped or not inherited */
 6125 bruce                   16157 GIC        1782 :         if (att->attisdropped)
 6125 bruce                   16158 UIC           0 :             continue;
 6022 tgl                     16159 GIC        1782 :         if (att->attinhcount <= 0)
                              16160            1383 :             continue;
                              16161                 : 
                              16162             399 :         if (SearchSysCacheExistsAttName(RelationGetRelid(parent_rel),
 6022 tgl                     16163 CBC         399 :                                         NameStr(att->attname)))
                              16164                 :         {
                              16165                 :             /* Decrement inhcount and possibly set islocal to true */
 6125 bruce                   16166 GIC         393 :             HeapTuple   copyTuple = heap_copytuple(attributeTuple);
      neilc                   16167             393 :             Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
                              16168                 : 
      bruce                   16169             393 :             copy_att->attinhcount--;
                              16170             393 :             if (copy_att->attinhcount == 0)
                              16171             393 :                 copy_att->attislocal = true;
                              16172                 : 
 2259 alvherre                16173             393 :             CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
 6125 bruce                   16174 CBC         393 :             heap_freetuple(copyTuple);
                              16175                 :         }
                              16176                 :     }
 6125 bruce                   16177 GIC         229 :     systable_endscan(scan);
 1539 andres                  16178 CBC         229 :     table_close(catalogRelation, RowExclusiveLock);
                              16179                 : 
                              16180                 :     /*
                              16181                 :      * Likewise, find inherited check constraints and disinherit them. To do
 5050 bruce                   16182 ECB             :      * this, we first need a list of the names of the parent's check
 5448 tgl                     16183                 :      * constraints.  (We cheat a bit by only checking for name matches,
                              16184                 :      * assuming that the expressions will match.)
                              16185                 :      *
                              16186                 :      * For NOT NULL columns, we store column numbers to match.
                              16187                 :      */
 1539 andres                  16188 GIC         229 :     catalogRelation = table_open(ConstraintRelationId, RowExclusiveLock);
 5448 tgl                     16189 CBC         229 :     ScanKeyInit(&key[0],
 5448 tgl                     16190 ECB             :                 Anum_pg_constraint_conrelid,
                              16191                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              16192                 :                 ObjectIdGetDatum(RelationGetRelid(parent_rel)));
 1678 tgl                     16193 GIC         229 :     scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
                              16194                 :                               true, NULL, 1, key);
 5448 tgl                     16195 ECB             : 
 5448 tgl                     16196 CBC         229 :     connames = NIL;
    2 alvherre                16197 GNC         229 :     nncolumns = NIL;
                              16198                 : 
 5448 tgl                     16199 CBC         330 :     while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
                              16200                 :     {
 5448 tgl                     16201 GIC         101 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
 5448 tgl                     16202 ECB             : 
 5448 tgl                     16203 GIC         101 :         if (con->contype == CONSTRAINT_CHECK)
                              16204               6 :             connames = lappend(connames, pstrdup(NameStr(con->conname)));
    2 alvherre                16205 GNC         101 :         if (con->contype == CONSTRAINT_NOTNULL)
                              16206              19 :             nncolumns = lappend_int(nncolumns, extractNotNullColumn(constraintTuple));
 5448 tgl                     16207 ECB             :     }
                              16208                 : 
 5448 tgl                     16209 GIC         229 :     systable_endscan(scan);
                              16210                 : 
                              16211                 :     /* Now scan the child's constraints */
 5448 tgl                     16212 CBC         229 :     ScanKeyInit(&key[0],
                              16213                 :                 Anum_pg_constraint_conrelid,
                              16214                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              16215                 :                 ObjectIdGetDatum(RelationGetRelid(child_rel)));
 1678                         16216             229 :     scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
                              16217                 :                               true, NULL, 1, key);
                              16218                 : 
 5448 tgl                     16219 GIC         428 :     while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
 5448 tgl                     16220 ECB             :     {
 5448 tgl                     16221 CBC         199 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
    2 alvherre                16222 GNC         199 :         bool        match = false;
                              16223                 :         ListCell   *lc;
                              16224                 : 
                              16225                 :         /*
                              16226                 :          * Match CHECK constraints by name, NOT NULL constraints by column
                              16227                 :          * number, and ignore all others.
                              16228                 :          */
                              16229             199 :         if (con->contype == CONSTRAINT_CHECK)
                              16230                 :         {
                              16231              92 :             foreach(lc, connames)
                              16232                 :             {
                              16233              12 :                 if (con->contype == CONSTRAINT_CHECK &&
                              16234              12 :                     strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
                              16235                 :                 {
                              16236               6 :                     match = true;
                              16237               6 :                     break;
                              16238                 :                 }
 5448 tgl                     16239 ECB             :             }
                              16240                 :         }
    2 alvherre                16241 GNC         113 :         else if (con->contype == CONSTRAINT_NOTNULL)
                              16242                 :         {
                              16243              28 :             AttrNumber  child_attno = extractNotNullColumn(constraintTuple);
                              16244                 : 
                              16245              40 :             foreach(lc, nncolumns)
                              16246                 :             {
                              16247              31 :                 if (lfirst_int(lc) == child_attno)
                              16248                 :                 {
                              16249              19 :                     match = true;
                              16250              19 :                     break;
                              16251                 :                 }
                              16252                 :             }
                              16253                 :         }
                              16254                 :         else
                              16255              85 :             continue;
 5448 tgl                     16256 ECB             : 
 5448 tgl                     16257 GBC         114 :         if (match)
                              16258                 :         {
 5448 tgl                     16259 ECB             :             /* Decrement inhcount and possibly set islocal to true */
 5448 tgl                     16260 GIC          25 :             HeapTuple   copyTuple = heap_copytuple(constraintTuple);
 5448 tgl                     16261 CBC          25 :             Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
                              16262                 : 
 2118 tgl                     16263 GIC          25 :             if (copy_con->coninhcount <= 0) /* shouldn't happen */
 5448 tgl                     16264 UIC           0 :                 elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
                              16265                 :                      RelationGetRelid(child_rel), NameStr(copy_con->conname));
                              16266                 : 
 5448 tgl                     16267 GIC          25 :             copy_con->coninhcount--;
                              16268              25 :             if (copy_con->coninhcount == 0)
                              16269              25 :                 copy_con->conislocal = true;
                              16270                 : 
 2259 alvherre                16271              25 :             CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
 5448 tgl                     16272 CBC          25 :             heap_freetuple(copyTuple);
                              16273                 :         }
 5448 tgl                     16274 ECB             :     }
                              16275                 : 
 5448 tgl                     16276 GIC         229 :     systable_endscan(scan);
 1539 andres                  16277 CBC         229 :     table_close(catalogRelation, RowExclusiveLock);
 5448 tgl                     16278 ECB             : 
 2314 rhaas                   16279 CBC         229 :     drop_parent_dependency(RelationGetRelid(child_rel),
 4372 rhaas                   16280 ECB             :                            RelationRelationId,
 2126                         16281                 :                            RelationGetRelid(parent_rel),
                              16282                 :                            child_dependency_type(child_is_partition));
 2308                         16283                 : 
                              16284                 :     /*
                              16285                 :      * Post alter hook of this inherits. Since object_access_hook doesn't take
                              16286                 :      * multiple object identifiers, we relay oid of parent relation using
                              16287                 :      * auxiliary_id argument.
                              16288                 :      */
 3675 rhaas                   16289 GIC         229 :     InvokeObjectPostAlterHookArg(InheritsRelationId,
                              16290                 :                                  RelationGetRelid(child_rel), 0,
                              16291                 :                                  RelationGetRelid(parent_rel), false);
 4372                         16292             229 : }
                              16293                 : 
                              16294                 : /*
                              16295                 :  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
                              16296                 :  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
                              16297                 :  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
                              16298                 :  * be TypeRelationId).  There's no convenient way to do this, so go trawling
                              16299                 :  * through pg_depend.
                              16300                 :  */
 4372 rhaas                   16301 ECB             : static void
 2126 rhaas                   16302 GIC         235 : drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
                              16303                 :                        DependencyType deptype)
                              16304                 : {
                              16305                 :     Relation    catalogRelation;
                              16306                 :     SysScanDesc scan;
                              16307                 :     ScanKeyData key[3];
 4372 rhaas                   16308 ECB             :     HeapTuple   depTuple;
                              16309                 : 
 1539 andres                  16310 CBC         235 :     catalogRelation = table_open(DependRelationId, RowExclusiveLock);
                              16311                 : 
 6125 bruce                   16312             235 :     ScanKeyInit(&key[0],
 6125 bruce                   16313 ECB             :                 Anum_pg_depend_classid,
                              16314                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              16315                 :                 ObjectIdGetDatum(RelationRelationId));
 6125 bruce                   16316 CBC         235 :     ScanKeyInit(&key[1],
 6125 bruce                   16317 ECB             :                 Anum_pg_depend_objid,
                              16318                 :                 BTEqualStrategyNumber, F_OIDEQ,
 4372 rhaas                   16319                 :                 ObjectIdGetDatum(relid));
 6022 tgl                     16320 GIC         235 :     ScanKeyInit(&key[2],
 6022 tgl                     16321 ECB             :                 Anum_pg_depend_objsubid,
                              16322                 :                 BTEqualStrategyNumber, F_INT4EQ,
                              16323                 :                 Int32GetDatum(0));
                              16324                 : 
 6125 bruce                   16325 GIC         235 :     scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
 3568 rhaas                   16326 ECB             :                               NULL, 3, key);
 6125 bruce                   16327                 : 
 6125 bruce                   16328 GIC         720 :     while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
                              16329                 :     {
 6125 bruce                   16330 CBC         485 :         Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
                              16331                 : 
 4372 rhaas                   16332             485 :         if (dep->refclassid == refclassid &&
 4372 rhaas                   16333 GIC         241 :             dep->refobjid == refobjid &&
 6022 tgl                     16334             235 :             dep->refobjsubid == 0 &&
 2126 rhaas                   16335 CBC         235 :             dep->deptype == deptype)
 2258 tgl                     16336 GIC         235 :             CatalogTupleDelete(catalogRelation, &depTuple->t_self);
 6125 bruce                   16337 ECB             :     }
                              16338                 : 
 6125 neilc                   16339 CBC         235 :     systable_endscan(scan);
 1539 andres                  16340 GIC         235 :     table_close(catalogRelation, RowExclusiveLock);
 4372 rhaas                   16341             235 : }
                              16342                 : 
                              16343                 : /*
                              16344                 :  * ALTER TABLE OF
 4372 rhaas                   16345 ECB             :  *
                              16346                 :  * Attach a table to a composite type, as though it had been created with CREATE
                              16347                 :  * TABLE OF.  All attname, atttypid, atttypmod and attcollation must match.  The
                              16348                 :  * subject table must not have inheritance parents.  These restrictions ensure
                              16349                 :  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
                              16350                 :  *
                              16351                 :  * The address of the type is returned.
                              16352                 :  */
                              16353                 : static ObjectAddress
 4372 rhaas                   16354 GIC          33 : ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
                              16355                 : {
 4372 rhaas                   16356 CBC          33 :     Oid         relid = RelationGetRelid(rel);
 4372 rhaas                   16357 ECB             :     Type        typetuple;
                              16358                 :     Form_pg_type typeform;
                              16359                 :     Oid         typeid;
                              16360                 :     Relation    inheritsRelation,
                              16361                 :                 relationRelation;
                              16362                 :     SysScanDesc scan;
                              16363                 :     ScanKeyData key;
                              16364                 :     AttrNumber  table_attno,
                              16365                 :                 type_attno;
                              16366                 :     TupleDesc   typeTupleDesc,
                              16367                 :                 tableTupleDesc;
                              16368                 :     ObjectAddress tableobj,
                              16369                 :                 typeobj;
                              16370                 :     HeapTuple   classtuple;
                              16371                 : 
                              16372                 :     /* Validate the type. */
 4372 rhaas                   16373 GIC          33 :     typetuple = typenameType(NULL, ofTypename, NULL);
                              16374              33 :     check_of_type(typetuple);
 1601 andres                  16375              33 :     typeform = (Form_pg_type) GETSTRUCT(typetuple);
                              16376              33 :     typeid = typeform->oid;
                              16377                 : 
                              16378                 :     /* Fail if the table has any inheritance parents. */
 1539                         16379              33 :     inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
 4372 rhaas                   16380 CBC          33 :     ScanKeyInit(&key,
 4372 rhaas                   16381 ECB             :                 Anum_pg_inherits_inhrelid,
 4372 rhaas                   16382 EUB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              16383                 :                 ObjectIdGetDatum(relid));
 4372 rhaas                   16384 GIC          33 :     scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
                              16385                 :                               true, NULL, 1, &key);
                              16386              33 :     if (HeapTupleIsValid(systable_getnext(scan)))
                              16387               3 :         ereport(ERROR,
                              16388                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16389                 :                  errmsg("typed tables cannot inherit")));
                              16390              30 :     systable_endscan(scan);
 1539 andres                  16391 CBC          30 :     table_close(inheritsRelation, AccessShareLock);
                              16392                 : 
 4372 rhaas                   16393 ECB             :     /*
                              16394                 :      * Check the tuple descriptors for compatibility.  Unlike inheritance, we
                              16395                 :      * require that the order also match.  However, attnotnull need not match.
                              16396                 :      */
 4372 rhaas                   16397 CBC          30 :     typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
                              16398              30 :     tableTupleDesc = RelationGetDescr(rel);
 4372 rhaas                   16399 GIC          30 :     table_attno = 1;
                              16400              95 :     for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
                              16401                 :     {
 4372 rhaas                   16402 ECB             :         Form_pg_attribute type_attr,
                              16403                 :                     table_attr;
                              16404                 :         const char *type_attname,
                              16405                 :                    *table_attname;
                              16406                 : 
                              16407                 :         /* Get the next non-dropped type attribute. */
 2058 andres                  16408 GIC          77 :         type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
 4372 rhaas                   16409 CBC          77 :         if (type_attr->attisdropped)
                              16410              22 :             continue;
 4372 rhaas                   16411 GIC          55 :         type_attname = NameStr(type_attr->attname);
                              16412                 : 
                              16413                 :         /* Get the next non-dropped table attribute. */
                              16414                 :         do
                              16415                 :         {
                              16416              61 :             if (table_attno > tableTupleDesc->natts)
                              16417               3 :                 ereport(ERROR,
                              16418                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16419                 :                          errmsg("table is missing column \"%s\"",
                              16420                 :                                 type_attname)));
 2058 andres                  16421              58 :             table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
                              16422              58 :             table_attno++;
 4372 rhaas                   16423              58 :         } while (table_attr->attisdropped);
                              16424              52 :         table_attname = NameStr(table_attr->attname);
                              16425                 : 
                              16426                 :         /* Compare name. */
                              16427              52 :         if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
                              16428               3 :             ereport(ERROR,
                              16429                 :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
 2118 tgl                     16430 ECB             :                      errmsg("table has column \"%s\" where type requires \"%s\"",
                              16431                 :                             table_attname, type_attname)));
                              16432                 : 
                              16433                 :         /* Compare type. */
 4372 rhaas                   16434 GIC          49 :         if (table_attr->atttypid != type_attr->atttypid ||
                              16435              46 :             table_attr->atttypmod != type_attr->atttypmod ||
                              16436              43 :             table_attr->attcollation != type_attr->attcollation)
 4372 rhaas                   16437 CBC           6 :             ereport(ERROR,
 4372 rhaas                   16438 ECB             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16439                 :                      errmsg("table \"%s\" has different type for column \"%s\"",
 2118 tgl                     16440                 :                             RelationGetRelationName(rel), type_attname)));
 4372 rhaas                   16441                 :     }
  480 tgl                     16442 GIC          18 :     ReleaseTupleDesc(typeTupleDesc);
                              16443                 : 
 4372 rhaas                   16444 ECB             :     /* Any remaining columns at the end of the table had better be dropped. */
 4372 rhaas                   16445 CBC          18 :     for (; table_attno <= tableTupleDesc->natts; table_attno++)
                              16446                 :     {
 2058 andres                  16447 GIC           3 :         Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
 2058 andres                  16448 ECB             :                                                      table_attno - 1);
                              16449                 : 
 4372 rhaas                   16450 GIC           3 :         if (!table_attr->attisdropped)
                              16451               3 :             ereport(ERROR,
 4372 rhaas                   16452 ECB             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16453                 :                      errmsg("table has extra column \"%s\"",
                              16454                 :                             NameStr(table_attr->attname))));
                              16455                 :     }
                              16456                 : 
                              16457                 :     /* If the table was already typed, drop the existing dependency. */
 4372 rhaas                   16458 GIC          15 :     if (rel->rd_rel->reloftype)
 2126                         16459               3 :         drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
                              16460                 :                                DEPENDENCY_NORMAL);
 4372 rhaas                   16461 ECB             : 
                              16462                 :     /* Record a dependency on the new type. */
 4372 rhaas                   16463 CBC          15 :     tableobj.classId = RelationRelationId;
                              16464              15 :     tableobj.objectId = relid;
                              16465              15 :     tableobj.objectSubId = 0;
 4372 rhaas                   16466 GIC          15 :     typeobj.classId = TypeRelationId;
                              16467              15 :     typeobj.objectId = typeid;
 4372 rhaas                   16468 CBC          15 :     typeobj.objectSubId = 0;
                              16469              15 :     recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
                              16470                 : 
                              16471                 :     /* Update pg_class.reloftype */
 1539 andres                  16472              15 :     relationRelation = table_open(RelationRelationId, RowExclusiveLock);
 4372 rhaas                   16473 GIC          15 :     classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
                              16474              15 :     if (!HeapTupleIsValid(classtuple))
 4372 rhaas                   16475 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
 4372 rhaas                   16476 CBC          15 :     ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
 2259 alvherre                16477 GIC          15 :     CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
                              16478                 : 
 3675 rhaas                   16479 CBC          15 :     InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
                              16480                 : 
 4372                         16481              15 :     heap_freetuple(classtuple);
 1539 andres                  16482 GIC          15 :     table_close(relationRelation, RowExclusiveLock);
                              16483                 : 
 4372 rhaas                   16484 CBC          15 :     ReleaseSysCache(typetuple);
 2937 alvherre                16485 ECB             : 
 2937 alvherre                16486 GIC          15 :     return typeobj;
                              16487                 : }
                              16488                 : 
                              16489                 : /*
                              16490                 :  * ALTER TABLE NOT OF
 4372 rhaas                   16491 ECB             :  *
 3260 bruce                   16492                 :  * Detach a typed table from its originating type.  Just clear reloftype and
 4372 rhaas                   16493                 :  * remove the dependency.
                              16494                 :  */
                              16495                 : static void
 4372 rhaas                   16496 GIC           3 : ATExecDropOf(Relation rel, LOCKMODE lockmode)
 4372 rhaas                   16497 ECB             : {
 4372 rhaas                   16498 CBC           3 :     Oid         relid = RelationGetRelid(rel);
                              16499                 :     Relation    relationRelation;
 4372 rhaas                   16500 ECB             :     HeapTuple   tuple;
                              16501                 : 
 4372 rhaas                   16502 GIC           3 :     if (!OidIsValid(rel->rd_rel->reloftype))
 4372 rhaas                   16503 LBC           0 :         ereport(ERROR,
                              16504                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16505                 :                  errmsg("\"%s\" is not a typed table",
 4372 rhaas                   16506 ECB             :                         RelationGetRelationName(rel))));
                              16507                 : 
                              16508                 :     /*
                              16509                 :      * We don't bother to check ownership of the type --- ownership of the
                              16510                 :      * table is presumed enough rights.  No lock required on the type, either.
                              16511                 :      */
                              16512                 : 
 2126 rhaas                   16513 GIC           3 :     drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
                              16514                 :                            DEPENDENCY_NORMAL);
 4372 rhaas                   16515 ECB             : 
 4372 rhaas                   16516 EUB             :     /* Clear pg_class.reloftype */
 1539 andres                  16517 GIC           3 :     relationRelation = table_open(RelationRelationId, RowExclusiveLock);
 4372 rhaas                   16518               3 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
                              16519               3 :     if (!HeapTupleIsValid(tuple))
 4372 rhaas                   16520 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
 4372 rhaas                   16521 GIC           3 :     ((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
 2259 alvherre                16522               3 :     CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
                              16523                 : 
 3675 rhaas                   16524               3 :     InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
                              16525                 : 
 4372 rhaas                   16526 CBC           3 :     heap_freetuple(tuple);
 1539 andres                  16527 GBC           3 :     table_close(relationRelation, RowExclusiveLock);
 6125 bruce                   16528 GIC           3 : }
                              16529                 : 
                              16530                 : /*
                              16531                 :  * relation_mark_replica_identity: Update a table's replica identity
                              16532                 :  *
                              16533                 :  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
                              16534                 :  * index. Otherwise, it must be InvalidOid.
                              16535                 :  *
                              16536                 :  * Caller had better hold an exclusive lock on the relation, as the results
   78 tgl                     16537 ECB             :  * of running two of these concurrently wouldn't be pretty.
 3439 rhaas                   16538                 :  */
                              16539                 : static void
 3439 rhaas                   16540 CBC         186 : relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
 3439 rhaas                   16541 EUB             :                                bool is_internal)
                              16542                 : {
                              16543                 :     Relation    pg_index;
                              16544                 :     Relation    pg_class;
                              16545                 :     HeapTuple   pg_class_tuple;
                              16546                 :     HeapTuple   pg_index_tuple;
                              16547                 :     Form_pg_class pg_class_form;
                              16548                 :     Form_pg_index pg_index_form;
                              16549                 :     ListCell   *index;
 3439 rhaas                   16550 ECB             : 
                              16551                 :     /*
                              16552                 :      * Check whether relreplident has changed, and update it if so.
                              16553                 :      */
 1539 andres                  16554 GIC         186 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
 3439 rhaas                   16555             186 :     pg_class_tuple = SearchSysCacheCopy1(RELOID,
 2118 tgl                     16556 ECB             :                                          ObjectIdGetDatum(RelationGetRelid(rel)));
 3439 rhaas                   16557 CBC         186 :     if (!HeapTupleIsValid(pg_class_tuple))
 3439 rhaas                   16558 UIC           0 :         elog(ERROR, "cache lookup failed for relation \"%s\"",
 3437 peter_e                 16559 ECB             :              RelationGetRelationName(rel));
 3439 rhaas                   16560 CBC         186 :     pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
 3439 rhaas                   16561 GIC         186 :     if (pg_class_form->relreplident != ri_type)
                              16562                 :     {
 3439 rhaas                   16563 CBC         164 :         pg_class_form->relreplident = ri_type;
 2259 alvherre                16564 GIC         164 :         CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
 3439 rhaas                   16565 ECB             :     }
 1539 andres                  16566 CBC         186 :     table_close(pg_class, RowExclusiveLock);
 3439 rhaas                   16567 GIC         186 :     heap_freetuple(pg_class_tuple);
                              16568                 : 
                              16569                 :     /*
                              16570                 :      * Update the per-index indisreplident flags correctly.
                              16571                 :      */
 1539 andres                  16572 CBC         186 :     pg_index = table_open(IndexRelationId, RowExclusiveLock);
 3439 rhaas                   16573             513 :     foreach(index, RelationGetIndexList(rel))
 3439 rhaas                   16574 ECB             :     {
 3439 rhaas                   16575 GIC         327 :         Oid         thisIndexOid = lfirst_oid(index);
                              16576             327 :         bool        dirty = false;
                              16577                 : 
                              16578             327 :         pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
                              16579                 :                                              ObjectIdGetDatum(thisIndexOid));
                              16580             327 :         if (!HeapTupleIsValid(pg_index_tuple))
 3439 rhaas                   16581 UIC           0 :             elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
 3439 rhaas                   16582 CBC         327 :         pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
                              16583                 : 
   78 tgl                     16584 GIC         327 :         if (thisIndexOid == indexOid)
                              16585                 :         {
                              16586                 :             /* Set the bit if not already set. */
   78 tgl                     16587 CBC         104 :             if (!pg_index_form->indisreplident)
   78 tgl                     16588 EUB             :             {
   78 tgl                     16589 GIC          98 :                 dirty = true;
                              16590              98 :                 pg_index_form->indisreplident = true;
                              16591                 :             }
                              16592                 :         }
                              16593                 :         else
                              16594                 :         {
                              16595                 :             /* Unset the bit if set. */
                              16596             223 :             if (pg_index_form->indisreplident)
   78 tgl                     16597 ECB             :             {
   78 tgl                     16598 GIC          20 :                 dirty = true;
                              16599              20 :                 pg_index_form->indisreplident = false;
                              16600                 :             }
                              16601                 :         }
                              16602                 : 
 3439 rhaas                   16603             327 :         if (dirty)
                              16604                 :         {
 2259 alvherre                16605 CBC         118 :             CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
 3439 rhaas                   16606 GIC         118 :             InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
 3437 peter_e                 16607 ECB             :                                          InvalidOid, is_internal);
                              16608                 : 
                              16609                 :             /*
                              16610                 :              * Invalidate the relcache for the table, so that after we commit
  509 akapila                 16611                 :              * all sessions will refresh the table's replica identity index
                              16612                 :              * before attempting any UPDATE or DELETE on the table.  (If we
   78 tgl                     16613                 :              * changed the table's pg_class row above, then a relcache inval
                              16614                 :              * is already queued due to that; but we might not have.)
                              16615                 :              */
  509 akapila                 16616 GIC         118 :             CacheInvalidateRelcache(rel);
                              16617                 :         }
 3439 rhaas                   16618             327 :         heap_freetuple(pg_index_tuple);
                              16619                 :     }
                              16620                 : 
 1539 andres                  16621             186 :     table_close(pg_index, RowExclusiveLock);
 3439 rhaas                   16622             186 : }
                              16623                 : 
 3439 rhaas                   16624 ECB             : /*
                              16625                 :  * ALTER TABLE <name> REPLICA IDENTITY ...
                              16626                 :  */
                              16627                 : static void
 3439 rhaas                   16628 GIC         207 : ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
                              16629                 : {
 3439 rhaas                   16630 ECB             :     Oid         indexOid;
                              16631                 :     Relation    indexRel;
                              16632                 :     int         key;
                              16633                 : 
 3439 rhaas                   16634 GIC         207 :     if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
                              16635                 :     {
                              16636               3 :         relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
                              16637               3 :         return;
 3439 rhaas                   16638 ECB             :     }
 3439 rhaas                   16639 CBC         204 :     else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
                              16640                 :     {
 3439 rhaas                   16641 GIC          61 :         relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
                              16642              61 :         return;
 3439 rhaas                   16643 ECB             :     }
 3439 rhaas                   16644 GIC         143 :     else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
                              16645                 :     {
 3439 rhaas                   16646 CBC          18 :         relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
 3439 rhaas                   16647 GIC          18 :         return;
                              16648                 :     }
                              16649             125 :     else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
 3439 rhaas                   16650 ECB             :     {
 3260 bruce                   16651                 :          /* fallthrough */ ;
 3439 rhaas                   16652                 :     }
                              16653                 :     else
 3439 rhaas                   16654 UIC           0 :         elog(ERROR, "unexpected identity type %u", stmt->identity_type);
                              16655                 : 
                              16656                 :     /* Check that the index exists */
 3439 rhaas                   16657 GIC         125 :     indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
                              16658             125 :     if (!OidIsValid(indexOid))
 3439 rhaas                   16659 UIC           0 :         ereport(ERROR,
 3439 rhaas                   16660 ECB             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              16661                 :                  errmsg("index \"%s\" for table \"%s\" does not exist",
                              16662                 :                         stmt->name, RelationGetRelationName(rel))));
                              16663                 : 
 3439 rhaas                   16664 CBC         125 :     indexRel = index_open(indexOid, ShareLock);
 3439 rhaas                   16665 ECB             : 
                              16666                 :     /* Check that the index is on the relation we're altering. */
 3439 rhaas                   16667 CBC         125 :     if (indexRel->rd_index == NULL ||
 3439 rhaas                   16668 GIC         125 :         indexRel->rd_index->indrelid != RelationGetRelid(rel))
                              16669               3 :         ereport(ERROR,
 3439 rhaas                   16670 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16671                 :                  errmsg("\"%s\" is not an index for table \"%s\"",
                              16672                 :                         RelationGetRelationName(indexRel),
                              16673                 :                         RelationGetRelationName(rel))));
                              16674                 :     /* The AM must support uniqueness, and the index must in fact be unique. */
 1539 andres                  16675 GIC         122 :     if (!indexRel->rd_indam->amcanunique ||
 2639 tgl                     16676             119 :         !indexRel->rd_index->indisunique)
 3439 rhaas                   16677 CBC           6 :         ereport(ERROR,
 3439 rhaas                   16678 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16679                 :                  errmsg("cannot use non-unique index \"%s\" as replica identity",
 2118 tgl                     16680                 :                         RelationGetRelationName(indexRel))));
 3439 rhaas                   16681 EUB             :     /* Deferred indexes are not guaranteed to be always unique. */
 3439 rhaas                   16682 GIC         116 :     if (!indexRel->rd_index->indimmediate)
                              16683               3 :         ereport(ERROR,
                              16684                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              16685                 :                  errmsg("cannot use non-immediate index \"%s\" as replica identity",
 2118 tgl                     16686 ECB             :                         RelationGetRelationName(indexRel))));
                              16687                 :     /* Expression indexes aren't supported. */
 3439 rhaas                   16688 GIC         113 :     if (RelationGetIndexExpressions(indexRel) != NIL)
                              16689               3 :         ereport(ERROR,
                              16690                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              16691                 :                  errmsg("cannot use expression index \"%s\" as replica identity",
                              16692                 :                         RelationGetRelationName(indexRel))));
                              16693                 :     /* Predicate indexes aren't supported. */
                              16694             110 :     if (RelationGetIndexPredicate(indexRel) != NIL)
                              16695               3 :         ereport(ERROR,
                              16696                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              16697                 :                  errmsg("cannot use partial index \"%s\" as replica identity",
                              16698                 :                         RelationGetRelationName(indexRel))));
                              16699                 : 
                              16700                 :     /* Check index for nullable columns. */
 1828 teodor                  16701             237 :     for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
                              16702                 :     {
 3260 bruce                   16703             133 :         int16       attno = indexRel->rd_index->indkey.values[key];
                              16704                 :         Form_pg_attribute attr;
                              16705                 : 
                              16706                 :         /*
 2550 tgl                     16707 ECB             :          * Reject any other system columns.  (Going forward, we'll disallow
                              16708                 :          * indexes containing such columns in the first place, but they might
                              16709                 :          * exist in older branches.)
                              16710                 :          */
 2550 tgl                     16711 GIC         133 :         if (attno <= 0)
 2550 tgl                     16712 UIC           0 :             ereport(ERROR,
                              16713                 :                     (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                              16714                 :                      errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
                              16715                 :                             RelationGetRelationName(indexRel), attno)));
                              16716                 : 
 2058 andres                  16717 CBC         133 :         attr = TupleDescAttr(rel->rd_att, attno - 1);
 3439 rhaas                   16718 GIC         133 :         if (!attr->attnotnull)
                              16719               3 :             ereport(ERROR,
 3437 peter_e                 16720 ECB             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16721                 :                      errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
                              16722                 :                             RelationGetRelationName(indexRel),
                              16723                 :                             NameStr(attr->attname))));
                              16724                 :     }
                              16725                 : 
 3439 rhaas                   16726                 :     /* This index is suitable for use as a replica identity. Mark it. */
 3439 rhaas                   16727 CBC         104 :     relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
                              16728                 : 
                              16729             104 :     index_close(indexRel, NoLock);
 3439 rhaas                   16730 ECB             : }
                              16731                 : 
                              16732                 : /*
                              16733                 :  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
                              16734                 :  */
                              16735                 : static void
  768 michael                 16736 CBC         139 : ATExecSetRowSecurity(Relation rel, bool rls)
                              16737                 : {
                              16738                 :     Relation    pg_class;
                              16739                 :     Oid         relid;
                              16740                 :     HeapTuple   tuple;
                              16741                 : 
 3124 sfrost                  16742 GIC         139 :     relid = RelationGetRelid(rel);
                              16743                 : 
                              16744                 :     /* Pull the record for this relation and update it */
 1539 andres                  16745             139 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
 3124 sfrost                  16746 ECB             : 
 3124 sfrost                  16747 CBC         139 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
                              16748                 : 
 3124 sfrost                  16749 GIC         139 :     if (!HeapTupleIsValid(tuple))
 3124 sfrost                  16750 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
 3124 sfrost                  16751 ECB             : 
  768 michael                 16752 GIC         139 :     ((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls;
 2259 alvherre                16753 CBC         139 :     CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
                              16754                 : 
 1539 andres                  16755             139 :     table_close(pg_class, RowExclusiveLock);
 2744 sfrost                  16756 GIC         139 :     heap_freetuple(tuple);
                              16757             139 : }
 2744 sfrost                  16758 ECB             : 
 2744 sfrost                  16759 EUB             : /*
 2744 sfrost                  16760 ECB             :  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
                              16761                 :  */
                              16762                 : static void
 2744 sfrost                  16763 CBC          55 : ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
 2744 sfrost                  16764 ECB             : {
                              16765                 :     Relation    pg_class;
                              16766                 :     Oid         relid;
                              16767                 :     HeapTuple   tuple;
                              16768                 : 
 2744 sfrost                  16769 GIC          55 :     relid = RelationGetRelid(rel);
 2744 sfrost                  16770 ECB             : 
 1539 andres                  16771 CBC          55 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
 2744 sfrost                  16772 ECB             : 
 2744 sfrost                  16773 GIC          55 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
 2744 sfrost                  16774 ECB             : 
 2744 sfrost                  16775 CBC          55 :     if (!HeapTupleIsValid(tuple))
 2744 sfrost                  16776 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
                              16777                 : 
 2744 sfrost                  16778 CBC          55 :     ((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
 2259 alvherre                16779              55 :     CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
                              16780                 : 
 1539 andres                  16781 GIC          55 :     table_close(pg_class, RowExclusiveLock);
 3124 sfrost                  16782              55 :     heap_freetuple(tuple);
                              16783              55 : }
                              16784                 : 
                              16785                 : /*
                              16786                 :  * ALTER FOREIGN TABLE <name> OPTIONS (...)
                              16787                 :  */
                              16788                 : static void
 4481 rhaas                   16789 CBC          23 : ATExecGenericOptions(Relation rel, List *options)
 4481 rhaas                   16790 ECB             : {
                              16791                 :     Relation    ftrel;
                              16792                 :     ForeignServer *server;
                              16793                 :     ForeignDataWrapper *fdw;
 4382 bruce                   16794                 :     HeapTuple   tuple;
                              16795                 :     bool        isnull;
                              16796                 :     Datum       repl_val[Natts_pg_foreign_table];
                              16797                 :     bool        repl_null[Natts_pg_foreign_table];
                              16798                 :     bool        repl_repl[Natts_pg_foreign_table];
                              16799                 :     Datum       datum;
                              16800                 :     Form_pg_foreign_table tableform;
                              16801                 : 
 4382 bruce                   16802 CBC          23 :     if (options == NIL)
 4481 rhaas                   16803 UIC           0 :         return;
 4481 rhaas                   16804 ECB             : 
 1539 andres                  16805 CBC          23 :     ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
 4481 rhaas                   16806 ECB             : 
 4481 rhaas                   16807 CBC          23 :     tuple = SearchSysCacheCopy1(FOREIGNTABLEREL, rel->rd_id);
 4481 rhaas                   16808 GIC          23 :     if (!HeapTupleIsValid(tuple))
 4481 rhaas                   16809 UIC           0 :         ereport(ERROR,
 4481 rhaas                   16810 ECB             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              16811                 :                  errmsg("foreign table \"%s\" does not exist",
                              16812                 :                         RelationGetRelationName(rel))));
 4481 rhaas                   16813 CBC          23 :     tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
 4481 rhaas                   16814 GIC          23 :     server = GetForeignServer(tableform->ftserver);
                              16815              23 :     fdw = GetForeignDataWrapper(server->fdwid);
                              16816                 : 
 4481 rhaas                   16817 CBC          23 :     memset(repl_val, 0, sizeof(repl_val));
 4481 rhaas                   16818 GIC          23 :     memset(repl_null, false, sizeof(repl_null));
                              16819              23 :     memset(repl_repl, false, sizeof(repl_repl));
 4481 rhaas                   16820 ECB             : 
                              16821                 :     /* Extract the current options */
 4481 rhaas                   16822 CBC          23 :     datum = SysCacheGetAttr(FOREIGNTABLEREL,
 4481 rhaas                   16823 ECB             :                             tuple,
                              16824                 :                             Anum_pg_foreign_table_ftoptions,
                              16825                 :                             &isnull);
 4481 rhaas                   16826 GIC          23 :     if (isnull)
                              16827               2 :         datum = PointerGetDatum(NULL);
                              16828                 : 
                              16829                 :     /* Transform the options */
 4481 rhaas                   16830 CBC          23 :     datum = transformGenericOptions(ForeignTableRelationId,
                              16831                 :                                     datum,
 4481 rhaas                   16832 ECB             :                                     options,
                              16833                 :                                     fdw->fdwvalidator);
                              16834                 : 
 4481 rhaas                   16835 CBC          22 :     if (PointerIsValid(DatumGetPointer(datum)))
 4481 rhaas                   16836 GIC          22 :         repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
 4481 rhaas                   16837 ECB             :     else
 4481 rhaas                   16838 LBC           0 :         repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
                              16839                 : 
 4481 rhaas                   16840 GIC          22 :     repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
                              16841                 : 
 4481 rhaas                   16842 ECB             :     /* Everything looks good - update the tuple */
                              16843                 : 
 4481 rhaas                   16844 CBC          22 :     tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
                              16845                 :                               repl_val, repl_null, repl_repl);
 4481 rhaas                   16846 ECB             : 
 2259 alvherre                16847 GIC          22 :     CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
 4481 rhaas                   16848 ECB             : 
                              16849                 :     /*
 2284 tgl                     16850                 :      * Invalidate relcache so that all sessions will refresh any cached plans
                              16851                 :      * that might depend on the old options.
                              16852                 :      */
 2284 tgl                     16853 GIC          22 :     CacheInvalidateRelcache(rel);
                              16854                 : 
 3675 rhaas                   16855              22 :     InvokeObjectPostAlterHook(ForeignTableRelationId,
 3675 rhaas                   16856 ECB             :                               RelationGetRelid(rel), 0);
                              16857                 : 
 1539 andres                  16858 CBC          22 :     table_close(ftrel, RowExclusiveLock);
                              16859                 : 
 4481 rhaas                   16860 GIC          22 :     heap_freetuple(tuple);
 4481 rhaas                   16861 ECB             : }
                              16862                 : 
                              16863                 : /*
  751                         16864                 :  * ALTER TABLE ALTER COLUMN SET COMPRESSION
  751 rhaas                   16865 EUB             :  *
                              16866                 :  * Return value is the address of the modified column
                              16867                 :  */
  751 rhaas                   16868 ECB             : static ObjectAddress
  270 peter                   16869 GNC          33 : ATExecSetCompression(Relation rel,
                              16870                 :                      const char *column,
  751 rhaas                   16871 ECB             :                      Node *newValue,
                              16872                 :                      LOCKMODE lockmode)
                              16873                 : {
                              16874                 :     Relation    attrel;
                              16875                 :     HeapTuple   tuple;
                              16876                 :     Form_pg_attribute atttableform;
                              16877                 :     AttrNumber  attnum;
                              16878                 :     char       *compression;
  748                         16879                 :     char        cmethod;
                              16880                 :     ObjectAddress address;
                              16881                 : 
  751 rhaas                   16882 GIC          33 :     compression = strVal(newValue);
                              16883                 : 
                              16884              33 :     attrel = table_open(AttributeRelationId, RowExclusiveLock);
                              16885                 : 
                              16886                 :     /* copy the cache entry so we can scribble on it below */
  749 tgl                     16887              33 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), column);
  751 rhaas                   16888 CBC          33 :     if (!HeapTupleIsValid(tuple))
  751 rhaas                   16889 UIC           0 :         ereport(ERROR,
                              16890                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
  751 rhaas                   16891 ECB             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                              16892                 :                         column, RelationGetRelationName(rel))));
                              16893                 : 
                              16894                 :     /* prevent them from altering a system attribute */
  751 rhaas                   16895 GIC          33 :     atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
                              16896              33 :     attnum = atttableform->attnum;
                              16897              33 :     if (attnum <= 0)
  751 rhaas                   16898 UIC           0 :         ereport(ERROR,
                              16899                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              16900                 :                  errmsg("cannot alter system column \"%s\"", column)));
  751 rhaas                   16901 ECB             : 
                              16902                 :     /*
                              16903                 :      * Check that column type is compressible, then get the attribute
                              16904                 :      * compression method code
                              16905                 :      */
  682 tgl                     16906 GIC          33 :     cmethod = GetAttributeCompression(atttableform->atttypid, compression);
                              16907                 : 
                              16908                 :     /* update pg_attribute entry */
  748 rhaas                   16909 CBC          30 :     atttableform->attcompression = cmethod;
  751 rhaas                   16910 GIC          30 :     CatalogTupleUpdate(attrel, &tuple->t_self, tuple);
  751 rhaas                   16911 ECB             : 
  751 rhaas                   16912 GIC          30 :     InvokeObjectPostAlterHook(RelationRelationId,
                              16913                 :                               RelationGetRelid(rel),
                              16914                 :                               attnum);
  751 rhaas                   16915 ECB             : 
                              16916                 :     /*
                              16917                 :      * Apply the change to indexes as well (only for simple index columns,
                              16918                 :      * matching behavior of index.c ConstructTupleDescriptor()).
  749 tgl                     16919                 :      */
  682 tgl                     16920 GIC          30 :     SetIndexStorageProperties(rel, attrel, attnum,
                              16921                 :                               false, 0,
                              16922                 :                               true, cmethod,
                              16923                 :                               lockmode);
  749 tgl                     16924 ECB             : 
  749 tgl                     16925 GIC          30 :     heap_freetuple(tuple);
                              16926                 : 
  751 rhaas                   16927 CBC          30 :     table_close(attrel, RowExclusiveLock);
                              16928                 : 
  751 rhaas                   16929 ECB             :     /* make changes visible */
  751 rhaas                   16930 GIC          30 :     CommandCounterIncrement();
  751 rhaas                   16931 ECB             : 
  751 rhaas                   16932 CBC          30 :     ObjectAddressSubSet(address, RelationRelationId,
  749 tgl                     16933 ECB             :                         RelationGetRelid(rel), attnum);
  751 rhaas                   16934 CBC          30 :     return address;
  751 rhaas                   16935 ECB             : }
                              16936                 : 
                              16937                 : 
 3152 alvherre                16938                 : /*
                              16939                 :  * Preparation phase for SET LOGGED/UNLOGGED
                              16940                 :  *
                              16941                 :  * This verifies that we're not trying to change a temp table.  Also,
                              16942                 :  * existing foreign key constraints are checked to avoid ending up with
                              16943                 :  * permanent tables referencing unlogged tables.
                              16944                 :  *
                              16945                 :  * Return value is false if the operation is a no-op (in which case the
                              16946                 :  * checks are skipped), otherwise true.
                              16947                 :  */
                              16948                 : static bool
 3149 alvherre                16949 GIC          35 : ATPrepChangePersistence(Relation rel, bool toLogged)
                              16950                 : {
                              16951                 :     Relation    pg_constraint;
                              16952                 :     HeapTuple   tuple;
 3152 alvherre                16953 ECB             :     SysScanDesc scan;
                              16954                 :     ScanKeyData skey[1];
                              16955                 : 
                              16956                 :     /*
                              16957                 :      * Disallow changing status for a temp table.  Also verify whether we can
                              16958                 :      * get away with doing nothing; in such cases we don't need to run the
                              16959                 :      * checks below, either.
                              16960                 :      */
 3152 alvherre                16961 GIC          35 :     switch (rel->rd_rel->relpersistence)
                              16962                 :     {
 3152 alvherre                16963 UIC           0 :         case RELPERSISTENCE_TEMP:
                              16964               0 :             ereport(ERROR,
                              16965                 :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              16966                 :                      errmsg("cannot change logged status of table \"%s\" because it is temporary",
                              16967                 :                             RelationGetRelationName(rel)),
                              16968                 :                      errtable(rel)));
                              16969                 :             break;
 3152 alvherre                16970 GIC          19 :         case RELPERSISTENCE_PERMANENT:
                              16971              19 :             if (toLogged)
 3152 alvherre                16972 ECB             :                 /* nothing to do */
 3152 alvherre                16973 CBC           3 :                 return false;
                              16974              16 :             break;
                              16975              16 :         case RELPERSISTENCE_UNLOGGED:
 3152 alvherre                16976 GIC          16 :             if (!toLogged)
                              16977                 :                 /* nothing to do */
 3152 alvherre                16978 CBC           3 :                 return false;
                              16979              13 :             break;
                              16980                 :     }
                              16981                 : 
                              16982                 :     /*
                              16983                 :      * Check that the table is not part of any publication when changing to
                              16984                 :      * UNLOGGED, as UNLOGGED tables can't be published.
 2271 peter_e                 16985 ECB             :      */
 2271 peter_e                 16986 CBC          45 :     if (!toLogged &&
  235 tgl                     16987 GNC          16 :         GetRelationPublications(RelationGetRelid(rel)) != NIL)
 2271 peter_e                 16988 UIC           0 :         ereport(ERROR,
 2271 peter_e                 16989 ECB             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              16990                 :                  errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
                              16991                 :                         RelationGetRelationName(rel)),
                              16992                 :                  errdetail("Unlogged relations cannot be replicated.")));
                              16993                 : 
                              16994                 :     /*
                              16995                 :      * Check existing foreign key constraints to preserve the invariant that
 2811 heikki.linnakangas      16996                 :      * permanent tables cannot reference unlogged ones.  Self-referencing
 3152 alvherre                16997                 :      * foreign keys can safely be ignored.
                              16998                 :      */
 1539 andres                  16999 CBC          29 :     pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
                              17000                 : 
                              17001                 :     /*
                              17002                 :      * Scan conrelid if changing to permanent, else confrelid.  This also
                              17003                 :      * determines whether a useful index exists.
                              17004                 :      */
 3152 alvherre                17005 GIC          29 :     ScanKeyInit(&skey[0],
                              17006                 :                 toLogged ? Anum_pg_constraint_conrelid :
 3152 alvherre                17007 ECB             :                 Anum_pg_constraint_confrelid,
                              17008                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              17009                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
 3152 alvherre                17010 CBC          29 :     scan = systable_beginscan(pg_constraint,
                              17011                 :                               toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
                              17012                 :                               true, NULL, 1, skey);
                              17013                 : 
 3152 alvherre                17014 GIC          53 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
 3152 alvherre                17015 ECB             :     {
 3152 alvherre                17016 CBC          30 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
                              17017                 : 
 3152 alvherre                17018 GIC          30 :         if (con->contype == CONSTRAINT_FOREIGN)
                              17019                 :         {
 3152 alvherre                17020 ECB             :             Oid         foreignrelid;
                              17021                 :             Relation    foreignrel;
                              17022                 : 
                              17023                 :             /* the opposite end of what we used as scankey */
 3152 alvherre                17024 GIC          15 :             foreignrelid = toLogged ? con->confrelid : con->conrelid;
                              17025                 : 
 3152 alvherre                17026 ECB             :             /* ignore if self-referencing */
 3152 alvherre                17027 CBC          15 :             if (RelationGetRelid(rel) == foreignrelid)
 3152 alvherre                17028 GIC           6 :                 continue;
                              17029                 : 
                              17030               9 :             foreignrel = relation_open(foreignrelid, AccessShareLock);
                              17031                 : 
                              17032               9 :             if (toLogged)
 3152 alvherre                17033 ECB             :             {
  748 bruce                   17034 CBC           3 :                 if (!RelationIsPermanent(foreignrel))
 3152 alvherre                17035               3 :                     ereport(ERROR,
 3152 alvherre                17036 ECB             :                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              17037                 :                              errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
                              17038                 :                                     RelationGetRelationName(rel),
                              17039                 :                                     RelationGetRelationName(foreignrel)),
                              17040                 :                              errtableconstraint(rel, NameStr(con->conname))));
                              17041                 :             }
                              17042                 :             else
                              17043                 :             {
  748 bruce                   17044 CBC           6 :                 if (RelationIsPermanent(foreignrel))
 3152 alvherre                17045 GIC           3 :                     ereport(ERROR,
 3152 alvherre                17046 ECB             :                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              17047                 :                              errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
                              17048                 :                                     RelationGetRelationName(rel),
 2697 tgl                     17049                 :                                     RelationGetRelationName(foreignrel)),
 3152 alvherre                17050                 :                              errtableconstraint(rel, NameStr(con->conname))));
                              17051                 :             }
                              17052                 : 
 3152 alvherre                17053 GIC           3 :             relation_close(foreignrel, AccessShareLock);
                              17054                 :         }
                              17055                 :     }
                              17056                 : 
 3152 alvherre                17057 CBC          23 :     systable_endscan(scan);
 3152 alvherre                17058 ECB             : 
 1539 andres                  17059 GIC          23 :     table_close(pg_constraint, AccessShareLock);
                              17060                 : 
 3152 alvherre                17061              23 :     return true;
 3152 alvherre                17062 ECB             : }
                              17063                 : 
 4133 rhaas                   17064                 : /*
                              17065                 :  * Execute ALTER TABLE SET SCHEMA
                              17066                 :  */
 2959 alvherre                17067                 : ObjectAddress
 2959 alvherre                17068 CBC          49 : AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
                              17069                 : {
                              17070                 :     Relation    rel;
 4133 rhaas                   17071 ECB             :     Oid         relid;
                              17072                 :     Oid         oldNspOid;
                              17073                 :     Oid         nspOid;
 4101 rhaas                   17074 EUB             :     RangeVar   *newrv;
 3812 alvherre                17075 ECB             :     ObjectAddresses *objsMoved;
 2959                         17076                 :     ObjectAddress myself;
                              17077                 : 
 4111 rhaas                   17078 CBC          49 :     relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
 1836 andres                  17079 GIC          49 :                                      stmt->missing_ok ? RVR_MISSING_OK : 0,
 4111 rhaas                   17080 ECB             :                                      RangeVarCallbackForAlterRelation,
                              17081                 :                                      (void *) stmt);
                              17082                 : 
 4094 simon                   17083 CBC          48 :     if (!OidIsValid(relid))
                              17084                 :     {
                              17085               6 :         ereport(NOTICE,
                              17086                 :                 (errmsg("relation \"%s\" does not exist, skipping",
                              17087                 :                         stmt->relation->relname)));
 2959 alvherre                17088 GIC           6 :         return InvalidObjectAddress;
                              17089                 :     }
                              17090                 : 
 4133 rhaas                   17091              42 :     rel = relation_open(relid, NoLock);
                              17092                 : 
                              17093              42 :     oldNspOid = RelationGetNamespace(rel);
                              17094                 : 
 4133 rhaas                   17095 ECB             :     /* If it's an owned sequence, disallow moving it by itself. */
 4133 rhaas                   17096 GIC          42 :     if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
 4133 rhaas                   17097 ECB             :     {
                              17098                 :         Oid         tableId;
                              17099                 :         int32       colId;
                              17100                 : 
 2194 peter_e                 17101 CBC           2 :         if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
 2194 peter_e                 17102 GBC           1 :             sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
 4133 rhaas                   17103 UIC           0 :             ereport(ERROR,
                              17104                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              17105                 :                      errmsg("cannot move an owned sequence into another schema"),
                              17106                 :                      errdetail("Sequence \"%s\" is linked to table \"%s\".",
                              17107                 :                                RelationGetRelationName(rel),
                              17108                 :                                get_rel_name(tableId))));
                              17109                 :     }
                              17110                 : 
                              17111                 :     /* Get and lock schema OID and check its permissions. */
 4101 rhaas                   17112 CBC          42 :     newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
 4101 rhaas                   17113 GIC          42 :     nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
                              17114                 : 
                              17115                 :     /* common checks on switching namespaces */
 2698 rhaas                   17116 CBC          42 :     CheckSetNamespace(oldNspOid, nspOid);
 6460 tgl                     17117 ECB             : 
 3812 alvherre                17118 CBC          42 :     objsMoved = new_object_addresses();
 3812 alvherre                17119 GBC          42 :     AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
 3812 alvherre                17120 CBC          42 :     free_object_addresses(objsMoved);
 3812 alvherre                17121 ECB             : 
 2959 alvherre                17122 GIC          42 :     ObjectAddressSet(myself, RelationRelationId, relid);
 2959 alvherre                17123 ECB             : 
 2959 alvherre                17124 GIC          42 :     if (oldschema)
 2959 alvherre                17125 CBC          42 :         *oldschema = oldNspOid;
 2959 alvherre                17126 ECB             : 
 3812                         17127                 :     /* close rel, but keep lock until commit */
 3812 alvherre                17128 GIC          42 :     relation_close(rel, NoLock);
                              17129                 : 
 2959                         17130              42 :     return myself;
                              17131                 : }
                              17132                 : 
                              17133                 : /*
                              17134                 :  * The guts of relocating a table or materialized view to another namespace:
                              17135                 :  * besides moving the relation itself, its dependent objects are relocated to
                              17136                 :  * the new schema.
                              17137                 :  */
                              17138                 : void
 3812 alvherre                17139 CBC          42 : AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
                              17140                 :                             ObjectAddresses *objsMoved)
                              17141                 : {
                              17142                 :     Relation    classRel;
                              17143                 : 
 3812 alvherre                17144 GIC          42 :     Assert(objsMoved != NULL);
                              17145                 : 
                              17146                 :     /* OK, modify the pg_class row and pg_depend entry */
 1539 andres                  17147              42 :     classRel = table_open(RelationRelationId, RowExclusiveLock);
                              17148                 : 
 3812 alvherre                17149              42 :     AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
                              17150                 :                                    nspOid, true, objsMoved);
                              17151                 : 
                              17152                 :     /* Fix the table's row type too, if it has one */
 1006 tgl                     17153 CBC          42 :     if (OidIsValid(rel->rd_rel->reltype))
                              17154              41 :         AlterTypeNamespaceInternal(rel->rd_rel->reltype,
                              17155                 :                                    nspOid, false, false, objsMoved);
 6460 tgl                     17156 ECB             : 
 6460 tgl                     17157 EUB             :     /* Fix other dependent stuff */
 3689 kgrittn                 17158 GIC          42 :     if (rel->rd_rel->relkind == RELKIND_RELATION ||
 2314 rhaas                   17159 CBC          10 :         rel->rd_rel->relkind == RELKIND_MATVIEW ||
                              17160               7 :         rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              17161                 :     {
 3812 alvherre                17162              35 :         AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
                              17163              35 :         AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
                              17164                 :                            objsMoved, AccessExclusiveLock);
                              17165              35 :         AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
 3812 alvherre                17166 ECB             :                                   false, objsMoved);
                              17167                 :     }
                              17168                 : 
 1539 andres                  17169 GIC          42 :     table_close(classRel, RowExclusiveLock);
 6460 tgl                     17170              42 : }
 6460 tgl                     17171 ECB             : 
                              17172                 : /*
                              17173                 :  * The guts of relocating a relation to another namespace: fix the pg_class
                              17174                 :  * entry, and the pg_depend entry if any.  Caller must already have
                              17175                 :  * opened and write-locked pg_class.
                              17176                 :  */
                              17177                 : void
 6460 tgl                     17178 GIC          88 : AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 6460 tgl                     17179 ECB             :                                Oid oldNspOid, Oid newNspOid,
 3599 sfrost                  17180 EUB             :                                bool hasDependEntry,
 3599 sfrost                  17181 ECB             :                                ObjectAddresses *objsMoved)
                              17182                 : {
 6385 bruce                   17183                 :     HeapTuple   classTup;
                              17184                 :     Form_pg_class classForm;
                              17185                 :     ObjectAddress thisobj;
 2698 rhaas                   17186 CBC          88 :     bool        already_done = false;
                              17187                 : 
 4802                         17188              88 :     classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
 6460 tgl                     17189              88 :     if (!HeapTupleIsValid(classTup))
 6460 tgl                     17190 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relOid);
 6460 tgl                     17191 GIC          88 :     classForm = (Form_pg_class) GETSTRUCT(classTup);
                              17192                 : 
                              17193              88 :     Assert(classForm->relnamespace == oldNspOid);
                              17194                 : 
 3812 alvherre                17195 CBC          88 :     thisobj.classId = RelationRelationId;
 3812 alvherre                17196 GIC          88 :     thisobj.objectId = relOid;
 3812 alvherre                17197 CBC          88 :     thisobj.objectSubId = 0;
 3812 alvherre                17198 ECB             : 
                              17199                 :     /*
                              17200                 :      * If the object has already been moved, don't move it again.  If it's
                              17201                 :      * already in the right place, don't move it, but still fire the object
 2698 rhaas                   17202                 :      * access hook.
                              17203                 :      */
 2698 rhaas                   17204 CBC          88 :     already_done = object_address_present(&thisobj, objsMoved);
                              17205              88 :     if (!already_done && oldNspOid != newNspOid)
                              17206                 :     {
                              17207                 :         /* check for duplicate name (more friendly than unique-index failure) */
 3812 alvherre                17208 GIC          67 :         if (get_relname_relid(NameStr(classForm->relname),
                              17209                 :                               newNspOid) != InvalidOid)
 3812 alvherre                17210 UIC           0 :             ereport(ERROR,
                              17211                 :                     (errcode(ERRCODE_DUPLICATE_TABLE),
                              17212                 :                      errmsg("relation \"%s\" already exists in schema \"%s\"",
                              17213                 :                             NameStr(classForm->relname),
                              17214                 :                             get_namespace_name(newNspOid))));
 6460 tgl                     17215 ECB             : 
                              17216                 :         /* classTup is a copy, so OK to scribble on */
 3812 alvherre                17217 CBC          67 :         classForm->relnamespace = newNspOid;
                              17218                 : 
 2259 alvherre                17219 GIC          67 :         CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
 6460 tgl                     17220 ECB             : 
 3812 alvherre                17221                 :         /* Update dependency on schema if caller said so */
 3812 alvherre                17222 GIC         115 :         if (hasDependEntry &&
 3599 sfrost                  17223              48 :             changeDependencyFor(RelationRelationId,
                              17224                 :                                 relOid,
                              17225                 :                                 NamespaceRelationId,
                              17226                 :                                 oldNspOid,
 3599 sfrost                  17227 ECB             :                                 newNspOid) != 1)
 3812 alvherre                17228 UIC           0 :             elog(ERROR, "failed to change schema dependency for relation \"%s\"",
                              17229                 :                  NameStr(classForm->relname));
                              17230                 :     }
 2698 rhaas                   17231 GIC          88 :     if (!already_done)
                              17232                 :     {
 3812 alvherre                17233 CBC          88 :         add_exact_object_address(&thisobj, objsMoved);
                              17234                 : 
 3675 rhaas                   17235              88 :         InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
 3812 alvherre                17236 ECB             :     }
                              17237                 : 
 6460 tgl                     17238 CBC          88 :     heap_freetuple(classTup);
 6460 tgl                     17239 GIC          88 : }
 6460 tgl                     17240 ECB             : 
                              17241                 : /*
                              17242                 :  * Move all indexes for the specified relation to another namespace.
                              17243                 :  *
                              17244                 :  * Note: we assume adequate permission checking was done by the caller,
                              17245                 :  * and that the caller has a suitable lock on the owning relation.
                              17246                 :  */
                              17247                 : static void
 6460 tgl                     17248 CBC          35 : AlterIndexNamespaces(Relation classRel, Relation rel,
                              17249                 :                      Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
                              17250                 : {
                              17251                 :     List       *indexList;
                              17252                 :     ListCell   *l;
 6460 tgl                     17253 EUB             : 
 6460 tgl                     17254 GIC          35 :     indexList = RelationGetIndexList(rel);
                              17255                 : 
 6460 tgl                     17256 CBC          57 :     foreach(l, indexList)
 6460 tgl                     17257 ECB             :     {
 6385 bruce                   17258 GBC          22 :         Oid         indexOid = lfirst_oid(l);
                              17259                 :         ObjectAddress thisobj;
                              17260                 : 
 3812 alvherre                17261 GIC          22 :         thisobj.classId = RelationRelationId;
                              17262              22 :         thisobj.objectId = indexOid;
 3812 alvherre                17263 CBC          22 :         thisobj.objectSubId = 0;
                              17264                 : 
                              17265                 :         /*
 6385 bruce                   17266 ECB             :          * Note: currently, the index will not have its own dependency on the
                              17267                 :          * namespace, so we don't need to do changeDependencyFor(). There's no
 4309 peter_e                 17268                 :          * row type in pg_type, either.
                              17269                 :          *
                              17270                 :          * XXX this objsMoved test may be pointless -- surely we have a single
                              17271                 :          * dependency link from a relation to each index?
                              17272                 :          */
 3812 alvherre                17273 GIC          22 :         if (!object_address_present(&thisobj, objsMoved))
 3812 alvherre                17274 ECB             :         {
 3812 alvherre                17275 CBC          22 :             AlterRelationNamespaceInternal(classRel, indexOid,
 3812 alvherre                17276 ECB             :                                            oldNspOid, newNspOid,
                              17277                 :                                            false, objsMoved);
 3812 alvherre                17278 GIC          22 :             add_exact_object_address(&thisobj, objsMoved);
                              17279                 :         }
                              17280                 :     }
 6460 tgl                     17281 ECB             : 
 6460 tgl                     17282 CBC          35 :     list_free(indexList);
 6460 tgl                     17283 GIC          35 : }
                              17284                 : 
                              17285                 : /*
                              17286                 :  * Move all identity and SERIAL-column sequences of the specified relation to another
 6460 tgl                     17287 ECB             :  * namespace.
                              17288                 :  *
                              17289                 :  * Note: we assume adequate permission checking was done by the caller,
                              17290                 :  * and that the caller has a suitable lock on the owning relation.
                              17291                 :  */
                              17292                 : static void
 6460 tgl                     17293 CBC          35 : AlterSeqNamespaces(Relation classRel, Relation rel,
 3812 alvherre                17294 ECB             :                    Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
                              17295                 :                    LOCKMODE lockmode)
                              17296                 : {
                              17297                 :     Relation    depRel;
                              17298                 :     SysScanDesc scan;
                              17299                 :     ScanKeyData key[2];
 6460 tgl                     17300                 :     HeapTuple   tup;
                              17301                 : 
                              17302                 :     /*
                              17303                 :      * SERIAL sequences are those having an auto dependency on one of the
                              17304                 :      * table's columns (we don't care *which* column, exactly).
                              17305                 :      */
 1539 andres                  17306 GIC          35 :     depRel = table_open(DependRelationId, AccessShareLock);
                              17307                 : 
 6460 tgl                     17308              35 :     ScanKeyInit(&key[0],
                              17309                 :                 Anum_pg_depend_refclassid,
 6460 tgl                     17310 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
 6460 tgl                     17311 EUB             :                 ObjectIdGetDatum(RelationRelationId));
 6460 tgl                     17312 GIC          35 :     ScanKeyInit(&key[1],
                              17313                 :                 Anum_pg_depend_refobjid,
                              17314                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              17315                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
 6460 tgl                     17316 ECB             :     /* we leave refobjsubid unspecified */
                              17317                 : 
 6460 tgl                     17318 CBC          35 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
                              17319                 :                               NULL, 2, key);
                              17320                 : 
 6460 tgl                     17321 GIC         246 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
                              17322                 :     {
                              17323             211 :         Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
                              17324                 :         Relation    seqRel;
                              17325                 : 
 6075 tgl                     17326 ECB             :         /* skip dependencies other than auto dependencies on columns */
 6460 tgl                     17327 GIC         211 :         if (depForm->refobjsubid == 0 ||
 6460 tgl                     17328 CBC         150 :             depForm->classid != RelationRelationId ||
 6460 tgl                     17329 GIC          18 :             depForm->objsubid != 0 ||
 2194 peter_e                 17330              18 :             !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
 6460 tgl                     17331             193 :             continue;
                              17332                 : 
                              17333                 :         /* Use relation_open just in case it's an index */
 4638 simon                   17334              18 :         seqRel = relation_open(depForm->objid, lockmode);
 6460 tgl                     17335 ECB             : 
                              17336                 :         /* skip non-sequence relations */
 6460 tgl                     17337 GIC          18 :         if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
                              17338                 :         {
                              17339                 :             /* No need to keep the lock */
 4638 simon                   17340 UIC           0 :             relation_close(seqRel, lockmode);
 6460 tgl                     17341 LBC           0 :             continue;
                              17342                 :         }
                              17343                 : 
 6460 tgl                     17344 ECB             :         /* Fix the pg_class and pg_depend entries */
 6460 tgl                     17345 GIC          18 :         AlterRelationNamespaceInternal(classRel, depForm->objid,
 6460 tgl                     17346 ECB             :                                        oldNspOid, newNspOid,
                              17347                 :                                        true, objsMoved);
 6385 bruce                   17348                 : 
 6460 tgl                     17349 EUB             :         /*
                              17350                 :          * Sequences used to have entries in pg_type, but no longer do.  If we
 1006 tgl                     17351 ECB             :          * ever re-instate that, we'll need to move the pg_type entry to the
                              17352                 :          * new namespace, too (using AlterTypeNamespaceInternal).
                              17353                 :          */
 1006 tgl                     17354 CBC          18 :         Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
 6460 tgl                     17355 ECB             : 
                              17356                 :         /* Now we can close it.  Keep the lock till end of transaction. */
 6460 tgl                     17357 GIC          18 :         relation_close(seqRel, NoLock);
                              17358                 :     }
                              17359                 : 
                              17360              35 :     systable_endscan(scan);
                              17361                 : 
 6460 tgl                     17362 CBC          35 :     relation_close(depRel, AccessShareLock);
 6460 tgl                     17363 GIC          35 : }
                              17364                 : 
                              17365                 : 
                              17366                 : /*
                              17367                 :  * This code supports
 7454 tgl                     17368 ECB             :  *  CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
                              17369                 :  *
                              17370                 :  * Because we only support this for TEMP tables, it's sufficient to remember
                              17371                 :  * the state in a backend-local data structure.
                              17372                 :  */
                              17373                 : 
                              17374                 : /*
 7454 tgl                     17375 EUB             :  * Register a newly-created relation's ON COMMIT action.
                              17376                 :  */
 7456 bruce                   17377 ECB             : void
 7454 tgl                     17378 CBC          80 : register_on_commit_action(Oid relid, OnCommitAction action)
                              17379                 : {
 7188 bruce                   17380 ECB             :     OnCommitItem *oc;
 7454 tgl                     17381                 :     MemoryContext oldcxt;
 7456 bruce                   17382                 : 
                              17383                 :     /*
                              17384                 :      * We needn't bother registering the relation unless there is an ON COMMIT
                              17385                 :      * action we need to take.
                              17386                 :      */
 7454 tgl                     17387 GIC          80 :     if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
 7456 bruce                   17388 CBC          12 :         return;
                              17389                 : 
 7454 tgl                     17390 GIC          68 :     oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
                              17391                 : 
                              17392              68 :     oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
                              17393              68 :     oc->relid = relid;
                              17394              68 :     oc->oncommit = action;
 6779                         17395              68 :     oc->creating_subid = GetCurrentSubTransactionId();
                              17396              68 :     oc->deleting_subid = InvalidSubTransactionId;
                              17397                 : 
                              17398                 :     /*
                              17399                 :      * We use lcons() here so that ON COMMIT actions are processed in reverse
                              17400                 :      * order of registration.  That might not be essential but it seems
 1362 tgl                     17401 ECB             :      * reasonable.
 1362 tgl                     17402 EUB             :      */
 7454 tgl                     17403 GIC          68 :     on_commits = lcons(oc, on_commits);
 7456 bruce                   17404 ECB             : 
 7454 tgl                     17405 GIC          68 :     MemoryContextSwitchTo(oldcxt);
 7454 tgl                     17406 ECB             : }
 7456 bruce                   17407                 : 
 7454 tgl                     17408 EUB             : /*
                              17409                 :  * Unregister any ON COMMIT action when a relation is deleted.
                              17410                 :  *
                              17411                 :  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
 7454 tgl                     17412 ECB             :  */
                              17413                 : void
 7454 tgl                     17414 CBC       19167 : remove_on_commit_action(Oid relid)
                              17415                 : {
 6892 neilc                   17416 ECB             :     ListCell   *l;
 7456 bruce                   17417                 : 
 7454 tgl                     17418 CBC       19231 :     foreach(l, on_commits)
                              17419                 :     {
 7188 bruce                   17420 GIC         126 :         OnCommitItem *oc = (OnCommitItem *) lfirst(l);
 7456 bruce                   17421 ECB             : 
 7454 tgl                     17422 GIC         126 :         if (oc->relid == relid)
                              17423                 :         {
 6779                         17424              62 :             oc->deleting_subid = GetCurrentSubTransactionId();
 7454 tgl                     17425 CBC          62 :             break;
 7456 bruce                   17426 ECB             :         }
                              17427                 :     }
 7456 bruce                   17428 GIC       19167 : }
 7456 bruce                   17429 ECB             : 
                              17430                 : /*
                              17431                 :  * Perform ON COMMIT actions.
                              17432                 :  *
                              17433                 :  * This is invoked just before actually committing, since it's possible
 7454 tgl                     17434                 :  * to encounter errors.
 7456 bruce                   17435                 :  */
                              17436                 : void
 7454 tgl                     17437 GBC      465920 : PreCommit_on_commit_actions(void)
                              17438                 : {
 6892 neilc                   17439 ECB             :     ListCell   *l;
 6646 tgl                     17440 GIC      465920 :     List       *oids_to_truncate = NIL;
 1612 michael                 17441          465920 :     List       *oids_to_drop = NIL;
                              17442                 : 
 7454 tgl                     17443 CBC      466275 :     foreach(l, on_commits)
                              17444                 :     {
 7188 bruce                   17445 GIC         355 :         OnCommitItem *oc = (OnCommitItem *) lfirst(l);
 7456 bruce                   17446 ECB             : 
                              17447                 :         /* Ignore entry if already dropped in this xact */
 6779 tgl                     17448 GIC         355 :         if (oc->deleting_subid != InvalidSubTransactionId)
 7454                         17449              34 :             continue;
                              17450                 : 
                              17451             321 :         switch (oc->oncommit)
 7454 tgl                     17452 ECB             :         {
 7454 tgl                     17453 UIC           0 :             case ONCOMMIT_NOOP:
 7454 tgl                     17454 ECB             :             case ONCOMMIT_PRESERVE_ROWS:
                              17455                 :                 /* Do nothing (there shouldn't be such entries, actually) */
 7454 tgl                     17456 UIC           0 :                 break;
 7454 tgl                     17457 CBC         299 :             case ONCOMMIT_DELETE_ROWS:
                              17458                 : 
 3722 heikki.linnakangas      17459 ECB             :                 /*
                              17460                 :                  * If this transaction hasn't accessed any temporary
                              17461                 :                  * relations, we can skip truncating ON COMMIT DELETE ROWS
                              17462                 :                  * tables, as they must still be empty.
                              17463                 :                  */
 1534 michael                 17464 GIC         299 :                 if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
 3722 heikki.linnakangas      17465             200 :                     oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
 7454 tgl                     17466             299 :                 break;
                              17467              22 :             case ONCOMMIT_DROP:
 1612 michael                 17468 CBC          22 :                 oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
 1612 michael                 17469 GIC          22 :                 break;
                              17470                 :         }
                              17471                 :     }
                              17472                 : 
                              17473                 :     /*
                              17474                 :      * Truncate relations before dropping so that all dependencies between
                              17475                 :      * relations are removed after they are worked on.  Doing it like this
                              17476                 :      * might be a waste as it is possible that a relation being truncated will
                              17477                 :      * be dropped anyway due to its parent being dropped, but this makes the
                              17478                 :      * code more robust because of not having to re-check that the relation
                              17479                 :      * exists at truncation time.
                              17480                 :      */
 6646 tgl                     17481 CBC      465920 :     if (oids_to_truncate != NIL)
 6646 tgl                     17482 GIC         167 :         heap_truncate(oids_to_truncate);
 1608 michael                 17483 ECB             : 
 1612 michael                 17484 GIC      465917 :     if (oids_to_drop != NIL)
                              17485                 :     {
 1612 michael                 17486 CBC          19 :         ObjectAddresses *targetObjects = new_object_addresses();
 1612 michael                 17487 EUB             : 
 1612 michael                 17488 GIC          41 :         foreach(l, oids_to_drop)
                              17489                 :         {
                              17490                 :             ObjectAddress object;
                              17491                 : 
                              17492              22 :             object.classId = RelationRelationId;
 1612 michael                 17493 CBC          22 :             object.objectId = lfirst_oid(l);
                              17494              22 :             object.objectSubId = 0;
 1612 michael                 17495 ECB             : 
 1612 michael                 17496 GBC          22 :             Assert(!object_address_present(&object, targetObjects));
                              17497                 : 
 1612 michael                 17498 GIC          22 :             add_exact_object_address(&object, targetObjects);
                              17499                 :         }
                              17500                 : 
                              17501                 :         /*
                              17502                 :          * Since this is an automatic drop, rather than one directly initiated
                              17503                 :          * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
 1612 michael                 17504 ECB             :          */
 1612 michael                 17505 GIC          19 :         performMultipleDeletions(targetObjects, DROP_CASCADE,
                              17506                 :                                  PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY);
 1612 michael                 17507 ECB             : 
                              17508                 : #ifdef USE_ASSERT_CHECKING
                              17509                 : 
                              17510                 :         /*
                              17511                 :          * Note that table deletion will call remove_on_commit_action, so the
                              17512                 :          * entry should get marked as deleted.
                              17513                 :          */
 1612 michael                 17514 GIC          66 :         foreach(l, on_commits)
                              17515                 :         {
                              17516              47 :             OnCommitItem *oc = (OnCommitItem *) lfirst(l);
                              17517                 : 
 1612 michael                 17518 CBC          47 :             if (oc->oncommit != ONCOMMIT_DROP)
 1612 michael                 17519 GIC          25 :                 continue;
                              17520                 : 
                              17521              22 :             Assert(oc->deleting_subid != InvalidSubTransactionId);
                              17522                 :         }
 1612 michael                 17523 ECB             : #endif
                              17524                 :     }
 7456 bruce                   17525 CBC      465917 : }
                              17526                 : 
                              17527                 : /*
 7454 tgl                     17528 ECB             :  * Post-commit or post-abort cleanup for ON COMMIT management.
                              17529                 :  *
                              17530                 :  * All we do here is remove no-longer-needed OnCommitItem entries.
                              17531                 :  *
                              17532                 :  * During commit, remove entries that were deleted during this transaction;
                              17533                 :  * during abort, remove those created during this transaction.
                              17534                 :  */
                              17535                 : void
 6779 tgl                     17536 GIC      485839 : AtEOXact_on_commit_actions(bool isCommit)
                              17537                 : {
                              17538                 :     ListCell   *cur_item;
                              17539                 : 
 1364                         17540          486209 :     foreach(cur_item, on_commits)
                              17541                 :     {
 6892 neilc                   17542             370 :         OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
                              17543                 : 
 6779 tgl                     17544             421 :         if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
                              17545              51 :             oc->creating_subid != InvalidSubTransactionId)
                              17546                 :         {
 6892 neilc                   17547 ECB             :             /* cur_item must be removed */
 1364 tgl                     17548 GIC          68 :             on_commits = foreach_delete_current(on_commits, cur_item);
 7454                         17549              68 :             pfree(oc);
                              17550                 :         }
                              17551                 :         else
                              17552                 :         {
                              17553                 :             /* cur_item must be preserved */
 6779                         17554             302 :             oc->creating_subid = InvalidSubTransactionId;
                              17555             302 :             oc->deleting_subid = InvalidSubTransactionId;
                              17556                 :         }
                              17557                 :     }
 6856                         17558          485839 : }
 6856 tgl                     17559 ECB             : 
                              17560                 : /*
 6856 tgl                     17561 EUB             :  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
                              17562                 :  *
                              17563                 :  * During subabort, we can immediately remove entries created during this
                              17564                 :  * subtransaction.  During subcommit, just relabel entries marked during
                              17565                 :  * this subtransaction as being the parent's responsibility.
                              17566                 :  */
                              17567                 : void
 6779 tgl                     17568 CBC        8785 : AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
 6779 tgl                     17569 ECB             :                               SubTransactionId parentSubid)
                              17570                 : {
 6797 bruce                   17571                 :     ListCell   *cur_item;
 6856 tgl                     17572                 : 
 1364 tgl                     17573 CBC        8785 :     foreach(cur_item, on_commits)
 6856 tgl                     17574 ECB             :     {
 6856 tgl                     17575 UIC           0 :         OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
 6856 tgl                     17576 ECB             : 
 6779 tgl                     17577 LBC           0 :         if (!isCommit && oc->creating_subid == mySubid)
                              17578                 :         {
                              17579                 :             /* cur_item must be removed */
 1364 tgl                     17580 UIC           0 :             on_commits = foreach_delete_current(on_commits, cur_item);
 6856                         17581               0 :             pfree(oc);
                              17582                 :         }
                              17583                 :         else
 6856 tgl                     17584 ECB             :         {
                              17585                 :             /* cur_item must be preserved */
 6779 tgl                     17586 UBC           0 :             if (oc->creating_subid == mySubid)
 6779 tgl                     17587 UIC           0 :                 oc->creating_subid = parentSubid;
                              17588               0 :             if (oc->deleting_subid == mySubid)
                              17589               0 :                 oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
                              17590                 :         }
                              17591                 :     }
 7456 bruce                   17592 GIC        8785 : }
                              17593                 : 
                              17594                 : /*
                              17595                 :  * This is intended as a callback for RangeVarGetRelidExtended().  It allows
                              17596                 :  * the relation to be locked only if (1) it's a plain or partitioned table,
  372 alvherre                17597 ECB             :  * materialized view, or TOAST table and (2) the current user is the owner (or
                              17598                 :  * the superuser) or has been granted MAINTAIN.  This meets the
                              17599                 :  * permission-checking needs of CLUSTER, REINDEX TABLE, and REFRESH
                              17600                 :  * MATERIALIZED VIEW; we expose it here so that it can be used by all.
                              17601                 :  */
                              17602                 : void
  117 jdavis                  17603 GNC         437 : RangeVarCallbackMaintainsTable(const RangeVar *relation,
                              17604                 :                                Oid relId, Oid oldRelId, void *arg)
                              17605                 : {
                              17606                 :     char        relkind;
                              17607                 : 
 4127 rhaas                   17608 ECB             :     /* Nothing to do if the relation was not found. */
 4127 rhaas                   17609 GIC         437 :     if (!OidIsValid(relId))
                              17610               3 :         return;
                              17611                 : 
 4127 rhaas                   17612 ECB             :     /*
                              17613                 :      * If the relation does exist, check whether it's an index.  But note that
 3955 bruce                   17614                 :      * the relation might have been dropped between the time we did the name
                              17615                 :      * lookup and now.  In that case, there's nothing to do.
 4127 rhaas                   17616                 :      */
 4127 rhaas                   17617 GIC         434 :     relkind = get_rel_relkind(relId);
                              17618             434 :     if (!relkind)
 4127 rhaas                   17619 UIC           0 :         return;
 3689 kgrittn                 17620 GIC         434 :     if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
 2314 rhaas                   17621              50 :         relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
 4127 rhaas                   17622 CBC          14 :         ereport(ERROR,
                              17623                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17624                 :                  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
 4127 rhaas                   17625 ECB             : 
                              17626                 :     /* Check permissions */
   86 jdavis                  17627 GNC         420 :     if (pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN) != ACLCHECK_OK &&
                              17628              12 :         !has_partition_ancestor_privs(relId, GetUserId(), ACL_MAINTAIN))
  117                         17629              12 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TABLE,
                              17630              12 :                        relation->relname);
                              17631                 : }
                              17632                 : 
                              17633                 : /*
                              17634                 :  * If relid is a partition, returns whether userid has any of the privileges
                              17635                 :  * specified in acl on any of its ancestors.  Otherwise, returns false.
                              17636                 :  */
                              17637                 : bool
   86                         17638             277 : has_partition_ancestor_privs(Oid relid, Oid userid, AclMode acl)
                              17639                 : {
                              17640                 :     List       *ancestors;
                              17641                 :     ListCell   *lc;
                              17642                 : 
                              17643             277 :     if (!get_rel_relispartition(relid))
                              17644             113 :         return false;
                              17645                 : 
                              17646             164 :     ancestors = get_partition_ancestors(relid);
                              17647             218 :     foreach(lc, ancestors)
                              17648                 :     {
                              17649             164 :         Oid         ancestor = lfirst_oid(lc);
                              17650                 : 
                              17651             328 :         if (OidIsValid(ancestor) &&
                              17652             164 :             pg_class_aclcheck(ancestor, userid, acl) == ACLCHECK_OK)
                              17653             110 :             return true;
                              17654                 :     }
                              17655                 : 
                              17656              54 :     return false;
                              17657                 : }
   86 jdavis                  17658 ECB             : 
                              17659                 : /*
 1703 michael                 17660                 :  * Callback to RangeVarGetRelidExtended() for TRUNCATE processing.
                              17661                 :  */
                              17662                 : static void
 1703 michael                 17663 GIC         809 : RangeVarCallbackForTruncate(const RangeVar *relation,
                              17664                 :                             Oid relId, Oid oldRelId, void *arg)
                              17665                 : {
                              17666                 :     HeapTuple   tuple;
                              17667                 : 
                              17668                 :     /* Nothing to do if the relation was not found. */
                              17669             809 :     if (!OidIsValid(relId))
 1703 michael                 17670 LBC           0 :         return;
 1703 michael                 17671 ECB             : 
 1703 michael                 17672 GIC         809 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
                              17673             809 :     if (!HeapTupleIsValid(tuple))   /* should not happen */
 1703 michael                 17674 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relId);
                              17675                 : 
 1703 michael                 17676 GIC         809 :     truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
 1164 fujii                   17677             807 :     truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
                              17678                 : 
 1703 michael                 17679 CBC         791 :     ReleaseSysCache(tuple);
                              17680                 : }
                              17681                 : 
                              17682                 : /*
 3338 rhaas                   17683 ECB             :  * Callback to RangeVarGetRelidExtended(), similar to
                              17684                 :  * RangeVarCallbackOwnsTable() but without checks on the type of the relation.
                              17685                 :  */
                              17686                 : void
 3338 rhaas                   17687 CBC        6659 : RangeVarCallbackOwnsRelation(const RangeVar *relation,
                              17688                 :                              Oid relId, Oid oldRelId, void *arg)
                              17689                 : {
                              17690                 :     HeapTuple   tuple;
                              17691                 : 
                              17692                 :     /* Nothing to do if the relation was not found. */
 3338 rhaas                   17693 GIC        6659 :     if (!OidIsValid(relId))
 3338 rhaas                   17694 CBC           7 :         return;
                              17695                 : 
 3338 rhaas                   17696 GIC        6652 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
 2118 tgl                     17697            6652 :     if (!HeapTupleIsValid(tuple))   /* should not happen */
 3338 rhaas                   17698 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relId);
                              17699                 : 
  147 peter                   17700 GNC        6652 :     if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
 1954 peter_e                 17701 GIC           3 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)),
 3338 rhaas                   17702               3 :                        relation->relname);
                              17703                 : 
 3338 rhaas                   17704 CBC       13238 :     if (!allowSystemTableMods &&
                              17705            6589 :         IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
 3338 rhaas                   17706 GIC           1 :         ereport(ERROR,
                              17707                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                              17708                 :                  errmsg("permission denied: \"%s\" is a system catalog",
 3338 rhaas                   17709 ECB             :                         relation->relname)));
                              17710                 : 
 3338 rhaas                   17711 CBC        6648 :     ReleaseSysCache(tuple);
                              17712                 : }
                              17713                 : 
 4111 rhaas                   17714 ECB             : /*
                              17715                 :  * Common RangeVarGetRelid callback for rename, set schema, and alter table
                              17716                 :  * processing.
                              17717                 :  */
                              17718                 : static void
 4111 rhaas                   17719 CBC       45540 : RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
                              17720                 :                                  void *arg)
                              17721                 : {
 3955 bruce                   17722           45540 :     Node       *stmt = (Node *) arg;
                              17723                 :     ObjectType  reltype;
                              17724                 :     HeapTuple   tuple;
                              17725                 :     Form_pg_class classform;
                              17726                 :     AclResult   aclresult;
 3955 bruce                   17727 ECB             :     char        relkind;
 4111 rhaas                   17728                 : 
 4111 rhaas                   17729 GBC       45540 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
 4111 rhaas                   17730 GIC       45540 :     if (!HeapTupleIsValid(tuple))
 3955 bruce                   17731             110 :         return;                 /* concurrently dropped */
 4111 rhaas                   17732           45430 :     classform = (Form_pg_class) GETSTRUCT(tuple);
                              17733           45430 :     relkind = classform->relkind;
                              17734                 : 
                              17735                 :     /* Must own relation. */
  147 peter                   17736 GNC       45430 :     if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
 1954 peter_e                 17737 GIC          30 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
 4111 rhaas                   17738 ECB             : 
                              17739                 :     /* No system table modifications unless explicitly allowed. */
 3419 rhaas                   17740 GIC       45400 :     if (!allowSystemTableMods && IsSystemClass(relid, classform))
 4111                         17741              14 :         ereport(ERROR,
 4111 rhaas                   17742 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                              17743                 :                  errmsg("permission denied: \"%s\" is a system catalog",
                              17744                 :                         rv->relname)));
                              17745                 : 
                              17746                 :     /*
                              17747                 :      * Extract the specified relation type from the statement parse tree.
                              17748                 :      *
                              17749                 :      * Also, for ALTER .. RENAME, check permissions: the user must (still)
                              17750                 :      * have CREATE rights on the containing namespace.
                              17751                 :      */
 4111 rhaas                   17752 GIC       45386 :     if (IsA(stmt, RenameStmt))
                              17753                 :     {
  147 peter                   17754 GNC         247 :         aclresult = object_aclcheck(NamespaceRelationId, classform->relnamespace,
                              17755                 :                                           GetUserId(), ACL_CREATE);
 4111 rhaas                   17756 CBC         247 :         if (aclresult != ACLCHECK_OK)
 1954 peter_e                 17757 UIC           0 :             aclcheck_error(aclresult, OBJECT_SCHEMA,
 4111 rhaas                   17758               0 :                            get_namespace_name(classform->relnamespace));
 4111 rhaas                   17759 GIC         247 :         reltype = ((RenameStmt *) stmt)->renameType;
                              17760                 :     }
                              17761           45139 :     else if (IsA(stmt, AlterObjectSchemaStmt))
                              17762              42 :         reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
                              17763                 : 
                              17764           45097 :     else if (IsA(stmt, AlterTableStmt))
 1002 michael                 17765 CBC       45097 :         reltype = ((AlterTableStmt *) stmt)->objtype;
                              17766                 :     else
                              17767                 :     {
 4111 rhaas                   17768 UIC           0 :         elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
                              17769                 :         reltype = OBJECT_TABLE; /* placate compiler */
 4111 rhaas                   17770 ECB             :     }
                              17771                 : 
                              17772                 :     /*
 3955 bruce                   17773                 :      * For compatibility with prior releases, we allow ALTER TABLE to be used
                              17774                 :      * with most other types of relations (but not composite types). We allow
                              17775                 :      * similar flexibility for ALTER INDEX in the case of RENAME, but not
                              17776                 :      * otherwise.  Otherwise, the user must select the correct form of the
                              17777                 :      * command for the relation at issue.
                              17778                 :      */
 4111 rhaas                   17779 CBC       45386 :     if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
 4111 rhaas                   17780 LBC           0 :         ereport(ERROR,
                              17781                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17782                 :                  errmsg("\"%s\" is not a sequence", rv->relname)));
                              17783                 : 
 4111 rhaas                   17784 CBC       45386 :     if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
 4111 rhaas                   17785 LBC           0 :         ereport(ERROR,
 4111 rhaas                   17786 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17787                 :                  errmsg("\"%s\" is not a view", rv->relname)));
                              17788                 : 
 3689 kgrittn                 17789 CBC       45386 :     if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
 3689 kgrittn                 17790 UIC           0 :         ereport(ERROR,
 3689 kgrittn                 17791 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17792                 :                  errmsg("\"%s\" is not a materialized view", rv->relname)));
                              17793                 : 
 4111 rhaas                   17794 GIC       45386 :     if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
 4111 rhaas                   17795 LBC           0 :         ereport(ERROR,
 4111 rhaas                   17796 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17797                 :                  errmsg("\"%s\" is not a foreign table", rv->relname)));
                              17798                 : 
 4111 rhaas                   17799 GIC       45386 :     if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
 4111 rhaas                   17800 UIC           0 :         ereport(ERROR,
                              17801                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17802                 :                  errmsg("\"%s\" is not a composite type", rv->relname)));
                              17803                 : 
 1906 alvherre                17804 CBC       45386 :     if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
                              17805                 :         relkind != RELKIND_PARTITIONED_INDEX
 4111 rhaas                   17806 GIC          18 :         && !IsA(stmt, RenameStmt))
                              17807               3 :         ereport(ERROR,
                              17808                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17809                 :                  errmsg("\"%s\" is not an index", rv->relname)));
                              17810                 : 
                              17811                 :     /*
 4111 rhaas                   17812 ECB             :      * Don't allow ALTER TABLE on composite types. We want people to use ALTER
                              17813                 :      * TYPE for that.
                              17814                 :      */
 4111 rhaas                   17815 CBC       45383 :     if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
 4111 rhaas                   17816 UBC           0 :         ereport(ERROR,
 4111 rhaas                   17817 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17818                 :                  errmsg("\"%s\" is a composite type", rv->relname),
                              17819                 :                  errhint("Use ALTER TYPE instead.")));
                              17820                 : 
                              17821                 :     /*
 3955 bruce                   17822                 :      * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
                              17823                 :      * to a different schema, such as indexes and TOAST tables.
                              17824                 :      */
  640 peter                   17825 GIC       45383 :     if (IsA(stmt, AlterObjectSchemaStmt))
                              17826                 :     {
                              17827              42 :         if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX)
  640 peter                   17828 UIC           0 :             ereport(ERROR,
                              17829                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  640 peter                   17830 ECB             :                      errmsg("cannot change schema of index \"%s\"",
                              17831                 :                             rv->relname),
                              17832                 :                      errhint("Change the schema of the table instead.")));
  640 peter                   17833 GIC          42 :         else if (relkind == RELKIND_COMPOSITE_TYPE)
  640 peter                   17834 LBC           0 :             ereport(ERROR,
                              17835                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  640 peter                   17836 EUB             :                      errmsg("cannot change schema of composite type \"%s\"",
                              17837                 :                             rv->relname),
                              17838                 :                      errhint("Use ALTER TYPE instead.")));
  640 peter                   17839 GIC          42 :         else if (relkind == RELKIND_TOASTVALUE)
  640 peter                   17840 UIC           0 :             ereport(ERROR,
                              17841                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17842                 :                      errmsg("cannot change schema of TOAST table \"%s\"",
  640 peter                   17843 ECB             :                             rv->relname),
                              17844                 :                      errhint("Change the schema of the table instead.")));
                              17845                 :     }
                              17846                 : 
 4111 rhaas                   17847 GIC       45383 :     ReleaseSysCache(tuple);
 4111 rhaas                   17848 ECB             : }
 2314                         17849                 : 
                              17850                 : /*
                              17851                 :  * Transform any expressions present in the partition key
                              17852                 :  *
                              17853                 :  * Returns a transformed PartitionSpec.
 2314 rhaas                   17854 EUB             :  */
                              17855                 : static PartitionSpec *
  157 alvherre                17856 GNC        2163 : transformPartitionSpec(Relation rel, PartitionSpec *partspec)
 2314 rhaas                   17857 ECB             : {
                              17858                 :     PartitionSpec *newspec;
 2308                         17859                 :     ParseState *pstate;
                              17860                 :     ParseNamespaceItem *nsitem;
                              17861                 :     ListCell   *l;
                              17862                 : 
 2298 peter_e                 17863 GIC        2163 :     newspec = makeNode(PartitionSpec);
 2314 rhaas                   17864 ECB             : 
 2314 rhaas                   17865 CBC        2163 :     newspec->strategy = partspec->strategy;
 2314 rhaas                   17866 GIC        2163 :     newspec->partParams = NIL;
 2142 tgl                     17867            2163 :     newspec->location = partspec->location;
                              17868                 : 
 2142 tgl                     17869 ECB             :     /* Check valid number of columns for strategy */
  157 alvherre                17870 GNC        3261 :     if (partspec->strategy == PARTITION_STRATEGY_LIST &&
 2142 tgl                     17871 CBC        1098 :         list_length(partspec->partParams) != 1)
 2142 tgl                     17872 GIC           3 :         ereport(ERROR,
                              17873                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 2142 tgl                     17874 ECB             :                  errmsg("cannot use \"list\" partition strategy with more than one column")));
                              17875                 : 
 2314 rhaas                   17876                 :     /*
                              17877                 :      * Create a dummy ParseState and insert the target relation as its sole
                              17878                 :      * rangetable entry.  We need a ParseState for transformExpr.
                              17879                 :      */
 2314 rhaas                   17880 GIC        2160 :     pstate = make_parsestate(NULL);
 1193 tgl                     17881            2160 :     nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
                              17882                 :                                            NULL, false, true);
                              17883            2160 :     addNSItemToQuery(pstate, nsitem, true, true, true);
                              17884                 : 
                              17885                 :     /* take care of any partition expressions */
 2314 rhaas                   17886 CBC        4500 :     foreach(l, partspec->partParams)
                              17887                 :     {
  629 peter                   17888            2352 :         PartitionElem *pelem = lfirst_node(PartitionElem, l);
                              17889                 : 
 2314 rhaas                   17890 GIC        2352 :         if (pelem->expr)
 2314 rhaas                   17891 ECB             :         {
                              17892                 :             /* Copy, to avoid scribbling on the input */
 2142 tgl                     17893 GIC         143 :             pelem = copyObject(pelem);
                              17894                 : 
 2314 rhaas                   17895 ECB             :             /* Now do parse transformation of the expression */
 2314 rhaas                   17896 CBC         143 :             pelem->expr = transformExpr(pstate, pelem->expr,
                              17897                 :                                         EXPR_KIND_PARTITION_EXPRESSION);
                              17898                 : 
                              17899                 :             /* we have to fix its collations too */
 2314 rhaas                   17900 GIC         131 :             assign_expr_collations(pstate, pelem->expr);
                              17901                 :         }
                              17902                 : 
                              17903            2340 :         newspec->partParams = lappend(newspec->partParams, pelem);
                              17904                 :     }
                              17905                 : 
 2314 rhaas                   17906 CBC        2148 :     return newspec;
                              17907                 : }
                              17908                 : 
                              17909                 : /*
                              17910                 :  * Compute per-partition-column information from a list of PartitionElems.
                              17911                 :  * Expressions in the PartitionElems must be parse-analyzed already.
                              17912                 :  */
                              17913                 : static void
 1691 peter_e                 17914 GIC        2148 : ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
                              17915                 :                       List **partexprs, Oid *partopclass, Oid *partcollation,
                              17916                 :                       PartitionStrategy strategy)
                              17917                 : {
                              17918                 :     int         attn;
 2314 rhaas                   17919 ECB             :     ListCell   *lc;
                              17920                 :     Oid         am_oid;
                              17921                 : 
 2314 rhaas                   17922 GIC        2148 :     attn = 0;
                              17923            4446 :     foreach(lc, partParams)
                              17924                 :     {
  629 peter                   17925 CBC        2340 :         PartitionElem *pelem = lfirst_node(PartitionElem, lc);
                              17926                 :         Oid         atttype;
                              17927                 :         Oid         attcollation;
                              17928                 : 
 2314 rhaas                   17929 GIC        2340 :         if (pelem->name != NULL)
                              17930                 :         {
 2314 rhaas                   17931 ECB             :             /* Simple attribute reference */
                              17932                 :             HeapTuple   atttuple;
                              17933                 :             Form_pg_attribute attform;
                              17934                 : 
 2142 tgl                     17935 GIC        2209 :             atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
 2142 tgl                     17936 CBC        2209 :                                              pelem->name);
 2314 rhaas                   17937 GIC        2209 :             if (!HeapTupleIsValid(atttuple))
                              17938               6 :                 ereport(ERROR,
                              17939                 :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
 2118 tgl                     17940 ECB             :                          errmsg("column \"%s\" named in partition key does not exist",
 1691 peter_e                 17941                 :                                 pelem->name),
                              17942                 :                          parser_errposition(pstate, pelem->location)));
 2314 rhaas                   17943 CBC        2203 :             attform = (Form_pg_attribute) GETSTRUCT(atttuple);
 2314 rhaas                   17944 ECB             : 
 2314 rhaas                   17945 GIC        2203 :             if (attform->attnum <= 0)
                              17946               3 :                 ereport(ERROR,
 2142 tgl                     17947 ECB             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              17948                 :                          errmsg("cannot use system column \"%s\" in partition key",
                              17949                 :                                 pelem->name),
 1691 peter_e                 17950                 :                          parser_errposition(pstate, pelem->location)));
                              17951                 : 
                              17952                 :             /*
 1471 peter                   17953 EUB             :              * Generated columns cannot work: They are computed after BEFORE
                              17954                 :              * triggers, but partition routing is done before all triggers.
                              17955                 :              */
 1471 peter                   17956 GIC        2200 :             if (attform->attgenerated)
                              17957               3 :                 ereport(ERROR,
 1471 peter                   17958 ECB             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              17959                 :                          errmsg("cannot use generated column in partition key"),
                              17960                 :                          errdetail("Column \"%s\" is a generated column.",
                              17961                 :                                    pelem->name),
                              17962                 :                          parser_errposition(pstate, pelem->location)));
                              17963                 : 
 2314 rhaas                   17964 GIC        2197 :             partattrs[attn] = attform->attnum;
                              17965            2197 :             atttype = attform->atttypid;
                              17966            2197 :             attcollation = attform->attcollation;
 2314 rhaas                   17967 CBC        2197 :             ReleaseSysCache(atttuple);
                              17968                 :         }
                              17969                 :         else
 2314 rhaas                   17970 ECB             :         {
                              17971                 :             /* Expression */
 2314 rhaas                   17972 GIC         131 :             Node       *expr = pelem->expr;
 1203 tgl                     17973 ECB             :             char        partattname[16];
                              17974                 : 
 2314 rhaas                   17975 CBC         131 :             Assert(expr != NULL);
                              17976             131 :             atttype = exprType(expr);
 2314 rhaas                   17977 GIC         131 :             attcollation = exprCollation(expr);
                              17978                 : 
                              17979                 :             /*
                              17980                 :              * The expression must be of a storable type (e.g., not RECORD).
                              17981                 :              * The test is the same as for whether a table column is of a safe
                              17982                 :              * type (which is why we needn't check for the non-expression
                              17983                 :              * case).
                              17984                 :              */
 1203 tgl                     17985             131 :             snprintf(partattname, sizeof(partattname), "%d", attn + 1);
                              17986             131 :             CheckAttributeType(partattname,
                              17987                 :                                atttype, attcollation,
                              17988                 :                                NIL, CHKATYPE_IS_PARTKEY);
                              17989                 : 
                              17990                 :             /*
 2314 rhaas                   17991 ECB             :              * Strip any top-level COLLATE clause.  This ensures that we treat
                              17992                 :              * "x COLLATE y" and "(x COLLATE y)" alike.
                              17993                 :              */
 2314 rhaas                   17994 GIC         125 :             while (IsA(expr, CollateExpr))
 2314 rhaas                   17995 UIC           0 :                 expr = (Node *) ((CollateExpr *) expr)->arg;
                              17996                 : 
 2314 rhaas                   17997 GIC         125 :             if (IsA(expr, Var) &&
 2142 tgl                     17998               6 :                 ((Var *) expr)->varattno > 0)
                              17999                 :             {
 2314 rhaas                   18000 ECB             :                 /*
                              18001                 :                  * User wrote "(column)" or "(column COLLATE something)".
                              18002                 :                  * Treat it like simple attribute anyway.
                              18003                 :                  */
 2314 rhaas                   18004 GIC           3 :                 partattrs[attn] = ((Var *) expr)->varattno;
 2314 rhaas                   18005 ECB             :             }
                              18006                 :             else
                              18007                 :             {
 2308 rhaas                   18008 CBC         122 :                 Bitmapset  *expr_attrs = NULL;
 2142 tgl                     18009 ECB             :                 int         i;
                              18010                 : 
 2308 rhaas                   18011 GIC         122 :                 partattrs[attn] = 0;    /* marks the column as expression */
 2314                         18012             122 :                 *partexprs = lappend(*partexprs, expr);
                              18013                 : 
                              18014                 :                 /*
                              18015                 :                  * Try to simplify the expression before checking for
 2142 tgl                     18016 ECB             :                  * mutability.  The main practical value of doing it in this
                              18017                 :                  * order is that an inline-able SQL-language function will be
                              18018                 :                  * accepted if its expansion is immutable, whether or not the
                              18019                 :                  * function itself is marked immutable.
                              18020                 :                  *
                              18021                 :                  * Note that expression_planner does not change the passed in
                              18022                 :                  * expression destructively and we have already saved the
                              18023                 :                  * expression to be stored into the catalog above.
                              18024                 :                  */
 2314 rhaas                   18025 GIC         122 :                 expr = (Node *) expression_planner((Expr *) expr);
                              18026                 : 
 2314 rhaas                   18027 ECB             :                 /*
                              18028                 :                  * Partition expression cannot contain mutable functions,
                              18029                 :                  * because a given row must always map to the same partition
                              18030                 :                  * as long as there is no change in the partition boundary
                              18031                 :                  * structure.
                              18032                 :                  */
 2314 rhaas                   18033 CBC         122 :                 if (contain_mutable_functions(expr))
 2314 rhaas                   18034 GIC           3 :                     ereport(ERROR,
 2314 rhaas                   18035 ECB             :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18036                 :                              errmsg("functions in partition key expression must be marked IMMUTABLE")));
                              18037                 : 
                              18038                 :                 /*
                              18039                 :                  * transformPartitionSpec() should have already rejected
                              18040                 :                  * subqueries, aggregates, window functions, and SRFs, based
 2308                         18041                 :                  * on the EXPR_KIND_ for partition expressions.
                              18042                 :                  */
                              18043                 : 
                              18044                 :                 /*
                              18045                 :                  * Cannot allow system column references, since that would
                              18046                 :                  * make partition routing impossible: their values won't be
                              18047                 :                  * known yet when we need to do that.
                              18048                 :                  */
 2314 rhaas                   18049 GIC         119 :                 pull_varattnos(expr, 1, &expr_attrs);
 2142 tgl                     18050 CBC         952 :                 for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
                              18051                 :                 {
 2142 tgl                     18052 GIC         833 :                     if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
 2142 tgl                     18053 ECB             :                                       expr_attrs))
 2142 tgl                     18054 LBC           0 :                         ereport(ERROR,
                              18055                 :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 2142 tgl                     18056 ECB             :                                  errmsg("partition key expressions cannot contain system column references")));
                              18057                 :                 }
                              18058                 : 
                              18059                 :                 /*
                              18060                 :                  * Generated columns cannot work: They are computed after
 1471 peter                   18061                 :                  * BEFORE triggers, but partition routing is done before all
                              18062                 :                  * triggers.
                              18063                 :                  */
 1471 peter                   18064 CBC         119 :                 i = -1;
 1471 peter                   18065 GIC         264 :                 while ((i = bms_next_member(expr_attrs, i)) >= 0)
 1471 peter                   18066 EUB             :                 {
 1418 tgl                     18067 GIC         148 :                     AttrNumber  attno = i + FirstLowInvalidHeapAttributeNumber;
                              18068                 : 
 1201 tgl                     18069 GBC         148 :                     if (attno > 0 &&
 1201 tgl                     18070 CBC         145 :                         TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
 1471 peter                   18071 GIC           3 :                         ereport(ERROR,
                              18072                 :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18073                 :                                  errmsg("cannot use generated column in partition key"),
                              18074                 :                                  errdetail("Column \"%s\" is a generated column.",
                              18075                 :                                            get_attname(RelationGetRelid(rel), attno, false)),
                              18076                 :                                  parser_errposition(pstate, pelem->location)));
 1471 peter                   18077 ECB             :                 }
                              18078                 : 
 2142 tgl                     18079                 :                 /*
                              18080                 :                  * While it is not exactly *wrong* for a partition expression
                              18081                 :                  * to be a constant, it seems better to reject such keys.
                              18082                 :                  */
 2142 tgl                     18083 GIC         116 :                 if (IsA(expr, Const))
                              18084               6 :                     ereport(ERROR,
                              18085                 :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18086                 :                              errmsg("cannot use constant expression as partition key")));
                              18087                 :             }
                              18088                 :         }
                              18089                 : 
                              18090                 :         /*
                              18091                 :          * Apply collation override if any
                              18092                 :          */
 2314 rhaas                   18093            2310 :         if (pelem->collation)
 2314 rhaas                   18094 CBC          15 :             attcollation = get_collation_oid(pelem->collation, false);
 2314 rhaas                   18095 ECB             : 
                              18096                 :         /*
                              18097                 :          * Check we have a collation iff it's a collatable type.  The only
                              18098                 :          * expected failures here are (1) COLLATE applied to a noncollatable
 2308                         18099                 :          * type, or (2) partition expression had an unresolved collation. But
                              18100                 :          * we might as well code this to be a complete consistency check.
 2314                         18101                 :          */
 2314 rhaas                   18102 GIC        2310 :         if (type_is_collatable(atttype))
                              18103                 :         {
                              18104             283 :             if (!OidIsValid(attcollation))
 2314 rhaas                   18105 LBC           0 :                 ereport(ERROR,
 2314 rhaas                   18106 ECB             :                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
                              18107                 :                          errmsg("could not determine which collation to use for partition expression"),
                              18108                 :                          errhint("Use the COLLATE clause to set the collation explicitly.")));
                              18109                 :         }
                              18110                 :         else
                              18111                 :         {
 2314 rhaas                   18112 GIC        2027 :             if (OidIsValid(attcollation))
 2314 rhaas                   18113 UIC           0 :                 ereport(ERROR,
                              18114                 :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              18115                 :                          errmsg("collations are not supported by type %s",
                              18116                 :                                 format_type_be(atttype))));
                              18117                 :         }
 2314 rhaas                   18118 ECB             : 
 2314 rhaas                   18119 GIC        2310 :         partcollation[attn] = attcollation;
                              18120                 : 
                              18121                 :         /*
                              18122                 :          * Identify the appropriate operator class.  For list and range
                              18123                 :          * partitioning, we use a btree operator class; hash partitioning uses
                              18124                 :          * a hash operator class.
                              18125                 :          */
 1977                         18126            2310 :         if (strategy == PARTITION_STRATEGY_HASH)
 1977 rhaas                   18127 CBC         131 :             am_oid = HASH_AM_OID;
                              18128                 :         else
                              18129            2179 :             am_oid = BTREE_AM_OID;
                              18130                 : 
 2314                         18131            2310 :         if (!pelem->opclass)
 2314 rhaas                   18132 ECB             :         {
 1977 rhaas                   18133 GIC        2244 :             partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
 2314 rhaas                   18134 ECB             : 
 2314 rhaas                   18135 GIC        2244 :             if (!OidIsValid(partopclass[attn]))
                              18136                 :             {
 1977                         18137               6 :                 if (strategy == PARTITION_STRATEGY_HASH)
 1977 rhaas                   18138 LBC           0 :                     ereport(ERROR,
                              18139                 :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
                              18140                 :                              errmsg("data type %s has no default operator class for access method \"%s\"",
                              18141                 :                                     format_type_be(atttype), "hash"),
                              18142                 :                              errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
                              18143                 :                 else
 1977 rhaas                   18144 GIC           6 :                     ereport(ERROR,
                              18145                 :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
                              18146                 :                              errmsg("data type %s has no default operator class for access method \"%s\"",
                              18147                 :                                     format_type_be(atttype), "btree"),
                              18148                 :                              errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
 1977 rhaas                   18149 ECB             :             }
                              18150                 :         }
                              18151                 :         else
 2314 rhaas                   18152 GIC          66 :             partopclass[attn] = ResolveOpClass(pelem->opclass,
 2314 rhaas                   18153 ECB             :                                                atttype,
                              18154                 :                                                am_oid == HASH_AM_OID ? "hash" : "btree",
 1977                         18155                 :                                                am_oid);
                              18156                 : 
 2314 rhaas                   18157 CBC        2298 :         attn++;
 2314 rhaas                   18158 ECB             :     }
 2314 rhaas                   18159 GIC        2106 : }
                              18160                 : 
 2061 rhaas                   18161 ECB             : /*
                              18162                 :  * PartConstraintImpliedByRelConstraint
                              18163                 :  *      Do scanrel's existing constraints imply the partition constraint?
                              18164                 :  *
                              18165                 :  * "Existing constraints" include its check constraints and column-level
                              18166                 :  * NOT NULL constraints.  partConstraint describes the partition constraint,
 1857 tgl                     18167                 :  * in implicit-AND form.
 2061 rhaas                   18168                 :  */
                              18169                 : bool
 2061 rhaas                   18170 GIC        1442 : PartConstraintImpliedByRelConstraint(Relation scanrel,
 2061 rhaas                   18171 ECB             :                                      List *partConstraint)
                              18172                 : {
 2061 rhaas                   18173 GIC        1442 :     List       *existConstraint = NIL;
                              18174            1442 :     TupleConstr *constr = RelationGetDescr(scanrel)->constr;
                              18175                 :     int         i;
                              18176                 : 
                              18177            1442 :     if (constr && constr->has_not_null)
                              18178                 :     {
                              18179             312 :         int         natts = scanrel->rd_att->natts;
                              18180                 : 
 2061 rhaas                   18181 CBC        1019 :         for (i = 1; i <= natts; i++)
                              18182                 :         {
 2058 andres                  18183 GIC         707 :             Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
                              18184                 : 
 2061 rhaas                   18185             707 :             if (att->attnotnull && !att->attisdropped)
 2061 rhaas                   18186 ECB             :             {
 2061 rhaas                   18187 GIC         414 :                 NullTest   *ntest = makeNode(NullTest);
 2061 rhaas                   18188 EUB             : 
 2061 rhaas                   18189 GIC         414 :                 ntest->arg = (Expr *) makeVar(1,
 2061 rhaas                   18190 EUB             :                                               i,
                              18191                 :                                               att->atttypid,
                              18192                 :                                               att->atttypmod,
                              18193                 :                                               att->attcollation,
                              18194                 :                                               0);
 2061 rhaas                   18195 GIC         414 :                 ntest->nulltesttype = IS_NOT_NULL;
                              18196                 : 
                              18197                 :                 /*
                              18198                 :                  * argisrow=false is correct even for a composite column,
 2061 rhaas                   18199 EUB             :                  * because attnotnull does not represent a SQL-spec IS NOT
                              18200                 :                  * NULL test in such a case, just IS DISTINCT FROM NULL.
                              18201                 :                  */
 2061 rhaas                   18202 GBC         414 :                 ntest->argisrow = false;
 2061 rhaas                   18203 GIC         414 :                 ntest->location = -1;
                              18204             414 :                 existConstraint = lappend(existConstraint, ntest);
 2061 rhaas                   18205 ECB             :             }
                              18206                 :         }
                              18207                 :     }
                              18208                 : 
 1488 rhaas                   18209 GIC        1442 :     return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
                              18210                 : }
                              18211                 : 
                              18212                 : /*
                              18213                 :  * ConstraintImpliedByRelConstraint
                              18214                 :  *      Do scanrel's existing constraints imply the given constraint?
                              18215                 :  *
 1488 rhaas                   18216 ECB             :  * testConstraint is the constraint to validate. provenConstraint is a
                              18217                 :  * caller-provided list of conditions which this function may assume
                              18218                 :  * to be true. Both provenConstraint and testConstraint must be in
                              18219                 :  * implicit-AND form, must only contain immutable clauses, and must
                              18220                 :  * contain only Vars with varno = 1.
                              18221                 :  */
                              18222                 : bool
 1488 rhaas                   18223 CBC        1995 : ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
                              18224                 : {
 1418 tgl                     18225 GIC        1995 :     List       *existConstraint = list_copy(provenConstraint);
 1488 rhaas                   18226            1995 :     TupleConstr *constr = RelationGetDescr(scanrel)->constr;
                              18227                 :     int         num_check,
                              18228                 :                 i;
                              18229                 : 
 2061 rhaas                   18230 CBC        1995 :     num_check = (constr != NULL) ? constr->num_check : 0;
                              18231            2253 :     for (i = 0; i < num_check; i++)
 2061 rhaas                   18232 EUB             :     {
 2061 rhaas                   18233 ECB             :         Node       *cexpr;
                              18234                 : 
                              18235                 :         /*
                              18236                 :          * If this constraint hasn't been fully validated yet, we must ignore
                              18237                 :          * it here.
                              18238                 :          */
 2061 rhaas                   18239 GIC         258 :         if (!constr->check[i].ccvalid)
 2061 rhaas                   18240 CBC           4 :             continue;
 2061 rhaas                   18241 ECB             : 
 2061 rhaas                   18242 CBC         254 :         cexpr = stringToNode(constr->check[i].ccbin);
 2061 rhaas                   18243 ECB             : 
                              18244                 :         /*
                              18245                 :          * Run each expression through const-simplification and
                              18246                 :          * canonicalization.  It is necessary, because we will be comparing it
                              18247                 :          * to similarly-processed partition constraint expressions, and may
                              18248                 :          * fail to detect valid matches without this.
                              18249                 :          */
 2061 rhaas                   18250 GIC         254 :         cexpr = eval_const_expressions(NULL, cexpr);
 1855 tgl                     18251 CBC         254 :         cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
                              18252                 : 
 2061 rhaas                   18253 GIC         254 :         existConstraint = list_concat(existConstraint,
                              18254             254 :                                       make_ands_implicit((Expr *) cexpr));
                              18255                 :     }
 2061 rhaas                   18256 ECB             : 
 1857 tgl                     18257                 :     /*
                              18258                 :      * Try to make the proof.  Since we are comparing CHECK constraints, we
                              18259                 :      * need to use weak implication, i.e., we assume existConstraint is
 1488 rhaas                   18260                 :      * not-false and try to prove the same for testConstraint.
                              18261                 :      *
 1857 tgl                     18262                 :      * Note that predicate_implied_by assumes its first argument is known
                              18263                 :      * immutable.  That should always be true for both NOT NULL and partition
 1418                         18264                 :      * constraints, so we don't test it here.
 1857                         18265                 :      */
 1488 rhaas                   18266 CBC        1995 :     return predicate_implied_by(testConstraint, existConstraint, true);
                              18267                 : }
                              18268                 : 
 2061 rhaas                   18269 ECB             : /*
                              18270                 :  * QueuePartitionConstraintValidation
                              18271                 :  *
                              18272                 :  * Add an entry to wqueue to have the given partition constraint validated by
                              18273                 :  * Phase 3, for the given relation, and all its children.
                              18274                 :  *
                              18275                 :  * We first verify whether the given constraint is implied by pre-existing
 1824 alvherre                18276                 :  * relation constraints; if it is, there's no need to scan the table to
                              18277                 :  * validate, so don't queue in that case.
                              18278                 :  */
                              18279                 : static void
 1824 alvherre                18280 GIC        1139 : QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
                              18281                 :                                    List *partConstraint,
 1824 alvherre                18282 ECB             :                                    bool validate_default)
 2061 rhaas                   18283 EUB             : {
                              18284                 :     /*
 1824 alvherre                18285 ECB             :      * Based on the table's existing constraints, determine whether or not we
                              18286                 :      * may skip scanning the table.
 2061 rhaas                   18287 EUB             :      */
 2061 rhaas                   18288 GIC        1139 :     if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
 2061 rhaas                   18289 ECB             :     {
 2012 rhaas                   18290 CBC          45 :         if (!validate_default)
 1310 tgl                     18291 GIC          34 :             ereport(DEBUG1,
  781 peter                   18292 ECB             :                     (errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints",
                              18293                 :                                      RelationGetRelationName(scanrel))));
                              18294                 :         else
 1310 tgl                     18295 GIC          11 :             ereport(DEBUG1,
                              18296                 :                     (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
                              18297                 :                                      RelationGetRelationName(scanrel))));
 2061 rhaas                   18298              45 :         return;
                              18299                 :     }
 2061 rhaas                   18300 ECB             : 
                              18301                 :     /*
                              18302                 :      * Constraints proved insufficient. For plain relations, queue a
                              18303                 :      * validation item now; for partitioned tables, recurse to process each
                              18304                 :      * partition.
                              18305                 :      */
 1824 alvherre                18306 CBC        1094 :     if (scanrel->rd_rel->relkind == RELKIND_RELATION)
 2061 rhaas                   18307 ECB             :     {
                              18308                 :         AlteredTableInfo *tab;
                              18309                 : 
 1824 alvherre                18310                 :         /* Grab a work queue entry. */
 1824 alvherre                18311 GBC         909 :         tab = ATGetQueueEntry(wqueue, scanrel);
 1824 alvherre                18312 GIC         909 :         Assert(tab->partition_constraint == NULL);
 1824 alvherre                18313 CBC         909 :         tab->partition_constraint = (Expr *) linitial(partConstraint);
                              18314             909 :         tab->validate_default = validate_default;
 1824 alvherre                18315 ECB             :     }
 1824 alvherre                18316 GIC         185 :     else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
 1824 alvherre                18317 ECB             :     {
  717 alvherre                18318 CBC         161 :         PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true);
 1824 alvherre                18319 ECB             :         int         i;
                              18320                 : 
 1824 alvherre                18321 GIC         334 :         for (i = 0; i < partdesc->nparts; i++)
                              18322                 :         {
                              18323                 :             Relation    part_rel;
 1824 alvherre                18324 ECB             :             List       *thisPartConstraint;
                              18325                 : 
                              18326                 :             /*
                              18327                 :              * This is the minimum lock we need to prevent deadlocks.
                              18328                 :              */
 1539 andres                  18329 GIC         173 :             part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
                              18330                 : 
                              18331                 :             /*
 2061 rhaas                   18332 ECB             :              * Adjust the constraint for scanrel so that it matches this
                              18333                 :              * partition's attribute numbers.
                              18334                 :              */
 1824 alvherre                18335                 :             thisPartConstraint =
 1824 alvherre                18336 GIC         173 :                 map_partition_varattnos(partConstraint, 1,
                              18337                 :                                         part_rel, scanrel);
                              18338                 : 
                              18339             173 :             QueuePartitionConstraintValidation(wqueue, part_rel,
                              18340                 :                                                thisPartConstraint,
                              18341                 :                                                validate_default);
 1539 andres                  18342 CBC         173 :             table_close(part_rel, NoLock);  /* keep lock till commit */
 2061 rhaas                   18343 ECB             :         }
                              18344                 :     }
                              18345                 : }
                              18346                 : 
                              18347                 : /*
                              18348                 :  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
 2314                         18349                 :  *
                              18350                 :  * Return the address of the newly attached partition.
                              18351                 :  */
                              18352                 : static ObjectAddress
  928 tgl                     18353 CBC        1034 : ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd,
  928 tgl                     18354 ECB             :                       AlterTableUtilityContext *context)
                              18355                 : {
                              18356                 :     Relation    attachrel,
                              18357                 :                 catalog;
                              18358                 :     List       *attachrel_children;
                              18359                 :     List       *partConstraint;
                              18360                 :     SysScanDesc scan;
                              18361                 :     ScanKeyData skey;
                              18362                 :     AttrNumber  attno;
                              18363                 :     int         natts;
                              18364                 :     TupleDesc   tupleDesc;
 2314 rhaas                   18365                 :     ObjectAddress address;
                              18366                 :     const char *trigger_name;
 2039                         18367                 :     Oid         defaultPartOid;
                              18368                 :     List       *partBoundConstraint;
  928 tgl                     18369 CBC        1034 :     ParseState *pstate = make_parsestate(NULL);
  928 tgl                     18370 EUB             : 
  928 tgl                     18371 GBC        1034 :     pstate->p_sourcetext = context->queryString;
 2039 rhaas                   18372 ECB             : 
                              18373                 :     /*
 1824 alvherre                18374                 :      * We must lock the default partition if one exists, because attaching a
                              18375                 :      * new partition will change its partition constraint.
                              18376                 :      */
 2039 rhaas                   18377                 :     defaultPartOid =
  717 alvherre                18378 CBC        1034 :         get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
 2039 rhaas                   18379 GIC        1034 :     if (OidIsValid(defaultPartOid))
                              18380              91 :         LockRelationOid(defaultPartOid, AccessExclusiveLock);
 2314 rhaas                   18381 EUB             : 
 1539 andres                  18382 GIC        1034 :     attachrel = table_openrv(cmd->name, AccessExclusiveLock);
                              18383                 : 
                              18384                 :     /*
                              18385                 :      * XXX I think it'd be a good idea to grab locks on all tables referenced
                              18386                 :      * by FKs at this point also.
                              18387                 :      */
                              18388                 : 
                              18389                 :     /*
                              18390                 :      * Must be owner of both parent and source table -- parent was checked by
                              18391                 :      * ATSimplePermissions call in ATPrepCmd
 2314 rhaas                   18392 ECB             :      */
  640 peter                   18393 GBC        1031 :     ATSimplePermissions(AT_AttachPartition, attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
                              18394                 : 
                              18395                 :     /* A partition can only have one parent */
 2075 rhaas                   18396 GIC        1028 :     if (attachrel->rd_rel->relispartition)
 2314 rhaas                   18397 CBC           3 :         ereport(ERROR,
 2314 rhaas                   18398 EUB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18399                 :                  errmsg("\"%s\" is already a partition",
                              18400                 :                         RelationGetRelationName(attachrel))));
                              18401                 : 
 2075 rhaas                   18402 CBC        1025 :     if (OidIsValid(attachrel->rd_rel->reloftype))
 2314 rhaas                   18403 GBC           3 :         ereport(ERROR,
                              18404                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18405                 :                  errmsg("cannot attach a typed table as partition")));
                              18406                 : 
 2314 rhaas                   18407 ECB             :     /*
 2314 rhaas                   18408 EUB             :      * Table being attached should not already be part of inheritance; either
                              18409                 :      * as a child table...
                              18410                 :      */
 1539 andres                  18411 GIC        1022 :     catalog = table_open(InheritsRelationId, AccessShareLock);
 2314 rhaas                   18412 CBC        1022 :     ScanKeyInit(&skey,
 2314 rhaas                   18413 EUB             :                 Anum_pg_inherits_inhrelid,
                              18414                 :                 BTEqualStrategyNumber, F_OIDEQ,
                              18415                 :                 ObjectIdGetDatum(RelationGetRelid(attachrel)));
 2314 rhaas                   18416 GIC        1022 :     scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
 2314 rhaas                   18417 ECB             :                               NULL, 1, &skey);
 2314 rhaas                   18418 GIC        1022 :     if (HeapTupleIsValid(systable_getnext(scan)))
 2314 rhaas                   18419 CBC           3 :         ereport(ERROR,
 2314 rhaas                   18420 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18421                 :                  errmsg("cannot attach inheritance child as partition")));
 2314 rhaas                   18422 GIC        1019 :     systable_endscan(scan);
                              18423                 : 
                              18424                 :     /* ...or as a parent table (except the case when it is partitioned) */
                              18425            1019 :     ScanKeyInit(&skey,
                              18426                 :                 Anum_pg_inherits_inhparent,
                              18427                 :                 BTEqualStrategyNumber, F_OIDEQ,
 2075 rhaas                   18428 ECB             :                 ObjectIdGetDatum(RelationGetRelid(attachrel)));
 2314 rhaas                   18429 GBC        1019 :     scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
                              18430                 :                               1, &skey);
 2314 rhaas                   18431 GIC        1019 :     if (HeapTupleIsValid(systable_getnext(scan)) &&
 2075                         18432             112 :         attachrel->rd_rel->relkind == RELKIND_RELATION)
 2314                         18433               3 :         ereport(ERROR,
                              18434                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18435                 :                  errmsg("cannot attach inheritance parent as partition")));
                              18436            1016 :     systable_endscan(scan);
 1539 andres                  18437            1016 :     table_close(catalog, AccessShareLock);
 2314 rhaas                   18438 ECB             : 
                              18439                 :     /*
 2075                         18440                 :      * Prevent circularity by seeing if rel is a partition of attachrel. (In
 2308 rhaas                   18441 EUB             :      * particular, this disallows making a rel a partition of itself.)
                              18442                 :      *
                              18443                 :      * We do that by checking if rel is a member of the list of attachrel's
                              18444                 :      * partitions provided the latter is partitioned at all.  We want to avoid
                              18445                 :      * having to construct this list again, so we request the strongest lock
 1823 alvherre                18446 ECB             :      * on all partitions.  We need the strongest lock, because we may decide
 1823 alvherre                18447 EUB             :      * to scan them if we find out that the table being attached (or its leaf
                              18448                 :      * partitions) may contain rows that violate the partition constraint. If
                              18449                 :      * the table has a constraint that would prevent such rows, which by
                              18450                 :      * definition is present in all the partitions, we need not scan the
                              18451                 :      * table, nor its partitions.  But we cannot risk a deadlock by taking a
 1823 alvherre                18452 ECB             :      * weaker lock now and the stronger one only when needed.
 2314 rhaas                   18453 EUB             :      */
 2075 rhaas                   18454 GIC        1016 :     attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
                              18455                 :                                              AccessExclusiveLock, NULL);
                              18456            1016 :     if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
 2314                         18457               6 :         ereport(ERROR,
                              18458                 :                 (errcode(ERRCODE_DUPLICATE_TABLE),
                              18459                 :                  errmsg("circular inheritance not allowed"),
 2314 rhaas                   18460 ECB             :                  errdetail("\"%s\" is already a child of \"%s\".",
                              18461                 :                            RelationGetRelationName(rel),
                              18462                 :                            RelationGetRelationName(attachrel))));
                              18463                 : 
                              18464                 :     /* If the parent is permanent, so must be all of its partitions. */
 1754 michael                 18465 GIC        1010 :     if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
                              18466             998 :         attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
                              18467               3 :         ereport(ERROR,
                              18468                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 1754 michael                 18469 ECB             :                  errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
                              18470                 :                         RelationGetRelationName(rel))));
                              18471                 : 
                              18472                 :     /* Temp parent cannot have a partition that is itself not a temp */
 2314 rhaas                   18473 GIC        1007 :     if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
 2075                         18474              12 :         attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
 2314                         18475               9 :         ereport(ERROR,
 2314 rhaas                   18476 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18477                 :                  errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
                              18478                 :                         RelationGetRelationName(rel))));
                              18479                 : 
                              18480                 :     /* If the parent is temp, it must belong to this session */
 2314 rhaas                   18481 GIC         998 :     if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              18482               3 :         !rel->rd_islocaltemp)
 2314 rhaas                   18483 LBC           0 :         ereport(ERROR,
 2314 rhaas                   18484 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 2308                         18485                 :                  errmsg("cannot attach as partition of temporary relation of another session")));
                              18486                 : 
                              18487                 :     /* Ditto for the partition */
 2075 rhaas                   18488 GIC         998 :     if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              18489               3 :         !attachrel->rd_islocaltemp)
 2314 rhaas                   18490 UIC           0 :         ereport(ERROR,
                              18491                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18492                 :                  errmsg("cannot attach temporary relation of another session as partition")));
 2314 rhaas                   18493 ECB             : 
 2075                         18494                 :     /* Check if there are any columns in attachrel that aren't in the parent */
 2075 rhaas                   18495 GIC         998 :     tupleDesc = RelationGetDescr(attachrel);
 2314 rhaas                   18496 CBC         998 :     natts = tupleDesc->natts;
 2314 rhaas                   18497 GIC        3427 :     for (attno = 1; attno <= natts; attno++)
                              18498                 :     {
 2058 andres                  18499 CBC        2438 :         Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
 2314 rhaas                   18500 GIC        2438 :         char       *attributeName = NameStr(attribute->attname);
 2314 rhaas                   18501 ECB             : 
                              18502                 :         /* Ignore dropped */
 2314 rhaas                   18503 CBC        2438 :         if (attribute->attisdropped)
 2314 rhaas                   18504 GIC         278 :             continue;
                              18505                 : 
 2299 rhaas                   18506 ECB             :         /* Try to find the column in parent (matching on column name) */
 2299 rhaas                   18507 GIC        2160 :         if (!SearchSysCacheExists2(ATTNAME,
                              18508                 :                                    ObjectIdGetDatum(RelationGetRelid(rel)),
 2299 rhaas                   18509 ECB             :                                    CStringGetDatum(attributeName)))
 2314 rhaas                   18510 GIC           9 :             ereport(ERROR,
                              18511                 :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              18512                 :                      errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
 2075 rhaas                   18513 ECB             :                             RelationGetRelationName(attachrel), attributeName,
                              18514                 :                             RelationGetRelationName(rel)),
                              18515                 :                      errdetail("The new partition may contain only the columns present in parent.")));
 2314                         18516                 :     }
                              18517                 : 
                              18518                 :     /*
 2111 rhodiumtoad             18519                 :      * If child_rel has row-level triggers with transition tables, we
                              18520                 :      * currently don't allow it to become a partition.  See also prohibitions
                              18521                 :      * in ATExecAddInherit() and CreateTrigger().
                              18522                 :      */
 2075 rhaas                   18523 GIC         989 :     trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
 2111 rhodiumtoad             18524             989 :     if (trigger_name != NULL)
                              18525               3 :         ereport(ERROR,
                              18526                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 2111 rhodiumtoad             18527 ECB             :                  errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
                              18528                 :                         trigger_name, RelationGetRelationName(attachrel)),
                              18529                 :                  errdetail("ROW triggers with transition tables are not supported on partitions.")));
                              18530                 : 
                              18531                 :     /*
                              18532                 :      * Check that the new partition's bound is valid and does not overlap any
                              18533                 :      * of existing partitions of the parent - note that it does not return on
                              18534                 :      * error.
 2314 rhaas                   18535                 :      */
 2075 rhaas                   18536 CBC         986 :     check_new_partition_bound(RelationGetRelationName(attachrel), rel,
                              18537                 :                               cmd->bound, pstate);
 2314 rhaas                   18538 ECB             : 
                              18539                 :     /* OK to create inheritance.  Rest of the checks performed there */
 1646 alvherre                18540 GIC         968 :     CreateInheritance(attachrel, rel);
                              18541                 : 
 2314 rhaas                   18542 ECB             :     /* Update the pg_class entry. */
 2075 rhaas                   18543 GIC         935 :     StorePartitionBound(attachrel, rel, cmd->bound);
                              18544                 : 
                              18545                 :     /* Ensure there exists a correct set of indexes in the partition. */
    2 alvherre                18546 GNC         935 :     AttachPartitionEnsureIndexes(wqueue, rel, attachrel);
                              18547                 : 
 1843 alvherre                18548 ECB             :     /* and triggers */
 1843 alvherre                18549 CBC         920 :     CloneRowTriggersToPartition(rel, attachrel);
 1843 alvherre                18550 ECB             : 
 1831                         18551                 :     /*
                              18552                 :      * Clone foreign key constraints.  Callee is responsible for setting up
                              18553                 :      * for phase 3 constraint verification.
                              18554                 :      */
 1467 alvherre                18555 GIC         917 :     CloneForeignKeyConstraints(wqueue, rel, attachrel);
 1831 alvherre                18556 ECB             : 
                              18557                 :     /*
 2314 rhaas                   18558                 :      * Generate partition constraint from the partition bound specification.
                              18559                 :      * If the parent itself is a partition, make sure to include its
                              18560                 :      * constraint as well.
                              18561                 :      */
  634 john.naylor             18562 GIC         917 :     partBoundConstraint = get_qual_from_partbound(rel, cmd->bound);
 2039 rhaas                   18563             917 :     partConstraint = list_concat(partBoundConstraint,
 2286                         18564             917 :                                  RelationGetPartitionQual(rel));
                              18565                 : 
                              18566                 :     /* Skip validation if there are no constraints to validate. */
 2039                         18567             917 :     if (partConstraint)
                              18568                 :     {
 1855 tgl                     18569 ECB             :         /*
                              18570                 :          * Run the partition quals through const-simplification similar to
                              18571                 :          * check constraints.  We skip canonicalize_qual, though, because
                              18572                 :          * partition quals should be in canonical form already.
                              18573                 :          */
                              18574                 :         partConstraint =
 2039 rhaas                   18575 GIC         893 :             (List *) eval_const_expressions(NULL,
                              18576                 :                                             (Node *) partConstraint);
 1855 tgl                     18577 ECB             : 
                              18578                 :         /* XXX this sure looks wrong */
 2039 rhaas                   18579 CBC         893 :         partConstraint = list_make1(make_ands_explicit(partConstraint));
 2039 rhaas                   18580 ECB             : 
                              18581                 :         /*
                              18582                 :          * Adjust the generated constraint to match this partition's attribute
                              18583                 :          * numbers.
                              18584                 :          */
 2039 rhaas                   18585 CBC         893 :         partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
                              18586                 :                                                  rel);
                              18587                 : 
 2039 rhaas                   18588 ECB             :         /* Validate partition constraints against the table being attached. */
 1824 alvherre                18589 CBC         893 :         QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
 1824 alvherre                18590 ECB             :                                            false);
                              18591                 :     }
                              18592                 : 
                              18593                 :     /*
                              18594                 :      * If we're attaching a partition other than the default partition and a
                              18595                 :      * default one exists, then that partition's partition constraint changes,
                              18596                 :      * so add an entry to the work queue to validate it, too.  (We must not do
                              18597                 :      * this when the partition being attached is the default one; we already
 1809 tgl                     18598                 :      * did it above!)
 2074 rhaas                   18599                 :      */
 2039 rhaas                   18600 GIC         917 :     if (OidIsValid(defaultPartOid))
                              18601                 :     {
                              18602                 :         Relation    defaultrel;
                              18603                 :         List       *defPartConstraint;
                              18604                 : 
 1824 alvherre                18605              73 :         Assert(!cmd->bound->is_default);
                              18606                 : 
 1824 alvherre                18607 ECB             :         /* we already hold a lock on the default partition */
 1539 andres                  18608 GBC          73 :         defaultrel = table_open(defaultPartOid, NoLock);
                              18609                 :         defPartConstraint =
 2039 rhaas                   18610 CBC          73 :             get_proposed_default_constraint(partBoundConstraint);
 1378 tgl                     18611 ECB             : 
                              18612                 :         /*
                              18613                 :          * Map the Vars in the constraint expression from rel's attnos to
                              18614                 :          * defaultrel's.
                              18615                 :          */
                              18616                 :         defPartConstraint =
 1381 alvherre                18617 CBC          73 :             map_partition_varattnos(defPartConstraint,
                              18618                 :                                     1, defaultrel, rel);
 1824 alvherre                18619 GIC          73 :         QueuePartitionConstraintValidation(wqueue, defaultrel,
                              18620                 :                                            defPartConstraint, true);
 2074 rhaas                   18621 ECB             : 
                              18622                 :         /* keep our lock until commit. */
 1539 andres                  18623 GIC          73 :         table_close(defaultrel, NoLock);
 2039 rhaas                   18624 ECB             :     }
 2314                         18625                 : 
 2075 rhaas                   18626 GIC         917 :     ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
                              18627                 : 
                              18628                 :     /*
                              18629                 :      * If the partition we just attached is partitioned itself, invalidate
                              18630                 :      * relcache for all descendent partitions too to ensure that their
                              18631                 :      * rd_partcheck expression trees are rebuilt; partitions already locked at
                              18632                 :      * the beginning of this function.
                              18633                 :      */
  538 alvherre                18634             917 :     if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              18635                 :     {
                              18636                 :         ListCell   *l;
                              18637                 : 
  538 alvherre                18638 CBC         450 :         foreach(l, attachrel_children)
                              18639                 :         {
  538 alvherre                18640 GIC         301 :             CacheInvalidateRelcacheByRelid(lfirst_oid(l));
                              18641                 :         }
                              18642                 :     }
                              18643                 : 
                              18644                 :     /* keep our lock until commit */
 1539 andres                  18645             917 :     table_close(attachrel, NoLock);
 2314 rhaas                   18646 ECB             : 
 2314 rhaas                   18647 CBC         917 :     return address;
                              18648                 : }
                              18649                 : 
                              18650                 : /*
                              18651                 :  * AttachPartitionEnsureIndexes
                              18652                 :  *      subroutine for ATExecAttachPartition to create/match indexes
                              18653                 :  *
                              18654                 :  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
                              18655                 :  * PARTITION: every partition must have an index attached to each index on the
                              18656                 :  * partitioned table.
                              18657                 :  */
                              18658                 : static void
    2 alvherre                18659 GNC         935 : AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel)
                              18660                 : {
                              18661                 :     List       *idxes;
 1906 alvherre                18662 ECB             :     List       *attachRelIdxs;
                              18663                 :     Relation   *attachrelIdxRels;
                              18664                 :     IndexInfo **attachInfos;
                              18665                 :     ListCell   *cell;
 1906 alvherre                18666 EUB             :     MemoryContext cxt;
                              18667                 :     MemoryContext oldcxt;
                              18668                 : 
 1906 alvherre                18669 GIC         935 :     cxt = AllocSetContextCreate(CurrentMemoryContext,
                              18670                 :                                 "AttachPartitionEnsureIndexes",
                              18671                 :                                 ALLOCSET_DEFAULT_SIZES);
                              18672             935 :     oldcxt = MemoryContextSwitchTo(cxt);
                              18673                 : 
                              18674             935 :     idxes = RelationGetIndexList(rel);
                              18675             935 :     attachRelIdxs = RelationGetIndexList(attachrel);
 1906 alvherre                18676 CBC         935 :     attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
                              18677             935 :     attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
                              18678                 : 
 1906 alvherre                18679 ECB             :     /* Build arrays of all existing indexes and their IndexInfos */
 1906 alvherre                18680 CBC        1084 :     foreach(cell, attachRelIdxs)
 1906 alvherre                18681 ECB             :     {
 1906 alvherre                18682 CBC         149 :         Oid         cldIdxId = lfirst_oid(cell);
    2 alvherre                18683 GNC         149 :         int         i = foreach_current_index(cell);
                              18684                 : 
 1906 alvherre                18685 GIC         149 :         attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
                              18686             149 :         attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
                              18687                 :     }
                              18688                 : 
                              18689                 :     /*
                              18690                 :      * If we're attaching a foreign table, we must fail if any of the indexes
                              18691                 :      * is a constraint index; otherwise, there's nothing to do here.  Do this
                              18692                 :      * before starting work, to avoid wasting the effort of building a few
                              18693                 :      * non-unique indexes before coming across a unique one.
 1383 alvherre                18694 ECB             :      */
 1383 alvherre                18695 CBC         935 :     if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
                              18696                 :     {
 1383 alvherre                18697 GIC          43 :         foreach(cell, idxes)
                              18698                 :         {
                              18699              18 :             Oid         idx = lfirst_oid(cell);
                              18700              18 :             Relation    idxRel = index_open(idx, AccessShareLock);
                              18701                 : 
                              18702              18 :             if (idxRel->rd_index->indisunique ||
                              18703              12 :                 idxRel->rd_index->indisprimary)
 1383 alvherre                18704 CBC           6 :                 ereport(ERROR,
 1383 alvherre                18705 ECB             :                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18706                 :                          errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
                              18707                 :                                 RelationGetRelationName(attachrel),
                              18708                 :                                 RelationGetRelationName(rel)),
                              18709                 :                          errdetail("Partitioned table \"%s\" contains unique indexes.",
                              18710                 :                                    RelationGetRelationName(rel))));
 1383 alvherre                18711 GIC          12 :             index_close(idxRel, AccessShareLock);
                              18712                 :         }
 1383 alvherre                18713 ECB             : 
 1383 alvherre                18714 GIC          25 :         goto out;
 1383 alvherre                18715 ECB             :     }
 1383 alvherre                18716 EUB             : 
                              18717                 :     /*
                              18718                 :      * For each index on the partitioned table, find a matching one in the
                              18719                 :      * partition-to-be; if one is not found, create one.
                              18720                 :      */
 1906 alvherre                18721 GIC        1088 :     foreach(cell, idxes)
                              18722                 :     {
 1906 alvherre                18723 CBC         193 :         Oid         idx = lfirst_oid(cell);
 1906 alvherre                18724 GBC         193 :         Relation    idxRel = index_open(idx, AccessShareLock);
                              18725                 :         IndexInfo  *info;
                              18726                 :         AttrMap    *attmap;
 1906 alvherre                18727 GIC         193 :         bool        found = false;
                              18728                 :         Oid         constraintOid;
                              18729                 : 
 1906 alvherre                18730 ECB             :         /*
                              18731                 :          * Ignore indexes in the partitioned table other than partitioned
                              18732                 :          * indexes.
                              18733                 :          */
 1906 alvherre                18734 GIC         193 :         if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
                              18735                 :         {
 1906 alvherre                18736 UIC           0 :             index_close(idxRel, AccessShareLock);
 1906 alvherre                18737 LBC           0 :             continue;
 1906 alvherre                18738 ECB             :         }
                              18739                 : 
                              18740                 :         /* construct an indexinfo to compare existing indexes against */
 1906 alvherre                18741 GIC         193 :         info = BuildIndexInfo(idxRel);
 1208 michael                 18742 CBC         193 :         attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
                              18743                 :                                        RelationGetDescr(rel),
                              18744                 :                                        false);
 1875 alvherre                18745             193 :         constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
                              18746                 : 
 1906 alvherre                18747 ECB             :         /*
                              18748                 :          * Scan the list of existing indexes in the partition-to-be, and mark
                              18749                 :          * the first matching, unattached one we find, if any, as partition of
 1906 alvherre                18750 EUB             :          * the parent index.  If we find one, we're done.
                              18751                 :          */
    2 alvherre                18752 GNC         220 :         for (int i = 0; i < list_length(attachRelIdxs); i++)
                              18753                 :         {
 1809 tgl                     18754 GIC         110 :             Oid         cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
                              18755             110 :             Oid         cldConstrOid = InvalidOid;
 1875 alvherre                18756 ECB             : 
                              18757                 :             /* does this index have a parent?  if so, can't use it */
 1824 alvherre                18758 GIC         110 :             if (attachrelIdxRels[i]->rd_rel->relispartition)
 1906                         18759               6 :                 continue;
                              18760                 : 
                              18761             104 :             if (CompareIndexInfo(attachInfos[i], info,
                              18762             104 :                                  attachrelIdxRels[i]->rd_indcollation,
                              18763                 :                                  idxRel->rd_indcollation,
 1906 alvherre                18764 CBC         104 :                                  attachrelIdxRels[i]->rd_opfamily,
                              18765                 :                                  idxRel->rd_opfamily,
                              18766                 :                                  attmap))
                              18767                 :             {
                              18768                 :                 /*
 1875 alvherre                18769 ECB             :                  * If this index is being created in the parent because of a
                              18770                 :                  * constraint, then the child needs to have a constraint also,
                              18771                 :                  * so look for one.  If there is no such constraint, this
                              18772                 :                  * index is no good, so keep looking.
                              18773                 :                  */
 1875 alvherre                18774 GIC          86 :                 if (OidIsValid(constraintOid))
                              18775                 :                 {
                              18776                 :                     cldConstrOid =
                              18777              43 :                         get_relation_idx_constraint_oid(RelationGetRelid(attachrel),
                              18778                 :                                                         cldIdxId);
                              18779                 :                     /* no dice */
                              18780              43 :                     if (!OidIsValid(cldConstrOid))
                              18781               3 :                         continue;
 1875 alvherre                18782 ECB             :                 }
                              18783                 : 
                              18784                 :                 /* bingo. */
 1906 alvherre                18785 CBC          83 :                 IndexSetParentIndex(attachrelIdxRels[i], idx);
 1875                         18786              83 :                 if (OidIsValid(constraintOid))
 1518 tgl                     18787 GIC          40 :                     ConstraintSetParentConstraint(cldConstrOid, constraintOid,
                              18788                 :                                                   RelationGetRelid(attachrel));
 1906 alvherre                18789 CBC          83 :                 found = true;
                              18790                 : 
 1467                         18791              83 :                 CommandCounterIncrement();
 1906 alvherre                18792 GIC          83 :                 break;
 1906 alvherre                18793 ECB             :             }
                              18794                 :         }
                              18795                 : 
                              18796                 :         /*
                              18797                 :          * If no suitable index was found in the partition-to-be, create one
                              18798                 :          * now.
                              18799                 :          */
 1906 alvherre                18800 GIC         193 :         if (!found)
 1906 alvherre                18801 ECB             :         {
                              18802                 :             IndexStmt  *stmt;
                              18803                 :             Oid         conOid;
                              18804                 : 
 1447 tgl                     18805 GIC         110 :             stmt = generateClonedIndexStmt(NULL,
                              18806                 :                                            idxRel, attmap,
                              18807                 :                                            &conOid);
                              18808                 : 
                              18809                 :             /*
                              18810                 :              * If the index is a primary key, mark all columns as NOT NULL if
                              18811                 :              * they aren't already.
                              18812                 :              */
    2 alvherre                18813 GNC         110 :             if (stmt->primary)
                              18814                 :             {
                              18815              59 :                 MemoryContextSwitchTo(oldcxt);
                              18816             124 :                 for (int j = 0; j < info->ii_NumIndexKeyAttrs; j++)
                              18817                 :                 {
                              18818                 :                     AttrNumber  childattno;
                              18819                 : 
                              18820              65 :                     childattno = get_attnum(RelationGetRelid(attachrel),
                              18821              65 :                                             get_attname(RelationGetRelid(rel),
                              18822              65 :                                                         info->ii_IndexAttrNumbers[j],
                              18823                 :                                                         false));
                              18824              65 :                     set_attnotnull(wqueue, attachrel, childattno,
                              18825                 :                                    true, AccessExclusiveLock);
                              18826                 :                 }
                              18827              59 :                 MemoryContextSwitchTo(cxt);
                              18828                 :             }
                              18829                 : 
 1906 alvherre                18830 GIC         110 :             DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid,
                              18831                 :                         RelationGetRelid(idxRel),
                              18832                 :                         conOid,
                              18833                 :                         -1,
                              18834                 :                         true, false, false, false, false);
                              18835                 :         }
                              18836                 : 
 1906 alvherre                18837 CBC         184 :         index_close(idxRel, AccessShareLock);
 1906 alvherre                18838 ECB             :     }
                              18839                 : 
 1383 alvherre                18840 GIC         920 : out:
                              18841                 :     /* Clean up. */
    2 alvherre                18842 GNC        1063 :     for (int i = 0; i < list_length(attachRelIdxs); i++)
 1906 alvherre                18843 GIC         143 :         index_close(attachrelIdxRels[i], AccessShareLock);
 1906 alvherre                18844 CBC         920 :     MemoryContextSwitchTo(oldcxt);
 1906 alvherre                18845 GIC         920 :     MemoryContextDelete(cxt);
                              18846             920 : }
                              18847                 : 
                              18848                 : /*
                              18849                 :  * CloneRowTriggersToPartition
                              18850                 :  *      subroutine for ATExecAttachPartition/DefineRelation to create row
                              18851                 :  *      triggers on partitions
                              18852                 :  */
                              18853                 : static void
 1843                         18854            1108 : CloneRowTriggersToPartition(Relation parent, Relation partition)
                              18855                 : {
                              18856                 :     Relation    pg_trigger;
                              18857                 :     ScanKeyData key;
 1843 alvherre                18858 ECB             :     SysScanDesc scan;
                              18859                 :     HeapTuple   tuple;
 1406 tgl                     18860                 :     MemoryContext perTupCxt;
 1843 alvherre                18861                 : 
 1843 alvherre                18862 GIC        1108 :     ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
                              18863                 :                 F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
 1539 andres                  18864            1108 :     pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
 1843 alvherre                18865 CBC        1108 :     scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
 1843 alvherre                18866 ECB             :                               true, NULL, 1, &key);
                              18867                 : 
 1843 alvherre                18868 GIC        1108 :     perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
                              18869                 :                                       "clone trig", ALLOCSET_SMALL_SIZES);
                              18870                 : 
                              18871            1788 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
                              18872                 :     {
 1406 tgl                     18873             683 :         Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
 1843 alvherre                18874 ECB             :         CreateTrigStmt *trigStmt;
 1843 alvherre                18875 CBC         683 :         Node       *qual = NULL;
                              18876                 :         Datum       value;
 1843 alvherre                18877 ECB             :         bool        isnull;
 1843 alvherre                18878 GIC         683 :         List       *cols = NIL;
 1370                         18879             683 :         List       *trigargs = NIL;
                              18880                 :         MemoryContext oldcxt;
                              18881                 : 
                              18882                 :         /*
                              18883                 :          * Ignore statement-level triggers; those are not cloned.
                              18884                 :          */
 1843 alvherre                18885 CBC         683 :         if (!TRIGGER_FOR_ROW(trigForm->tgtype))
                              18886             605 :             continue;
                              18887                 : 
 1193 alvherre                18888 ECB             :         /*
  459                         18889                 :          * Don't clone internal triggers, because the constraint cloning code
                              18890                 :          * will.
                              18891                 :          */
  459 alvherre                18892 GIC         683 :         if (trigForm->tgisinternal)
 1832                         18893             605 :             continue;
                              18894                 : 
                              18895                 :         /*
                              18896                 :          * Complain if we find an unexpected trigger type.
                              18897                 :          */
 1117                         18898              78 :         if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
                              18899              69 :             !TRIGGER_FOR_AFTER(trigForm->tgtype))
 1843 alvherre                18900 UIC           0 :             elog(ERROR, "unexpected trigger \"%s\" found",
 1843 alvherre                18901 ECB             :                  NameStr(trigForm->tgname));
                              18902                 : 
                              18903                 :         /* Use short-lived context for CREATE TRIGGER */
 1406 tgl                     18904 GIC          78 :         oldcxt = MemoryContextSwitchTo(perTupCxt);
                              18905                 : 
                              18906                 :         /*
                              18907                 :          * If there is a WHEN clause, generate a 'cooked' version of it that's
                              18908                 :          * appropriate for the partition.
                              18909                 :          */
 1843 alvherre                18910              78 :         value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
                              18911                 :                              RelationGetDescr(pg_trigger), &isnull);
                              18912              78 :         if (!isnull)
                              18913                 :         {
                              18914               3 :             qual = stringToNode(TextDatumGetCString(value));
 1843 alvherre                18915 CBC           3 :             qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
                              18916                 :                                                     partition, parent);
 1843 alvherre                18917 GIC           3 :             qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
                              18918                 :                                                     partition, parent);
                              18919                 :         }
                              18920                 : 
                              18921                 :         /*
                              18922                 :          * If there is a column list, transform it to a list of column names.
 1843 alvherre                18923 ECB             :          * Note we don't need to map this list in any way ...
                              18924                 :          */
 1843 alvherre                18925 CBC          78 :         if (trigForm->tgattr.dim1 > 0)
 1843 alvherre                18926 ECB             :         {
                              18927                 :             int         i;
                              18928                 : 
 1843 alvherre                18929 GIC           6 :             for (i = 0; i < trigForm->tgattr.dim1; i++)
 1843 alvherre                18930 ECB             :             {
                              18931                 :                 Form_pg_attribute col;
                              18932                 : 
 1843 alvherre                18933 CBC           3 :                 col = TupleDescAttr(parent->rd_att,
                              18934                 :                                     trigForm->tgattr.values[i] - 1);
 1812 alvherre                18935 GIC           3 :                 cols = lappend(cols,
                              18936               3 :                                makeString(pstrdup(NameStr(col->attname))));
                              18937                 :             }
                              18938                 :         }
                              18939                 : 
                              18940                 :         /* Reconstruct trigger arguments list. */
 1370 alvherre                18941 CBC          78 :         if (trigForm->tgnargs > 0)
                              18942                 :         {
                              18943                 :             char       *p;
                              18944                 : 
 1370 alvherre                18945 GIC           6 :             value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
 1370 alvherre                18946 ECB             :                                  RelationGetDescr(pg_trigger), &isnull);
 1370 alvherre                18947 CBC           6 :             if (isnull)
 1370 alvherre                18948 LBC           0 :                 elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
 1370 alvherre                18949 ECB             :                      NameStr(trigForm->tgname), RelationGetRelationName(partition));
                              18950                 : 
 1370 alvherre                18951 CBC           6 :             p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
                              18952                 : 
                              18953              18 :             for (int i = 0; i < trigForm->tgnargs; i++)
                              18954                 :             {
 1370 alvherre                18955 GIC          12 :                 trigargs = lappend(trigargs, makeString(pstrdup(p)));
 1370 alvherre                18956 CBC          12 :                 p += strlen(p) + 1;
                              18957                 :             }
                              18958                 :         }
                              18959                 : 
 1843 alvherre                18960 GIC          78 :         trigStmt = makeNode(CreateTrigStmt);
  876 tgl                     18961              78 :         trigStmt->replace = false;
                              18962              78 :         trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
 1843 alvherre                18963              78 :         trigStmt->trigname = NameStr(trigForm->tgname);
 1843 alvherre                18964 CBC          78 :         trigStmt->relation = NULL;
 1843 alvherre                18965 GIC          78 :         trigStmt->funcname = NULL;   /* passed separately */
 1370                         18966              78 :         trigStmt->args = trigargs;
 1843                         18967              78 :         trigStmt->row = true;
                              18968              78 :         trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
                              18969              78 :         trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
                              18970              78 :         trigStmt->columns = cols;
 1843 alvherre                18971 CBC          78 :         trigStmt->whenClause = NULL; /* passed separately */
 1843 alvherre                18972 GIC          78 :         trigStmt->transitionRels = NIL; /* not supported at present */
                              18973              78 :         trigStmt->deferrable = trigForm->tgdeferrable;
 1843 alvherre                18974 CBC          78 :         trigStmt->initdeferred = trigForm->tginitdeferred;
 1843 alvherre                18975 GIC          78 :         trigStmt->constrrel = NULL; /* passed separately */
                              18976                 : 
  632 alvherre                18977 CBC          78 :         CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
                              18978                 :                               trigForm->tgconstrrelid, InvalidOid, InvalidOid,
                              18979                 :                               trigForm->tgfoid, trigForm->oid, qual,
  632 alvherre                18980 GIC          78 :                               false, true, trigForm->tgenabled);
                              18981                 : 
 1406 tgl                     18982              75 :         MemoryContextSwitchTo(oldcxt);
 1843 alvherre                18983              75 :         MemoryContextReset(perTupCxt);
                              18984                 :     }
                              18985                 : 
                              18986            1105 :     MemoryContextDelete(perTupCxt);
                              18987                 : 
 1843 alvherre                18988 CBC        1105 :     systable_endscan(scan);
 1539 andres                  18989 GIC        1105 :     table_close(pg_trigger, RowExclusiveLock);
 1843 alvherre                18990            1105 : }
                              18991                 : 
                              18992                 : /*
                              18993                 :  * ALTER TABLE DETACH PARTITION
                              18994                 :  *
                              18995                 :  * Return the address of the relation that is no longer a partition of rel.
                              18996                 :  *
                              18997                 :  * If concurrent mode is requested, we run in two transactions.  A side-
                              18998                 :  * effect is that this command cannot run in a multi-part ALTER TABLE.
                              18999                 :  * Currently, that's enforced by the grammar.
                              19000                 :  *
                              19001                 :  * The strategy for concurrency is to first modify the partition's
                              19002                 :  * pg_inherit catalog row to make it visible to everyone that the
                              19003                 :  * partition is detached, lock the partition against writes, and commit
  745 alvherre                19004 ECB             :  * the transaction; anyone who requests the partition descriptor from
                              19005                 :  * that point onwards has to ignore such a partition.  In a second
                              19006                 :  * transaction, we wait until all transactions that could have seen the
                              19007                 :  * partition as attached are gone, then we remove the rest of partition
                              19008                 :  * metadata (pg_inherits and pg_class.relpartbounds).
                              19009                 :  */
                              19010                 : static ObjectAddress
  745 alvherre                19011 GIC         252 : ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel,
                              19012                 :                       RangeVar *name, bool concurrent)
 2314 rhaas                   19013 ECB             : {
  745 alvherre                19014                 :     Relation    partRel;
 2314 rhaas                   19015                 :     ObjectAddress address;
                              19016                 :     Oid         defaultPartOid;
 2039                         19017                 : 
                              19018                 :     /*
                              19019                 :      * We must lock the default partition, because detaching this partition
                              19020                 :      * will change its partition constraint.
                              19021                 :      */
                              19022                 :     defaultPartOid =
  717 alvherre                19023 GIC         252 :         get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
 2039 rhaas                   19024             252 :     if (OidIsValid(defaultPartOid))
                              19025                 :     {
                              19026                 :         /*
                              19027                 :          * Concurrent detaching when a default partition exists is not
  745 alvherre                19028 ECB             :          * supported. The main problem is that the default partition
                              19029                 :          * constraint would change.  And there's a definitional problem: what
                              19030                 :          * should happen to the tuples that are being inserted that belong to
                              19031                 :          * the partition being detached?  Putting them on the partition being
  503                         19032                 :          * detached would be wrong, since they'd become "lost" after the
                              19033                 :          * detaching completes but we cannot put them in the default partition
                              19034                 :          * either until we alter its partition constraint.
                              19035                 :          *
                              19036                 :          * I think we could solve this problem if we effected the constraint
  745                         19037                 :          * change before committing the first transaction.  But the lock would
                              19038                 :          * have to remain AEL and it would cause concurrent query planning to
                              19039                 :          * be blocked, so changing it that way would be even worse.
                              19040                 :          */
  745 alvherre                19041 GIC          53 :         if (concurrent)
                              19042               6 :             ereport(ERROR,
                              19043                 :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19044                 :                      errmsg("cannot detach partitions concurrently when a default partition exists")));
 2039 rhaas                   19045              47 :         LockRelationOid(defaultPartOid, AccessExclusiveLock);
  745 alvherre                19046 ECB             :     }
 2314 rhaas                   19047                 : 
                              19048                 :     /*
                              19049                 :      * In concurrent mode, the partition is locked with share-update-exclusive
                              19050                 :      * in the first transaction.  This allows concurrent transactions to be
  745 alvherre                19051                 :      * doing DML to the partition.
                              19052                 :      */
  745 alvherre                19053 CBC         246 :     partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock :
  745 alvherre                19054 ECB             :                            AccessExclusiveLock);
                              19055                 : 
                              19056                 :     /*
  697 tgl                     19057                 :      * Check inheritance conditions and either delete the pg_inherits row (in
                              19058                 :      * non-concurrent mode) or just set the inhdetachpending flag.
                              19059                 :      */
  745 alvherre                19060 CBC         240 :     if (!concurrent)
  745 alvherre                19061 GIC         167 :         RemoveInheritance(partRel, rel, false);
                              19062                 :     else
                              19063              73 :         MarkInheritDetached(partRel, rel);
  745 alvherre                19064 ECB             : 
                              19065                 :     /*
                              19066                 :      * Ensure that foreign keys still hold after this detach.  This keeps
                              19067                 :      * locks on the referencing tables, which prevents concurrent transactions
                              19068                 :      * from adding rows that we wouldn't see.  For this to work in concurrent
                              19069                 :      * mode, it is critical that the partition appears as no longer attached
                              19070                 :      * for the RI queries as soon as the first transaction commits.
                              19071                 :      */
 1467 alvherre                19072 CBC         230 :     ATDetachCheckNoForeignKeyRefs(partRel);
                              19073                 : 
                              19074                 :     /*
                              19075                 :      * Concurrent mode has to work harder; first we add a new constraint to
                              19076                 :      * the partition that matches the partition constraint.  Then we close our
                              19077                 :      * existing transaction, and in a new one wait for all processes to catch
                              19078                 :      * up on the catalog updates we've done so far; at that point we can
                              19079                 :      * complete the operation.
                              19080                 :      */
  745 alvherre                19081 GIC         213 :     if (concurrent)
                              19082                 :     {
                              19083                 :         Oid         partrelid,
                              19084                 :                     parentrelid;
                              19085                 :         LOCKTAG     tag;
                              19086                 :         char       *parentrelname;
                              19087                 :         char       *partrelname;
                              19088                 : 
  745 alvherre                19089 ECB             :         /*
                              19090                 :          * Add a new constraint to the partition being detached, which
                              19091                 :          * supplants the partition constraint (unless there is one already).
                              19092                 :          */
  745 alvherre                19093 GIC          70 :         DetachAddConstraintIfNeeded(wqueue, partRel);
                              19094                 : 
                              19095                 :         /*
                              19096                 :          * We're almost done now; the only traces that remain are the
                              19097                 :          * pg_inherits tuple and the partition's relpartbounds.  Before we can
                              19098                 :          * remove those, we need to wait until all transactions that know that
                              19099                 :          * this is a partition are gone.
  745 alvherre                19100 ECB             :          */
 2314 rhaas                   19101                 : 
  745 alvherre                19102                 :         /*
                              19103                 :          * Remember relation OIDs to re-acquire them later; and relation names
                              19104                 :          * too, for error messages if something is dropped in between.
                              19105                 :          */
  745 alvherre                19106 GIC          70 :         partrelid = RelationGetRelid(partRel);
                              19107              70 :         parentrelid = RelationGetRelid(rel);
  745 alvherre                19108 CBC          70 :         parentrelname = MemoryContextStrdup(PortalContext,
                              19109              70 :                                             RelationGetRelationName(rel));
                              19110              70 :         partrelname = MemoryContextStrdup(PortalContext,
  745 alvherre                19111 GIC          70 :                                           RelationGetRelationName(partRel));
                              19112                 : 
                              19113                 :         /* Invalidate relcache entries for the parent -- must be before close */
                              19114              70 :         CacheInvalidateRelcache(rel);
                              19115                 : 
  745 alvherre                19116 CBC          70 :         table_close(partRel, NoLock);
                              19117              70 :         table_close(rel, NoLock);
  745 alvherre                19118 GBC          70 :         tab->rel = NULL;
                              19119                 : 
                              19120                 :         /* Make updated catalog entry visible */
  745 alvherre                19121 GIC          70 :         PopActiveSnapshot();
                              19122              70 :         CommitTransactionCommand();
  745 alvherre                19123 ECB             : 
  745 alvherre                19124 CBC          70 :         StartTransactionCommand();
 2314 rhaas                   19125 EUB             : 
                              19126                 :         /*
                              19127                 :          * Now wait.  This ensures that all queries that were planned
                              19128                 :          * including the partition are finished before we remove the rest of
                              19129                 :          * catalog entries.  We don't need or indeed want to acquire this
  697 tgl                     19130 ECB             :          * lock, though -- that would block later queries.
 1845 alvherre                19131                 :          *
  745                         19132                 :          * We don't need to concern ourselves with waiting for a lock on the
                              19133                 :          * partition itself, since we will acquire AccessExclusiveLock below.
 2039 rhaas                   19134                 :          */
  745 alvherre                19135 CBC          70 :         SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid);
  745 alvherre                19136 GIC          70 :         WaitForLockersMultiple(list_make1(&tag), AccessExclusiveLock, false);
                              19137                 : 
  745 alvherre                19138 ECB             :         /*
                              19139                 :          * Now acquire locks in both relations again.  Note they may have been
                              19140                 :          * removed in the meantime, so care is required.
                              19141                 :          */
  745 alvherre                19142 CBC          45 :         rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock);
  745 alvherre                19143 GIC          45 :         partRel = try_relation_open(partrelid, AccessExclusiveLock);
                              19144                 : 
  745 alvherre                19145 ECB             :         /* If the relations aren't there, something bad happened; bail out */
  745 alvherre                19146 GIC          45 :         if (rel == NULL)
                              19147                 :         {
  745 alvherre                19148 UIC           0 :             if (partRel != NULL)    /* shouldn't happen */
                              19149               0 :                 elog(WARNING, "dangling partition \"%s\" remains, can't fix",
                              19150                 :                      partrelname);
                              19151               0 :             ereport(ERROR,
                              19152                 :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19153                 :                      errmsg("partitioned table \"%s\" was removed concurrently",
                              19154                 :                             parentrelname)));
                              19155                 :         }
  745 alvherre                19156 GIC          45 :         if (partRel == NULL)
  745 alvherre                19157 UIC           0 :             ereport(ERROR,
  745 alvherre                19158 ECB             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19159                 :                      errmsg("partition \"%s\" was removed concurrently", partrelname)));
                              19160                 : 
  745 alvherre                19161 GIC          45 :         tab->rel = rel;
                              19162                 :     }
                              19163                 : 
                              19164                 :     /* Do the final part of detaching */
                              19165             188 :     DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
                              19166                 : 
                              19167             187 :     ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
                              19168                 : 
                              19169                 :     /* keep our lock until commit */
                              19170             187 :     table_close(partRel, NoLock);
 1906 alvherre                19171 ECB             : 
  745 alvherre                19172 GIC         187 :     return address;
                              19173                 : }
                              19174                 : 
  745 alvherre                19175 ECB             : /*
                              19176                 :  * Second part of ALTER TABLE .. DETACH.
                              19177                 :  *
                              19178                 :  * This is separate so that it can be run independently when the second
                              19179                 :  * transaction of the concurrent algorithm fails (crash or abort).
                              19180                 :  */
                              19181                 : static void
  745 alvherre                19182 GIC         195 : DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
                              19183                 :                         Oid defaultPartOid)
  745 alvherre                19184 ECB             : {
                              19185                 :     Relation    classRel;
                              19186                 :     List       *fks;
                              19187                 :     ListCell   *cell;
                              19188                 :     List       *indexes;
                              19189                 :     Datum       new_val[Natts_pg_class];
                              19190                 :     bool        new_null[Natts_pg_class],
                              19191                 :                 new_repl[Natts_pg_class];
                              19192                 :     HeapTuple   tuple,
                              19193                 :                 newtuple;
  459 alvherre                19194 GIC         195 :     Relation    trigrel = NULL;
                              19195                 : 
  745                         19196             195 :     if (concurrent)
  745 alvherre                19197 ECB             :     {
                              19198                 :         /*
                              19199                 :          * We can remove the pg_inherits row now. (In the non-concurrent case,
                              19200                 :          * this was already done).
                              19201                 :          */
  745 alvherre                19202 CBC          52 :         RemoveInheritance(partRel, rel, true);
                              19203                 :     }
                              19204                 : 
                              19205                 :     /* Drop any triggers that were cloned on creation/attach. */
 1083 alvherre                19206 GIC         195 :     DropClonedTriggersFromPartition(RelationGetRelid(partRel));
                              19207                 : 
                              19208                 :     /*
                              19209                 :      * Detach any foreign keys that are inherited.  This includes creating
 1539 alvherre                19210 ECB             :      * additional action triggers.
                              19211                 :      */
 1640 alvherre                19212 GIC         195 :     fks = copyObject(RelationGetFKeyList(partRel));
  459                         19213             195 :     if (fks != NIL)
  459 alvherre                19214 CBC          24 :         trigrel = table_open(TriggerRelationId, RowExclusiveLock);
 1640 alvherre                19215 GIC         234 :     foreach(cell, fks)
                              19216                 :     {
                              19217              39 :         ForeignKeyCacheInfo *fk = lfirst(cell);
                              19218                 :         HeapTuple   contup;
                              19219                 :         Form_pg_constraint conform;
 1539 alvherre                19220 ECB             :         Constraint *fkconstraint;
                              19221                 :         Oid         insertTriggerOid,
                              19222                 :                     updateTriggerOid;
                              19223                 : 
 1640 alvherre                19224 CBC          39 :         contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
 1435 tgl                     19225 GIC          39 :         if (!HeapTupleIsValid(contup))
 1640 alvherre                19226 UIC           0 :             elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
 1539 alvherre                19227 GIC          39 :         conform = (Form_pg_constraint) GETSTRUCT(contup);
                              19228                 : 
                              19229                 :         /* consider only the inherited foreign keys */
                              19230              39 :         if (conform->contype != CONSTRAINT_FOREIGN ||
                              19231              39 :             !OidIsValid(conform->conparentid))
                              19232                 :         {
                              19233               9 :             ReleaseSysCache(contup);
                              19234               9 :             continue;
 1539 alvherre                19235 ECB             :         }
                              19236                 : 
                              19237                 :         /* unset conparentid and adjust conislocal, coninhcount, etc. */
 1518 tgl                     19238 GIC          30 :         ConstraintSetParentConstraint(fk->conoid, InvalidOid, InvalidOid);
                              19239                 : 
  459 alvherre                19240 ECB             :         /*
                              19241                 :          * Also, look up the partition's "check" triggers corresponding to the
                              19242                 :          * constraint being detached and detach them from the parent triggers.
                              19243                 :          */
  459 alvherre                19244 GIC          30 :         GetForeignKeyCheckTriggers(trigrel,
  459 alvherre                19245 ECB             :                                    fk->conoid, fk->confrelid, fk->conrelid,
                              19246                 :                                    &insertTriggerOid, &updateTriggerOid);
  459 alvherre                19247 GIC          30 :         Assert(OidIsValid(insertTriggerOid));
                              19248              30 :         TriggerSetParentTrigger(trigrel, insertTriggerOid, InvalidOid,
                              19249                 :                                 RelationGetRelid(partRel));
                              19250              30 :         Assert(OidIsValid(updateTriggerOid));
                              19251              30 :         TriggerSetParentTrigger(trigrel, updateTriggerOid, InvalidOid,
  459 alvherre                19252 ECB             :                                 RelationGetRelid(partRel));
                              19253                 : 
 1539                         19254                 :         /*
                              19255                 :          * Make the action triggers on the referenced relation.  When this was
                              19256                 :          * a partition the action triggers pointed to the parent rel (they
                              19257                 :          * still do), but now we need separate ones of our own.
                              19258                 :          */
 1539 alvherre                19259 GIC          30 :         fkconstraint = makeNode(Constraint);
  157                         19260              30 :         fkconstraint->contype = CONSTRAINT_FOREIGN;
 1539 alvherre                19261 CBC          30 :         fkconstraint->conname = pstrdup(NameStr(conform->conname));
 1539 alvherre                19262 GIC          30 :         fkconstraint->deferrable = conform->condeferrable;
                              19263              30 :         fkconstraint->initdeferred = conform->condeferred;
  157                         19264              30 :         fkconstraint->location = -1;
                              19265              30 :         fkconstraint->pktable = NULL;
                              19266              30 :         fkconstraint->fk_attrs = NIL;
                              19267              30 :         fkconstraint->pk_attrs = NIL;
                              19268              30 :         fkconstraint->fk_matchtype = conform->confmatchtype;
  157 alvherre                19269 CBC          30 :         fkconstraint->fk_upd_action = conform->confupdtype;
  157 alvherre                19270 GIC          30 :         fkconstraint->fk_del_action = conform->confdeltype;
                              19271              30 :         fkconstraint->fk_del_set_cols = NIL;
                              19272              30 :         fkconstraint->old_conpfeqop = NIL;
  157 alvherre                19273 CBC          30 :         fkconstraint->old_pktable_oid = InvalidOid;
  157 alvherre                19274 GIC          30 :         fkconstraint->skip_validation = false;
  157 alvherre                19275 CBC          30 :         fkconstraint->initially_valid = true;
                              19276                 : 
 1539 alvherre                19277 GIC          30 :         createForeignKeyActionTriggers(partRel, conform->confrelid,
                              19278                 :                                        fkconstraint, fk->conoid,
                              19279                 :                                        conform->conindid,
  459 alvherre                19280 ECB             :                                        InvalidOid, InvalidOid,
                              19281                 :                                        NULL, NULL);
 1539                         19282                 : 
 1640 alvherre                19283 GIC          30 :         ReleaseSysCache(contup);
                              19284                 :     }
                              19285             195 :     list_free_deep(fks);
  459                         19286             195 :     if (trigrel)
                              19287              24 :         table_close(trigrel, RowExclusiveLock);
                              19288                 : 
                              19289                 :     /*
                              19290                 :      * Any sub-constraints that are in the referenced-side of a larger
                              19291                 :      * constraint have to be removed.  This partition is no longer part of the
                              19292                 :      * key space of the constraint.
                              19293                 :      */
 1467 alvherre                19294 CBC         213 :     foreach(cell, GetParentedForeignKeyRefs(partRel))
                              19295                 :     {
 1467 alvherre                19296 GIC          19 :         Oid         constrOid = lfirst_oid(cell);
                              19297                 :         ObjectAddress constraint;
                              19298                 : 
                              19299              19 :         ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
                              19300              19 :         deleteDependencyRecordsForClass(ConstraintRelationId,
                              19301                 :                                         constrOid,
                              19302                 :                                         ConstraintRelationId,
                              19303                 :                                         DEPENDENCY_INTERNAL);
 1467 alvherre                19304 CBC          19 :         CommandCounterIncrement();
                              19305                 : 
 1467 alvherre                19306 GIC          19 :         ObjectAddressSet(constraint, ConstraintRelationId, constrOid);
 1467 alvherre                19307 CBC          19 :         performDeletion(&constraint, DROP_RESTRICT, 0);
                              19308                 :     }
  745 alvherre                19309 ECB             : 
                              19310                 :     /* Now we can detach indexes */
  745 alvherre                19311 CBC         194 :     indexes = RelationGetIndexList(partRel);
                              19312             264 :     foreach(cell, indexes)
                              19313                 :     {
  745 alvherre                19314 GIC          70 :         Oid         idxid = lfirst_oid(cell);
  745 alvherre                19315 ECB             :         Relation    idx;
                              19316                 :         Oid         constrOid;
                              19317                 : 
  745 alvherre                19318 CBC          70 :         if (!has_superclass(idxid))
  745 alvherre                19319 GIC           6 :             continue;
  745 alvherre                19320 ECB             : 
  745 alvherre                19321 CBC          64 :         Assert((IndexGetRelation(get_partition_parent(idxid, false), false) ==
                              19322                 :                 RelationGetRelid(rel)));
                              19323                 : 
  745 alvherre                19324 GIC          64 :         idx = index_open(idxid, AccessExclusiveLock);
                              19325              64 :         IndexSetParentIndex(idx, InvalidOid);
                              19326                 : 
                              19327                 :         /* If there's a constraint associated with the index, detach it too */
                              19328              64 :         constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel),
                              19329                 :                                                     idxid);
  745 alvherre                19330 CBC          64 :         if (OidIsValid(constrOid))
  745 alvherre                19331 GIC          30 :             ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
  745 alvherre                19332 ECB             : 
  745 alvherre                19333 GIC          64 :         index_close(idx, NoLock);
  745 alvherre                19334 ECB             :     }
                              19335                 : 
                              19336                 :     /* Update pg_class tuple */
  745 alvherre                19337 CBC         194 :     classRel = table_open(RelationRelationId, RowExclusiveLock);
                              19338             194 :     tuple = SearchSysCacheCopy1(RELOID,
  745 alvherre                19339 ECB             :                                 ObjectIdGetDatum(RelationGetRelid(partRel)));
  745 alvherre                19340 GIC         194 :     if (!HeapTupleIsValid(tuple))
  745 alvherre                19341 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u",
                              19342                 :              RelationGetRelid(partRel));
  745 alvherre                19343 GIC         194 :     Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
                              19344                 : 
                              19345                 :     /* Clear relpartbound and reset relispartition */
  745 alvherre                19346 CBC         194 :     memset(new_val, 0, sizeof(new_val));
  745 alvherre                19347 GIC         194 :     memset(new_null, false, sizeof(new_null));
                              19348             194 :     memset(new_repl, false, sizeof(new_repl));
  745 alvherre                19349 CBC         194 :     new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
  745 alvherre                19350 GIC         194 :     new_null[Anum_pg_class_relpartbound - 1] = true;
                              19351             194 :     new_repl[Anum_pg_class_relpartbound - 1] = true;
                              19352             194 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
                              19353                 :                                  new_val, new_null, new_repl);
                              19354                 : 
                              19355             194 :     ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
  745 alvherre                19356 CBC         194 :     CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
  745 alvherre                19357 GIC         194 :     heap_freetuple(newtuple);
  745 alvherre                19358 CBC         194 :     table_close(classRel, RowExclusiveLock);
  745 alvherre                19359 ECB             : 
  745 alvherre                19360 GIC         194 :     if (OidIsValid(defaultPartOid))
                              19361                 :     {
  745 alvherre                19362 ECB             :         /*
                              19363                 :          * If the relation being detached is the default partition itself,
                              19364                 :          * remove it from the parent's pg_partitioned_table entry.
                              19365                 :          *
                              19366                 :          * If not, we must invalidate default partition's relcache entry, as
                              19367                 :          * in StorePartitionBound: its partition constraint depends on every
                              19368                 :          * other partition's partition constraint.
                              19369                 :          */
  745 alvherre                19370 GIC          23 :         if (RelationGetRelid(partRel) == defaultPartOid)
  745 alvherre                19371 GBC           1 :             update_default_partition_oid(RelationGetRelid(rel), InvalidOid);
  745 alvherre                19372 EUB             :         else
  745 alvherre                19373 GIC          22 :             CacheInvalidateRelcacheByRelid(defaultPartOid);
                              19374                 :     }
                              19375                 : 
 2314 rhaas                   19376 ECB             :     /*
 2308                         19377                 :      * Invalidate the parent's relcache so that the partition is no longer
                              19378                 :      * included in its partition descriptor.
                              19379                 :      */
 2314 rhaas                   19380 CBC         194 :     CacheInvalidateRelcache(rel);
                              19381                 : 
                              19382                 :     /*
                              19383                 :      * If the partition we just detached is partitioned itself, invalidate
                              19384                 :      * relcache for all descendent partitions too to ensure that their
                              19385                 :      * rd_partcheck expression trees are rebuilt; must lock partitions before
                              19386                 :      * doing so, using the same lockmode as what partRel has been locked with
  332 tgl                     19387 ECB             :      * by the caller.
                              19388                 :      */
  538 alvherre                19389 CBC         194 :     if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
  538 alvherre                19390 ECB             :     {
                              19391                 :         List       *children;
                              19392                 : 
  538 alvherre                19393 CBC          25 :         children = find_all_inheritors(RelationGetRelid(partRel),
  538 alvherre                19394 ECB             :                                        AccessExclusiveLock, NULL);
  538 alvherre                19395 GIC          81 :         foreach(cell, children)
  538 alvherre                19396 ECB             :         {
  538 alvherre                19397 CBC          56 :             CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
                              19398                 :         }
  538 alvherre                19399 ECB             :     }
  745 alvherre                19400 GIC         194 : }
                              19401                 : 
                              19402                 : /*
                              19403                 :  * ALTER TABLE ... DETACH PARTITION ... FINALIZE
                              19404                 :  *
                              19405                 :  * To use when a DETACH PARTITION command previously did not run to
                              19406                 :  * completion; this completes the detaching process.
                              19407                 :  */
                              19408                 : static ObjectAddress
  745 alvherre                19409 CBC           7 : ATExecDetachPartitionFinalize(Relation rel, RangeVar *name)
                              19410                 : {
                              19411                 :     Relation    partRel;
  745 alvherre                19412 ECB             :     ObjectAddress address;
  745 alvherre                19413 GIC           7 :     Snapshot    snap = GetActiveSnapshot();
                              19414                 : 
  745 alvherre                19415 CBC           7 :     partRel = table_openrv(name, AccessExclusiveLock);
  745 alvherre                19416 ECB             : 
                              19417                 :     /*
                              19418                 :      * Wait until existing snapshots are gone.  This is important if the
                              19419                 :      * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the
                              19420                 :      * user could immediately run DETACH FINALIZE without actually waiting for
                              19421                 :      * existing transactions.  We must not complete the detach action until
                              19422                 :      * all such queries are complete (otherwise we would present them with an
                              19423                 :      * inconsistent view of catalogs).
                              19424                 :      */
  745 alvherre                19425 GIC           7 :     WaitForOlderSnapshots(snap->xmin, false);
  745 alvherre                19426 ECB             : 
  745 alvherre                19427 CBC           7 :     DetachPartitionFinalize(rel, partRel, true, InvalidOid);
                              19428                 : 
 2314 rhaas                   19429 GIC           7 :     ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
                              19430                 : 
 1539 andres                  19431               7 :     table_close(partRel, NoLock);
                              19432                 : 
 2314 rhaas                   19433               7 :     return address;
                              19434                 : }
 1906 alvherre                19435 ECB             : 
                              19436                 : /*
                              19437                 :  * DetachAddConstraintIfNeeded
                              19438                 :  *      Subroutine for ATExecDetachPartition.  Create a constraint that
                              19439                 :  *      takes the place of the partition constraint, but avoid creating
  718                         19440                 :  *      a dupe if an constraint already exists which implies the needed
                              19441                 :  *      constraint.
                              19442                 :  */
                              19443                 : static void
  745 alvherre                19444 GIC          70 : DetachAddConstraintIfNeeded(List **wqueue, Relation partRel)
                              19445                 : {
                              19446                 :     List       *constraintExpr;
                              19447                 : 
  718 alvherre                19448 CBC          70 :     constraintExpr = RelationGetPartitionQual(partRel);
  718 alvherre                19449 GIC          70 :     constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr);
  745 alvherre                19450 ECB             : 
  718                         19451                 :     /*
                              19452                 :      * Avoid adding a new constraint if the needed constraint is implied by an
                              19453                 :      * existing constraint
                              19454                 :      */
  718 alvherre                19455 CBC          70 :     if (!PartConstraintImpliedByRelConstraint(partRel, constraintExpr))
  745 alvherre                19456 ECB             :     {
  718                         19457                 :         AlteredTableInfo *tab;
                              19458                 :         Constraint *n;
                              19459                 : 
  718 alvherre                19460 GIC          67 :         tab = ATGetQueueEntry(wqueue, partRel);
                              19461                 : 
  718 alvherre                19462 ECB             :         /* Add constraint on partition, equivalent to the partition constraint */
  718 alvherre                19463 GIC          67 :         n = makeNode(Constraint);
                              19464              67 :         n->contype = CONSTR_CHECK;
  718 alvherre                19465 CBC          67 :         n->conname = NULL;
  718 alvherre                19466 GIC          67 :         n->location = -1;
                              19467              67 :         n->is_no_inherit = false;
                              19468              67 :         n->raw_expr = NULL;
                              19469              67 :         n->cooked_expr = nodeToString(make_ands_explicit(constraintExpr));
                              19470              67 :         n->initially_valid = true;
                              19471              67 :         n->skip_validation = true;
  718 alvherre                19472 ECB             :         /* It's a re-add, since it nominally already exists */
  718 alvherre                19473 GIC          67 :         ATAddCheckConstraint(wqueue, tab, partRel, n,
                              19474                 :                              true, false, true, ShareUpdateExclusiveLock);
  745 alvherre                19475 ECB             :     }
  745 alvherre                19476 GIC          70 : }
  745 alvherre                19477 ECB             : 
 1083                         19478                 : /*
                              19479                 :  * DropClonedTriggersFromPartition
                              19480                 :  *      subroutine for ATExecDetachPartition to remove any triggers that were
                              19481                 :  *      cloned to the partition when it was created-as-partition or attached.
                              19482                 :  *      This undoes what CloneRowTriggersToPartition did.
                              19483                 :  */
                              19484                 : static void
 1083 alvherre                19485 GIC         195 : DropClonedTriggersFromPartition(Oid partitionId)
                              19486                 : {
                              19487                 :     ScanKeyData skey;
                              19488                 :     SysScanDesc scan;
 1083 alvherre                19489 ECB             :     HeapTuple   trigtup;
                              19490                 :     Relation    tgrel;
                              19491                 :     ObjectAddresses *objects;
                              19492                 : 
 1083 alvherre                19493 GIC         195 :     objects = new_object_addresses();
                              19494                 : 
                              19495                 :     /*
                              19496                 :      * Scan pg_trigger to search for all triggers on this rel.
 1083 alvherre                19497 ECB             :      */
 1083 alvherre                19498 GIC         195 :     ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
 1083 alvherre                19499 ECB             :                 F_OIDEQ, ObjectIdGetDatum(partitionId));
 1083 alvherre                19500 CBC         195 :     tgrel = table_open(TriggerRelationId, RowExclusiveLock);
 1083 alvherre                19501 GIC         195 :     scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
                              19502                 :                               true, NULL, 1, &skey);
 1083 alvherre                19503 CBC         320 :     while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
                              19504                 :     {
 1083 alvherre                19505 GIC         125 :         Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup);
 1083 alvherre                19506 ECB             :         ObjectAddress trig;
                              19507                 : 
                              19508                 :         /* Ignore triggers that weren't cloned */
 1083 alvherre                19509 GIC         125 :         if (!OidIsValid(pg_trigger->tgparentid))
 1083 alvherre                19510 CBC         116 :             continue;
                              19511                 : 
                              19512                 :         /*
  459 alvherre                19513 ECB             :          * Ignore internal triggers that are implementation objects of foreign
                              19514                 :          * keys, because these will be detached when the foreign keys
                              19515                 :          * themselves are.
                              19516                 :          */
  459 alvherre                19517 GIC         107 :         if (OidIsValid(pg_trigger->tgconstrrelid))
                              19518              98 :             continue;
                              19519                 : 
 1083 alvherre                19520 ECB             :         /*
                              19521                 :          * This is ugly, but necessary: remove the dependency markings on the
                              19522                 :          * trigger so that it can be removed.
                              19523                 :          */
 1083 alvherre                19524 GIC           9 :         deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
                              19525                 :                                         TriggerRelationId,
                              19526                 :                                         DEPENDENCY_PARTITION_PRI);
 1083 alvherre                19527 CBC           9 :         deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
 1083 alvherre                19528 ECB             :                                         RelationRelationId,
                              19529                 :                                         DEPENDENCY_PARTITION_SEC);
                              19530                 : 
                              19531                 :         /* remember this trigger to remove it below */
 1083 alvherre                19532 GIC           9 :         ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid);
 1083 alvherre                19533 CBC           9 :         add_exact_object_address(&trig, objects);
 1083 alvherre                19534 ECB             :     }
 1083 alvherre                19535 EUB             : 
                              19536                 :     /* make the dependency removal visible to the deletion below */
 1083 alvherre                19537 GIC         195 :     CommandCounterIncrement();
                              19538             195 :     performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
 1083 alvherre                19539 ECB             : 
                              19540                 :     /* done */
 1083 alvherre                19541 GIC         195 :     free_object_addresses(objects);
                              19542             195 :     systable_endscan(scan);
                              19543             195 :     table_close(tgrel, RowExclusiveLock);
                              19544             195 : }
 1083 alvherre                19545 ECB             : 
                              19546                 : /*
 1906                         19547                 :  * Before acquiring lock on an index, acquire the same lock on the owning
                              19548                 :  * table.
                              19549                 :  */
                              19550                 : struct AttachIndexCallbackState
                              19551                 : {
 1809 tgl                     19552                 :     Oid         partitionOid;
                              19553                 :     Oid         parentTblOid;
                              19554                 :     bool        lockedParentTbl;
                              19555                 : };
                              19556                 : 
                              19557                 : static void
 1906 alvherre                19558 GIC         193 : RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
                              19559                 :                                void *arg)
 1906 alvherre                19560 ECB             : {
                              19561                 :     struct AttachIndexCallbackState *state;
                              19562                 :     Form_pg_class classform;
                              19563                 :     HeapTuple   tuple;
                              19564                 : 
 1906 alvherre                19565 GIC         193 :     state = (struct AttachIndexCallbackState *) arg;
                              19566                 : 
                              19567             193 :     if (!state->lockedParentTbl)
 1906 alvherre                19568 ECB             :     {
 1906 alvherre                19569 GIC         186 :         LockRelationOid(state->parentTblOid, AccessShareLock);
 1906 alvherre                19570 CBC         186 :         state->lockedParentTbl = true;
 1906 alvherre                19571 ECB             :     }
                              19572                 : 
                              19573                 :     /*
                              19574                 :      * If we previously locked some other heap, and the name we're looking up
                              19575                 :      * no longer refers to an index on that relation, release the now-useless
                              19576                 :      * lock.  XXX maybe we should do *after* we verify whether the index does
                              19577                 :      * not actually belong to the same relation ...
                              19578                 :      */
 1906 alvherre                19579 GIC         193 :     if (relOid != oldRelOid && OidIsValid(state->partitionOid))
 1906 alvherre                19580 ECB             :     {
 1906 alvherre                19581 UIC           0 :         UnlockRelationOid(state->partitionOid, AccessShareLock);
 1906 alvherre                19582 LBC           0 :         state->partitionOid = InvalidOid;
 1906 alvherre                19583 EUB             :     }
                              19584                 : 
                              19585                 :     /* Didn't find a relation, so no need for locking or permission checks. */
 1906 alvherre                19586 CBC         193 :     if (!OidIsValid(relOid))
 1906 alvherre                19587 GIC           3 :         return;
 1906 alvherre                19588 ECB             : 
 1906 alvherre                19589 GIC         190 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
 1906 alvherre                19590 CBC         190 :     if (!HeapTupleIsValid(tuple))
 1906 alvherre                19591 LBC           0 :         return;                 /* concurrently dropped, so nothing to do */
 1906 alvherre                19592 GIC         190 :     classform = (Form_pg_class) GETSTRUCT(tuple);
                              19593             190 :     if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
                              19594             147 :         classform->relkind != RELKIND_INDEX)
 1906 alvherre                19595 CBC           3 :         ereport(ERROR,
 1906 alvherre                19596 ECB             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              19597                 :                  errmsg("\"%s\" is not an index", rv->relname)));
 1906 alvherre                19598 CBC         187 :     ReleaseSysCache(tuple);
 1906 alvherre                19599 ECB             : 
                              19600                 :     /*
                              19601                 :      * Since we need only examine the heap's tupledesc, an access share lock
                              19602                 :      * on it (preventing any DDL) is sufficient.
                              19603                 :      */
 1906 alvherre                19604 CBC         187 :     state->partitionOid = IndexGetRelation(relOid, false);
                              19605             187 :     LockRelationOid(state->partitionOid, AccessShareLock);
 1906 alvherre                19606 ECB             : }
                              19607                 : 
                              19608                 : /*
                              19609                 :  * ALTER INDEX i1 ATTACH PARTITION i2
                              19610                 :  */
                              19611                 : static ObjectAddress
 1906 alvherre                19612 CBC         186 : ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
                              19613                 : {
                              19614                 :     Relation    partIdx;
 1906 alvherre                19615 ECB             :     Relation    partTbl;
                              19616                 :     Relation    parentTbl;
                              19617                 :     ObjectAddress address;
                              19618                 :     Oid         partIdxId;
                              19619                 :     Oid         currParent;
                              19620                 :     struct AttachIndexCallbackState state;
                              19621                 : 
                              19622                 :     /*
                              19623                 :      * We need to obtain lock on the index 'name' to modify it, but we also
                              19624                 :      * need to read its owning table's tuple descriptor -- so we need to lock
                              19625                 :      * both.  To avoid deadlocks, obtain lock on the table before doing so on
                              19626                 :      * the index.  Furthermore, we need to examine the parent table of the
                              19627                 :      * partition, so lock that one too.
                              19628                 :      */
 1906 alvherre                19629 GIC         186 :     state.partitionOid = InvalidOid;
                              19630             186 :     state.parentTblOid = parentIdx->rd_index->indrelid;
                              19631             186 :     state.lockedParentTbl = false;
                              19632                 :     partIdxId =
 1836 andres                  19633             186 :         RangeVarGetRelidExtended(name, AccessExclusiveLock, 0,
                              19634                 :                                  RangeVarCallbackForAttachIndex,
                              19635                 :                                  (void *) &state);
                              19636                 :     /* Not there? */
 1906 alvherre                19637             180 :     if (!OidIsValid(partIdxId))
 1906 alvherre                19638 UIC           0 :         ereport(ERROR,
                              19639                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              19640                 :                  errmsg("index \"%s\" does not exist", name->relname)));
                              19641                 : 
                              19642                 :     /* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
 1906 alvherre                19643 GIC         180 :     partIdx = relation_open(partIdxId, AccessExclusiveLock);
                              19644                 : 
                              19645                 :     /* we already hold locks on both tables, so this is safe: */
 1906 alvherre                19646 CBC         180 :     parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
 1906 alvherre                19647 GIC         180 :     partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
                              19648                 : 
                              19649             180 :     ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
                              19650                 : 
                              19651                 :     /* Silently do nothing if already in the right state */
 1824                         19652             360 :     currParent = partIdx->rd_rel->relispartition ?
  745                         19653             180 :         get_partition_parent(partIdxId, false) : InvalidOid;
 1906                         19654             180 :     if (currParent != RelationGetRelid(parentIdx))
                              19655                 :     {
                              19656                 :         IndexInfo  *childInfo;
                              19657                 :         IndexInfo  *parentInfo;
 1208 michael                 19658 ECB             :         AttrMap    *attmap;
 1906 alvherre                19659                 :         bool        found;
                              19660                 :         int         i;
                              19661                 :         PartitionDesc partDesc;
                              19662                 :         Oid         constraintOid,
 1875 alvherre                19663 GIC         174 :                     cldConstrId = InvalidOid;
                              19664                 : 
                              19665                 :         /*
                              19666                 :          * If this partition already has an index attached, refuse the
                              19667                 :          * operation.
                              19668                 :          */
 1906                         19669             174 :         refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
                              19670                 : 
                              19671             171 :         if (OidIsValid(currParent))
 1906 alvherre                19672 UIC           0 :             ereport(ERROR,
                              19673                 :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19674                 :                      errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              19675                 :                             RelationGetRelationName(partIdx),
 1906 alvherre                19676 ECB             :                             RelationGetRelationName(parentIdx)),
                              19677                 :                      errdetail("Index \"%s\" is already attached to another index.",
                              19678                 :                                RelationGetRelationName(partIdx))));
                              19679                 : 
                              19680                 :         /* Make sure it indexes a partition of the other index's table */
  717 alvherre                19681 GIC         171 :         partDesc = RelationGetPartitionDesc(parentTbl, true);
 1906                         19682             171 :         found = false;
                              19683             272 :         for (i = 0; i < partDesc->nparts; i++)
                              19684                 :         {
                              19685             269 :             if (partDesc->oids[i] == state.partitionOid)
                              19686                 :             {
                              19687             168 :                 found = true;
 1906 alvherre                19688 CBC         168 :                 break;
                              19689                 :             }
                              19690                 :         }
 1906 alvherre                19691 GIC         171 :         if (!found)
                              19692               3 :             ereport(ERROR,
                              19693                 :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19694                 :                      errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
 1906 alvherre                19695 ECB             :                             RelationGetRelationName(partIdx),
                              19696                 :                             RelationGetRelationName(parentIdx)),
                              19697                 :                      errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
                              19698                 :                                RelationGetRelationName(partIdx),
                              19699                 :                                RelationGetRelationName(parentTbl))));
                              19700                 : 
                              19701                 :         /* Ensure the indexes are compatible */
 1906 alvherre                19702 GIC         168 :         childInfo = BuildIndexInfo(partIdx);
                              19703             168 :         parentInfo = BuildIndexInfo(parentIdx);
 1208 michael                 19704             168 :         attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
                              19705                 :                                        RelationGetDescr(parentTbl),
                              19706                 :                                        false);
 1906 alvherre                19707             168 :         if (!CompareIndexInfo(childInfo, parentInfo,
 1906 alvherre                19708 ECB             :                               partIdx->rd_indcollation,
                              19709                 :                               parentIdx->rd_indcollation,
                              19710                 :                               partIdx->rd_opfamily,
                              19711                 :                               parentIdx->rd_opfamily,
                              19712                 :                               attmap))
 1906 alvherre                19713 GIC          21 :             ereport(ERROR,
                              19714                 :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              19715                 :                      errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              19716                 :                             RelationGetRelationName(partIdx),
 1906 alvherre                19717 ECB             :                             RelationGetRelationName(parentIdx)),
                              19718                 :                      errdetail("The index definitions do not match.")));
                              19719                 : 
                              19720                 :         /*
                              19721                 :          * If there is a constraint in the parent, make sure there is one in
                              19722                 :          * the child too.
                              19723                 :          */
 1875 alvherre                19724 GIC         147 :         constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
                              19725                 :                                                         RelationGetRelid(parentIdx));
                              19726                 : 
                              19727             147 :         if (OidIsValid(constraintOid))
                              19728                 :         {
 1875 alvherre                19729 CBC          64 :             cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
                              19730                 :                                                           partIdxId);
 1875 alvherre                19731 GIC          64 :             if (!OidIsValid(cldConstrId))
                              19732               3 :                 ereport(ERROR,
                              19733                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              19734                 :                          errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              19735                 :                                 RelationGetRelationName(partIdx),
                              19736                 :                                 RelationGetRelationName(parentIdx)),
                              19737                 :                          errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
                              19738                 :                                    RelationGetRelationName(parentIdx),
                              19739                 :                                    RelationGetRelationName(parentTbl),
                              19740                 :                                    RelationGetRelationName(partIdx))));
                              19741                 :         }
 1875 alvherre                19742 ECB             : 
                              19743                 :         /*
                              19744                 :          * If it's a primary key, make sure the columns in the partition are
                              19745                 :          * NOT NULL.
                              19746                 :          */
    2 alvherre                19747 GNC         144 :         if (parentIdx->rd_index->indisprimary)
                              19748              49 :             verifyPartitionIndexNotNull(childInfo, partTbl);
                              19749                 : 
 1906 alvherre                19750 ECB             :         /* All good -- do it */
 1906 alvherre                19751 CBC         141 :         IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
 1875                         19752             141 :         if (OidIsValid(constraintOid))
 1518 tgl                     19753              58 :             ConstraintSetParentConstraint(cldConstrId, constraintOid,
 1518 tgl                     19754 ECB             :                                           RelationGetRelid(partTbl));
                              19755                 : 
 1208 michael                 19756 GIC         141 :         free_attrmap(attmap);
 1906 alvherre                19757 ECB             : 
 1906 alvherre                19758 GIC         141 :         validatePartitionedIndex(parentIdx, parentTbl);
 1906 alvherre                19759 ECB             :     }
                              19760                 : 
 1906 alvherre                19761 CBC         147 :     relation_close(parentTbl, AccessShareLock);
                              19762                 :     /* keep these locks till commit */
 1906 alvherre                19763 GIC         147 :     relation_close(partTbl, NoLock);
 1906 alvherre                19764 CBC         147 :     relation_close(partIdx, NoLock);
 1906 alvherre                19765 ECB             : 
 1906 alvherre                19766 GIC         147 :     return address;
 1906 alvherre                19767 ECB             : }
                              19768                 : 
                              19769                 : /*
                              19770                 :  * Verify whether the given partition already contains an index attached
                              19771                 :  * to the given partitioned index.  If so, raise an error.
                              19772                 :  */
                              19773                 : static void
 1906 alvherre                19774 GIC         174 : refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
                              19775                 : {
                              19776                 :     Oid         existingIdx;
                              19777                 : 
 1481 alvherre                19778 CBC         174 :     existingIdx = index_get_partition(partitionTbl,
 1481 alvherre                19779 ECB             :                                       RelationGetRelid(parentIdx));
 1481 alvherre                19780 GIC         174 :     if (OidIsValid(existingIdx))
                              19781               3 :         ereport(ERROR,
                              19782                 :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19783                 :                  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              19784                 :                         RelationGetRelationName(partIdx),
 1481 alvherre                19785 ECB             :                         RelationGetRelationName(parentIdx)),
                              19786                 :                  errdetail("Another index is already attached for partition \"%s\".",
                              19787                 :                            RelationGetRelationName(partitionTbl))));
 1906 alvherre                19788 GIC         171 : }
 1906 alvherre                19789 ECB             : 
                              19790                 : /*
 1906 alvherre                19791 EUB             :  * Verify whether the set of attached partition indexes to a parent index on
                              19792                 :  * a partitioned table is complete.  If it is, mark the parent index valid.
                              19793                 :  *
                              19794                 :  * This should be called each time a partition index is attached.
                              19795                 :  */
                              19796                 : static void
 1906 alvherre                19797 GIC         159 : validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
                              19798                 : {
 1809 tgl                     19799 ECB             :     Relation    inheritsRel;
 1809 tgl                     19800 EUB             :     SysScanDesc scan;
                              19801                 :     ScanKeyData key;
 1809 tgl                     19802 GIC         159 :     int         tuples = 0;
                              19803                 :     HeapTuple   inhTup;
 1809 tgl                     19804 CBC         159 :     bool        updated = false;
                              19805                 : 
 1906 alvherre                19806 GIC         159 :     Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
                              19807                 : 
 1906 alvherre                19808 ECB             :     /*
                              19809                 :      * Scan pg_inherits for this parent index.  Count each valid index we find
                              19810                 :      * (verifying the pg_index entry for each), and if we reach the total
                              19811                 :      * amount we expect, we can mark this parent index as valid.
                              19812                 :      */
 1539 andres                  19813 CBC         159 :     inheritsRel = table_open(InheritsRelationId, AccessShareLock);
 1906 alvherre                19814 GIC         159 :     ScanKeyInit(&key, Anum_pg_inherits_inhparent,
 1906 alvherre                19815 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                              19816                 :                 ObjectIdGetDatum(RelationGetRelid(partedIdx)));
 1906 alvherre                19817 GIC         159 :     scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
                              19818                 :                               NULL, 1, &key);
                              19819             420 :     while ((inhTup = systable_getnext(scan)) != NULL)
                              19820                 :     {
                              19821             261 :         Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
                              19822                 :         HeapTuple   indTup;
                              19823                 :         Form_pg_index indexForm;
                              19824                 : 
 1906 alvherre                19825 CBC         261 :         indTup = SearchSysCache1(INDEXRELID,
                              19826                 :                                  ObjectIdGetDatum(inhForm->inhrelid));
 1435 tgl                     19827 GIC         261 :         if (!HeapTupleIsValid(indTup))
 1435 tgl                     19828 UIC           0 :             elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
 1906 alvherre                19829 GIC         261 :         indexForm = (Form_pg_index) GETSTRUCT(indTup);
 1564 peter_e                 19830             261 :         if (indexForm->indisvalid)
 1906 alvherre                19831             235 :             tuples += 1;
                              19832             261 :         ReleaseSysCache(indTup);
                              19833                 :     }
                              19834                 : 
                              19835                 :     /* Done with pg_inherits */
                              19836             159 :     systable_endscan(scan);
 1539 andres                  19837 CBC         159 :     table_close(inheritsRel, AccessShareLock);
                              19838                 : 
 1906 alvherre                19839 ECB             :     /*
                              19840                 :      * If we found as many inherited indexes as the partitioned table has
                              19841                 :      * partitions, we're good; update pg_index to set indisvalid.
                              19842                 :      */
  717 alvherre                19843 GIC         159 :     if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts)
                              19844                 :     {
 1906 alvherre                19845 ECB             :         Relation    idxRel;
                              19846                 :         HeapTuple   newtup;
                              19847                 : 
 1539 andres                  19848 GIC          77 :         idxRel = table_open(IndexRelationId, RowExclusiveLock);
 1906 alvherre                19849 ECB             : 
 1906 alvherre                19850 GIC          77 :         newtup = heap_copytuple(partedIdx->rd_indextuple);
                              19851              77 :         ((Form_pg_index) GETSTRUCT(newtup))->indisvalid = true;
                              19852              77 :         updated = true;
                              19853                 : 
                              19854              77 :         CatalogTupleUpdate(idxRel, &partedIdx->rd_indextuple->t_self, newtup);
 1906 alvherre                19855 ECB             : 
 1539 andres                  19856 CBC          77 :         table_close(idxRel, RowExclusiveLock);
 1906 alvherre                19857 ECB             :     }
                              19858                 : 
                              19859                 :     /*
                              19860                 :      * If this index is in turn a partition of a larger index, validating it
                              19861                 :      * might cause the parent to become valid also.  Try that.
                              19862                 :      */
 1824 alvherre                19863 GIC         159 :     if (updated && partedIdx->rd_rel->relispartition)
                              19864                 :     {
                              19865                 :         Oid         parentIdxId,
                              19866                 :                     parentTblId;
 1906 alvherre                19867 ECB             :         Relation    parentIdx,
                              19868                 :                     parentTbl;
 1906 alvherre                19869 EUB             : 
 1906 alvherre                19870 ECB             :         /* make sure we see the validation we just did */
 1906 alvherre                19871 GIC          18 :         CommandCounterIncrement();
                              19872                 : 
  745 alvherre                19873 CBC          18 :         parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false);
                              19874              18 :         parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false);
 1906 alvherre                19875 GIC          18 :         parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
 1906 alvherre                19876 CBC          18 :         parentTbl = relation_open(parentTblId, AccessExclusiveLock);
                              19877              18 :         Assert(!parentIdx->rd_index->indisvalid);
                              19878                 : 
 1906 alvherre                19879 GIC          18 :         validatePartitionedIndex(parentIdx, parentTbl);
                              19880                 : 
 1906 alvherre                19881 CBC          18 :         relation_close(parentIdx, AccessExclusiveLock);
 1906 alvherre                19882 GIC          18 :         relation_close(parentTbl, AccessExclusiveLock);
                              19883                 :     }
                              19884             159 : }
                              19885                 : 
                              19886                 : /*
                              19887                 :  * When attaching an index as a partition of a partitioned index which is a
                              19888                 :  * primary key, verify that all the columns in the partition are marked NOT
                              19889                 :  * NULL.
                              19890                 :  */
                              19891                 : static void
    2 alvherre                19892 GNC          49 : verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partition)
                              19893                 : {
                              19894              96 :     for (int i = 0; i < iinfo->ii_NumIndexKeyAttrs; i++)
                              19895                 :     {
                              19896              50 :         Form_pg_attribute att = TupleDescAttr(RelationGetDescr(partition),
                              19897                 :                                               iinfo->ii_IndexAttrNumbers[i] - 1);
                              19898                 : 
                              19899              50 :         if (!att->attnotnull)
                              19900               3 :             ereport(ERROR,
                              19901                 :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              19902                 :                     errmsg("invalid primary key definition"),
                              19903                 :                     errdetail("Column \"%s\" of relation \"%s\" is not marked NOT NULL.",
                              19904                 :                               NameStr(att->attname),
                              19905                 :                               RelationGetRelationName(partition)));
                              19906                 :     }
                              19907              46 : }
                              19908                 : 
                              19909                 : /*
 1467 alvherre                19910 ECB             :  * Return an OID list of constraints that reference the given relation
                              19911                 :  * that are marked as having a parent constraints.
                              19912                 :  */
                              19913                 : static List *
 1467 alvherre                19914 CBC         425 : GetParentedForeignKeyRefs(Relation partition)
                              19915                 : {
 1467 alvherre                19916 ECB             :     Relation    pg_constraint;
                              19917                 :     HeapTuple   tuple;
                              19918                 :     SysScanDesc scan;
                              19919                 :     ScanKeyData key[2];
 1467 alvherre                19920 GIC         425 :     List       *constraints = NIL;
                              19921                 : 
                              19922                 :     /*
                              19923                 :      * If no indexes, or no columns are referenceable by FKs, we can avoid the
                              19924                 :      * scan.
 1467 alvherre                19925 ECB             :      */
 1467 alvherre                19926 CBC         591 :     if (RelationGetIndexList(partition) == NIL ||
                              19927             166 :         bms_is_empty(RelationGetIndexAttrBitmap(partition,
 1467 alvherre                19928 ECB             :                                                 INDEX_ATTR_BITMAP_KEY)))
 1467 alvherre                19929 CBC         337 :         return NIL;
 1467 alvherre                19930 ECB             : 
                              19931                 :     /* Search for constraints referencing this table */
 1467 alvherre                19932 CBC          88 :     pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
                              19933              88 :     ScanKeyInit(&key[0],
 1467 alvherre                19934 ECB             :                 Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
                              19935                 :                 F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition)));
 1467 alvherre                19936 CBC          88 :     ScanKeyInit(&key[1],
 1467 alvherre                19937 ECB             :                 Anum_pg_constraint_contype, BTEqualStrategyNumber,
                              19938                 :                 F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
                              19939                 : 
                              19940                 :     /* XXX This is a seqscan, as we don't have a usable index */
 1467 alvherre                19941 CBC          88 :     scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key);
 1467 alvherre                19942 GIC         150 :     while ((tuple = systable_getnext(scan)) != NULL)
 1467 alvherre                19943 ECB             :     {
 1467 alvherre                19944 GIC          62 :         Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              19945                 : 
                              19946                 :         /*
                              19947                 :          * We only need to process constraints that are part of larger ones.
                              19948                 :          */
 1467 alvherre                19949 CBC          62 :         if (!OidIsValid(constrForm->conparentid))
 1467 alvherre                19950 UIC           0 :             continue;
 1467 alvherre                19951 ECB             : 
 1467 alvherre                19952 CBC          62 :         constraints = lappend_oid(constraints, constrForm->oid);
 1467 alvherre                19953 ECB             :     }
                              19954                 : 
 1467 alvherre                19955 GIC          88 :     systable_endscan(scan);
                              19956              88 :     table_close(pg_constraint, AccessShareLock);
                              19957                 : 
                              19958              88 :     return constraints;
                              19959                 : }
 1467 alvherre                19960 ECB             : 
                              19961                 : /*
                              19962                 :  * During DETACH PARTITION, verify that any foreign keys pointing to the
                              19963                 :  * partitioned table would not become invalid.  An error is raised if any
                              19964                 :  * referenced values exist.
                              19965                 :  */
                              19966                 : static void
 1467 alvherre                19967 GIC         230 : ATDetachCheckNoForeignKeyRefs(Relation partition)
                              19968                 : {
                              19969                 :     List       *constraints;
 1467 alvherre                19970 ECB             :     ListCell   *cell;
                              19971                 : 
 1467 alvherre                19972 CBC         230 :     constraints = GetParentedForeignKeyRefs(partition);
 1467 alvherre                19973 ECB             : 
 1467 alvherre                19974 GIC         256 :     foreach(cell, constraints)
                              19975                 :     {
                              19976              43 :         Oid         constrOid = lfirst_oid(cell);
 1467 alvherre                19977 ECB             :         HeapTuple   tuple;
                              19978                 :         Form_pg_constraint constrForm;
                              19979                 :         Relation    rel;
  267 peter                   19980 GNC          43 :         Trigger     trig = {0};
                              19981                 : 
 1467 alvherre                19982 GIC          43 :         tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
                              19983              43 :         if (!HeapTupleIsValid(tuple))
 1467 alvherre                19984 LBC           0 :             elog(ERROR, "cache lookup failed for constraint %u", constrOid);
 1467 alvherre                19985 CBC          43 :         constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              19986                 : 
                              19987              43 :         Assert(OidIsValid(constrForm->conparentid));
 1467 alvherre                19988 GIC          43 :         Assert(constrForm->confrelid == RelationGetRelid(partition));
                              19989                 : 
 1467 alvherre                19990 ECB             :         /* prevent data changes into the referencing table until commit */
 1467 alvherre                19991 CBC          43 :         rel = table_open(constrForm->conrelid, ShareLock);
                              19992                 : 
                              19993              43 :         trig.tgoid = InvalidOid;
 1467 alvherre                19994 GIC          43 :         trig.tgname = NameStr(constrForm->conname);
 1467 alvherre                19995 CBC          43 :         trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
                              19996              43 :         trig.tgisinternal = true;
 1467 alvherre                19997 GIC          43 :         trig.tgconstrrelid = RelationGetRelid(partition);
 1467 alvherre                19998 CBC          43 :         trig.tgconstrindid = constrForm->conindid;
 1467 alvherre                19999 GIC          43 :         trig.tgconstraint = constrForm->oid;
                              20000              43 :         trig.tgdeferrable = false;
                              20001              43 :         trig.tginitdeferred = false;
 1467 alvherre                20002 ECB             :         /* we needn't fill in remaining fields */
                              20003                 : 
 1467 alvherre                20004 GIC          43 :         RI_PartitionRemove_Check(&trig, rel, partition);
 1467 alvherre                20005 ECB             : 
 1467 alvherre                20006 GBC          26 :         ReleaseSysCache(tuple);
                              20007                 : 
 1467 alvherre                20008 CBC          26 :         table_close(rel, NoLock);
                              20009                 :     }
 1467 alvherre                20010 GIC         213 : }
  888 tmunro                  20011 ECB             : 
  751 rhaas                   20012                 : /*
                              20013                 :  * resolve column compression specification to compression method.
                              20014                 :  */
                              20015                 : static char
  682 tgl                     20016 CBC        1195 : GetAttributeCompression(Oid atttypid, char *compression)
  751 rhaas                   20017 ECB             : {
                              20018                 :     char        cmethod;
                              20019                 : 
  682 tgl                     20020 CBC        1195 :     if (compression == NULL || strcmp(compression, "default") == 0)
                              20021            1124 :         return InvalidCompressionMethod;
  682 tgl                     20022 ECB             : 
  751 rhaas                   20023                 :     /*
                              20024                 :      * To specify a nondefault method, the column data type must be toastable.
  682 tgl                     20025                 :      * Note this says nothing about whether the column's attstorage setting
                              20026                 :      * permits compression; we intentionally allow attstorage and
                              20027                 :      * attcompression to be independent.  But with a non-toastable type,
                              20028                 :      * attstorage could not be set to a value that would permit compression.
                              20029                 :      *
                              20030                 :      * We don't actually need to enforce this, since nothing bad would happen
                              20031                 :      * if attcompression were non-default; it would never be consulted.  But
                              20032                 :      * it seems more user-friendly to complain about a certainly-useless
                              20033                 :      * attempt to set the property.
                              20034                 :      */
  682 tgl                     20035 CBC          71 :     if (!TypeIsToastable(atttypid))
  751 rhaas                   20036               3 :         ereport(ERROR,
                              20037                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  751 rhaas                   20038 ECB             :                  errmsg("column data type %s does not support compression",
                              20039                 :                         format_type_be(atttypid))));
                              20040                 : 
  748 rhaas                   20041 GIC          68 :     cmethod = CompressionNameToMethod(compression);
                              20042              68 :     if (!CompressionMethodIsValid(cmethod))
                              20043               6 :         ereport(ERROR,
                              20044                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  748 rhaas                   20045 ECB             :                  errmsg("invalid compression method \"%s\"", compression)));
                              20046                 : 
  751 rhaas                   20047 GIC          62 :     return cmethod;
                              20048                 : }
                              20049                 : 
                              20050                 : /*
                              20051                 :  * resolve column storage specification
                              20052                 :  */
                              20053                 : static char
  270 peter                   20054 GNC         115 : GetAttributeStorage(Oid atttypid, const char *storagemode)
                              20055                 : {
                              20056             115 :     char        cstorage = 0;
                              20057                 : 
                              20058             115 :     if (pg_strcasecmp(storagemode, "plain") == 0)
                              20059              23 :         cstorage = TYPSTORAGE_PLAIN;
                              20060              92 :     else if (pg_strcasecmp(storagemode, "external") == 0)
                              20061              75 :         cstorage = TYPSTORAGE_EXTERNAL;
                              20062              17 :     else if (pg_strcasecmp(storagemode, "extended") == 0)
                              20063               7 :         cstorage = TYPSTORAGE_EXTENDED;
                              20064              10 :     else if (pg_strcasecmp(storagemode, "main") == 0)
                              20065               7 :         cstorage = TYPSTORAGE_MAIN;
  150 tgl                     20066               3 :     else if (pg_strcasecmp(storagemode, "default") == 0)
                              20067               3 :         cstorage = get_typstorage(atttypid);
                              20068                 :     else
  270 peter                   20069 UNC           0 :         ereport(ERROR,
                              20070                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                              20071                 :                  errmsg("invalid storage type \"%s\"",
                              20072                 :                         storagemode)));
                              20073                 : 
                              20074                 :     /*
                              20075                 :      * safety check: do not allow toasted storage modes unless column datatype
                              20076                 :      * is TOAST-aware.
                              20077                 :      */
  270 peter                   20078 GNC         115 :     if (!(cstorage == TYPSTORAGE_PLAIN || TypeIsToastable(atttypid)))
                              20079               3 :         ereport(ERROR,
                              20080                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              20081                 :                  errmsg("column data type %s can only have storage PLAIN",
                              20082                 :                         format_type_be(atttypid))));
                              20083                 : 
                              20084             112 :     return cstorage;
                              20085                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a