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 ECB DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 91.9 % 6920 6359 66 495 7 8 1159 5185 4 29 468
Current Date: 2024-04-14 14:21:10 Functions: 99.5 % 202 201 1 81 120 17
Baseline: 16@8cea358b128 Branches: 71.4 % 5621 4013 256 10 6 1336 21 8 832 3152 2
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 93.0 % 426 396 24 6 1 376 19
(60,120] days: 93.9 % 314 295 13 6 221 74
(120,180] days: 100.0 % 8 8 5 3
(180,240] days: 95.8 % 545 522 23 514 8
(240..) days: 91.3 % 5627 5138 6 483 6 8 43 5081 4
Function coverage date bins:
[..60] days: 100.0 % 11 11 10 1
(60,120] days: 100.0 % 9 9 9
(180,240] days: 100.0 % 15 15 15
(240..) days: 99.4 % 167 166 1 47 119
Branch coverage date bins:
[..60] days: 73.5 % 359 264 92 3 258 6
(60,120] days: 68.7 % 252 173 59 20 157 16
(120,180] days: 75.0 % 4 3 1 3
(180,240] days: 81.3 % 486 395 90 1 390 5
(240..) days: 70.3 % 4522 3178 15 10 6 1311 21 8 27 3122 2

 Age         Owner                    Branch data    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-2024, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/commands/tablecmds.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include "access/attmap.h"
                                 18                 :                : #include "access/genam.h"
                                 19                 :                : #include "access/gist.h"
                                 20                 :                : #include "access/heapam.h"
                                 21                 :                : #include "access/heapam_xlog.h"
                                 22                 :                : #include "access/multixact.h"
                                 23                 :                : #include "access/reloptions.h"
                                 24                 :                : #include "access/relscan.h"
                                 25                 :                : #include "access/sysattr.h"
                                 26                 :                : #include "access/tableam.h"
                                 27                 :                : #include "access/toast_compression.h"
                                 28                 :                : #include "access/xact.h"
                                 29                 :                : #include "access/xlog.h"
                                 30                 :                : #include "access/xloginsert.h"
                                 31                 :                : #include "catalog/catalog.h"
                                 32                 :                : #include "catalog/heap.h"
                                 33                 :                : #include "catalog/index.h"
                                 34                 :                : #include "catalog/namespace.h"
                                 35                 :                : #include "catalog/objectaccess.h"
                                 36                 :                : #include "catalog/partition.h"
                                 37                 :                : #include "catalog/pg_am.h"
                                 38                 :                : #include "catalog/pg_attrdef.h"
                                 39                 :                : #include "catalog/pg_collation.h"
                                 40                 :                : #include "catalog/pg_constraint.h"
                                 41                 :                : #include "catalog/pg_depend.h"
                                 42                 :                : #include "catalog/pg_foreign_table.h"
                                 43                 :                : #include "catalog/pg_inherits.h"
                                 44                 :                : #include "catalog/pg_largeobject.h"
                                 45                 :                : #include "catalog/pg_namespace.h"
                                 46                 :                : #include "catalog/pg_opclass.h"
                                 47                 :                : #include "catalog/pg_policy.h"
                                 48                 :                : #include "catalog/pg_rewrite.h"
                                 49                 :                : #include "catalog/pg_statistic_ext.h"
                                 50                 :                : #include "catalog/pg_tablespace.h"
                                 51                 :                : #include "catalog/pg_trigger.h"
                                 52                 :                : #include "catalog/pg_type.h"
                                 53                 :                : #include "catalog/storage.h"
                                 54                 :                : #include "catalog/storage_xlog.h"
                                 55                 :                : #include "catalog/toasting.h"
                                 56                 :                : #include "commands/cluster.h"
                                 57                 :                : #include "commands/comment.h"
                                 58                 :                : #include "commands/defrem.h"
                                 59                 :                : #include "commands/event_trigger.h"
                                 60                 :                : #include "commands/sequence.h"
                                 61                 :                : #include "commands/tablecmds.h"
                                 62                 :                : #include "commands/tablespace.h"
                                 63                 :                : #include "commands/trigger.h"
                                 64                 :                : #include "commands/typecmds.h"
                                 65                 :                : #include "commands/user.h"
                                 66                 :                : #include "commands/vacuum.h"
                                 67                 :                : #include "executor/executor.h"
                                 68                 :                : #include "foreign/fdwapi.h"
                                 69                 :                : #include "foreign/foreign.h"
                                 70                 :                : #include "miscadmin.h"
                                 71                 :                : #include "nodes/makefuncs.h"
                                 72                 :                : #include "nodes/nodeFuncs.h"
                                 73                 :                : #include "nodes/parsenodes.h"
                                 74                 :                : #include "optimizer/optimizer.h"
                                 75                 :                : #include "parser/parse_coerce.h"
                                 76                 :                : #include "parser/parse_collate.h"
                                 77                 :                : #include "parser/parse_expr.h"
                                 78                 :                : #include "parser/parse_relation.h"
                                 79                 :                : #include "parser/parse_type.h"
                                 80                 :                : #include "parser/parse_utilcmd.h"
                                 81                 :                : #include "parser/parser.h"
                                 82                 :                : #include "partitioning/partbounds.h"
                                 83                 :                : #include "partitioning/partdesc.h"
                                 84                 :                : #include "pgstat.h"
                                 85                 :                : #include "rewrite/rewriteDefine.h"
                                 86                 :                : #include "rewrite/rewriteHandler.h"
                                 87                 :                : #include "rewrite/rewriteManip.h"
                                 88                 :                : #include "storage/bufmgr.h"
                                 89                 :                : #include "storage/lmgr.h"
                                 90                 :                : #include "storage/lock.h"
                                 91                 :                : #include "storage/predicate.h"
                                 92                 :                : #include "storage/smgr.h"
                                 93                 :                : #include "tcop/utility.h"
                                 94                 :                : #include "utils/acl.h"
                                 95                 :                : #include "utils/builtins.h"
                                 96                 :                : #include "utils/fmgroids.h"
                                 97                 :                : #include "utils/inval.h"
                                 98                 :                : #include "utils/lsyscache.h"
                                 99                 :                : #include "utils/memutils.h"
                                100                 :                : #include "utils/partcache.h"
                                101                 :                : #include "utils/relcache.h"
                                102                 :                : #include "utils/ruleutils.h"
                                103                 :                : #include "utils/snapmgr.h"
                                104                 :                : #include "utils/syscache.h"
                                105                 :                : #include "utils/timestamp.h"
                                106                 :                : #include "utils/typcache.h"
                                107                 :                : #include "utils/usercontext.h"
                                108                 :                : 
                                109                 :                : /*
                                110                 :                :  * ON COMMIT action list
                                111                 :                :  */
                                112                 :                : typedef struct OnCommitItem
                                113                 :                : {
                                114                 :                :     Oid         relid;          /* relid of relation */
                                115                 :                :     OnCommitAction oncommit;    /* what to do at end of xact */
                                116                 :                : 
                                117                 :                :     /*
                                118                 :                :      * If this entry was created during the current transaction,
                                119                 :                :      * creating_subid is the ID of the creating subxact; if created in a prior
                                120                 :                :      * transaction, creating_subid is zero.  If deleted during the current
                                121                 :                :      * transaction, deleting_subid is the ID of the deleting subxact; if no
                                122                 :                :      * deletion request is pending, deleting_subid is zero.
                                123                 :                :      */
                                124                 :                :     SubTransactionId creating_subid;
                                125                 :                :     SubTransactionId deleting_subid;
                                126                 :                : } OnCommitItem;
                                127                 :                : 
                                128                 :                : static List *on_commits = NIL;
                                129                 :                : 
                                130                 :                : 
                                131                 :                : /*
                                132                 :                :  * State information for ALTER TABLE
                                133                 :                :  *
                                134                 :                :  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
                                135                 :                :  * structs, one for each table modified by the operation (the named table
                                136                 :                :  * plus any child tables that are affected).  We save lists of subcommands
                                137                 :                :  * to apply to this table (possibly modified by parse transformation steps);
                                138                 :                :  * these lists will be executed in Phase 2.  If a Phase 3 step is needed,
                                139                 :                :  * necessary information is stored in the constraints and newvals lists.
                                140                 :                :  *
                                141                 :                :  * Phase 2 is divided into multiple passes; subcommands are executed in
                                142                 :                :  * a pass determined by subcommand type.
                                143                 :                :  */
                                144                 :                : 
                                145                 :                : typedef enum AlterTablePass
                                146                 :                : {
                                147                 :                :     AT_PASS_UNSET = -1,         /* UNSET will cause ERROR */
                                148                 :                :     AT_PASS_DROP,               /* DROP (all flavors) */
                                149                 :                :     AT_PASS_ALTER_TYPE,         /* ALTER COLUMN TYPE */
                                150                 :                :     AT_PASS_ADD_COL,            /* ADD COLUMN */
                                151                 :                :     AT_PASS_SET_EXPRESSION,     /* ALTER SET EXPRESSION */
                                152                 :                :     AT_PASS_OLD_INDEX,          /* re-add existing indexes */
                                153                 :                :     AT_PASS_OLD_CONSTR,         /* re-add existing constraints */
                                154                 :                :     /* We could support a RENAME COLUMN pass here, but not currently used */
                                155                 :                :     AT_PASS_ADD_CONSTR,         /* ADD constraints (initial examination) */
                                156                 :                :     AT_PASS_COL_ATTRS,          /* set column attributes, eg NOT NULL */
                                157                 :                :     AT_PASS_ADD_INDEXCONSTR,    /* ADD index-based constraints */
                                158                 :                :     AT_PASS_ADD_INDEX,          /* ADD indexes */
                                159                 :                :     AT_PASS_ADD_OTHERCONSTR,    /* ADD other constraints, defaults */
                                160                 :                :     AT_PASS_MISC,               /* other stuff */
                                161                 :                : } AlterTablePass;
                                162                 :                : 
                                163                 :                : #define AT_NUM_PASSES           (AT_PASS_MISC + 1)
                                164                 :                : 
                                165                 :                : typedef struct AlteredTableInfo
                                166                 :                : {
                                167                 :                :     /* Information saved before any work commences: */
                                168                 :                :     Oid         relid;          /* Relation to work on */
                                169                 :                :     char        relkind;        /* Its relkind */
                                170                 :                :     TupleDesc   oldDesc;        /* Pre-modification tuple descriptor */
                                171                 :                : 
                                172                 :                :     /*
                                173                 :                :      * Transiently set during Phase 2, normally set to NULL.
                                174                 :                :      *
                                175                 :                :      * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd
                                176                 :                :      * returns control.  This can be exploited by ATExecCmd subroutines to
                                177                 :                :      * close/reopen across transaction boundaries.
                                178                 :                :      */
                                179                 :                :     Relation    rel;
                                180                 :                : 
                                181                 :                :     /* Information saved by Phase 1 for Phase 2: */
                                182                 :                :     List       *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
                                183                 :                :     /* Information saved by Phases 1/2 for Phase 3: */
                                184                 :                :     List       *constraints;    /* List of NewConstraint */
                                185                 :                :     List       *newvals;        /* List of NewColumnValue */
                                186                 :                :     List       *afterStmts;     /* List of utility command parsetrees */
                                187                 :                :     bool        verify_new_notnull; /* T if we should recheck NOT NULL */
                                188                 :                :     int         rewrite;        /* Reason for forced rewrite, if any */
                                189                 :                :     bool        chgAccessMethod;    /* T if SET ACCESS METHOD is used */
                                190                 :                :     Oid         newAccessMethod;    /* new access method; 0 means no change,
                                191                 :                :                                      * if above is true */
                                192                 :                :     Oid         newTableSpace;  /* new tablespace; 0 means no change */
                                193                 :                :     bool        chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
                                194                 :                :     char        newrelpersistence;  /* if above is true */
                                195                 :                :     Expr       *partition_constraint;   /* for attach partition validation */
                                196                 :                :     /* true, if validating default due to some other attach/detach */
                                197                 :                :     bool        validate_default;
                                198                 :                :     /* Objects to rebuild after completing ALTER TYPE operations */
                                199                 :                :     List       *changedConstraintOids;  /* OIDs of constraints to rebuild */
                                200                 :                :     List       *changedConstraintDefs;  /* string definitions of same */
                                201                 :                :     List       *changedIndexOids;   /* OIDs of indexes to rebuild */
                                202                 :                :     List       *changedIndexDefs;   /* string definitions of same */
                                203                 :                :     char       *replicaIdentityIndex;   /* index to reset as REPLICA IDENTITY */
                                204                 :                :     char       *clusterOnIndex; /* index to use for CLUSTER */
                                205                 :                :     List       *changedStatisticsOids;  /* OIDs of statistics to rebuild */
                                206                 :                :     List       *changedStatisticsDefs;  /* string definitions of same */
                                207                 :                : } AlteredTableInfo;
                                208                 :                : 
                                209                 :                : /* Struct describing one new constraint to check in Phase 3 scan */
                                210                 :                : /* Note: new not-null constraints are handled elsewhere */
                                211                 :                : typedef struct NewConstraint
                                212                 :                : {
                                213                 :                :     char       *name;           /* Constraint name, or NULL if none */
                                214                 :                :     ConstrType  contype;        /* CHECK or FOREIGN */
                                215                 :                :     Oid         refrelid;       /* PK rel, if FOREIGN */
                                216                 :                :     Oid         refindid;       /* OID of PK's index, if FOREIGN */
                                217                 :                :     bool        conwithperiod;  /* Whether the new FOREIGN KEY uses PERIOD */
                                218                 :                :     Oid         conid;          /* OID of pg_constraint entry, if FOREIGN */
                                219                 :                :     Node       *qual;           /* Check expr or CONSTR_FOREIGN Constraint */
                                220                 :                :     ExprState  *qualstate;      /* Execution state for CHECK expr */
                                221                 :                : } NewConstraint;
                                222                 :                : 
                                223                 :                : /*
                                224                 :                :  * Struct describing one new column value that needs to be computed during
                                225                 :                :  * Phase 3 copy (this could be either a new column with a non-null default, or
                                226                 :                :  * a column that we're changing the type of).  Columns without such an entry
                                227                 :                :  * are just copied from the old table during ATRewriteTable.  Note that the
                                228                 :                :  * expr is an expression over *old* table values, except when is_generated
                                229                 :                :  * is true; then it is an expression over columns of the *new* tuple.
                                230                 :                :  */
                                231                 :                : typedef struct NewColumnValue
                                232                 :                : {
                                233                 :                :     AttrNumber  attnum;         /* which column */
                                234                 :                :     Expr       *expr;           /* expression to compute */
                                235                 :                :     ExprState  *exprstate;      /* execution state */
                                236                 :                :     bool        is_generated;   /* is it a GENERATED expression? */
                                237                 :                : } NewColumnValue;
                                238                 :                : 
                                239                 :                : /*
                                240                 :                :  * Error-reporting support for RemoveRelations
                                241                 :                :  */
                                242                 :                : struct dropmsgstrings
                                243                 :                : {
                                244                 :                :     char        kind;
                                245                 :                :     int         nonexistent_code;
                                246                 :                :     const char *nonexistent_msg;
                                247                 :                :     const char *skipping_msg;
                                248                 :                :     const char *nota_msg;
                                249                 :                :     const char *drophint_msg;
                                250                 :                : };
                                251                 :                : 
                                252                 :                : static const struct dropmsgstrings dropmsgstringarray[] = {
                                253                 :                :     {RELKIND_RELATION,
                                254                 :                :         ERRCODE_UNDEFINED_TABLE,
                                255                 :                :         gettext_noop("table \"%s\" does not exist"),
                                256                 :                :         gettext_noop("table \"%s\" does not exist, skipping"),
                                257                 :                :         gettext_noop("\"%s\" is not a table"),
                                258                 :                :     gettext_noop("Use DROP TABLE to remove a table.")},
                                259                 :                :     {RELKIND_SEQUENCE,
                                260                 :                :         ERRCODE_UNDEFINED_TABLE,
                                261                 :                :         gettext_noop("sequence \"%s\" does not exist"),
                                262                 :                :         gettext_noop("sequence \"%s\" does not exist, skipping"),
                                263                 :                :         gettext_noop("\"%s\" is not a sequence"),
                                264                 :                :     gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
                                265                 :                :     {RELKIND_VIEW,
                                266                 :                :         ERRCODE_UNDEFINED_TABLE,
                                267                 :                :         gettext_noop("view \"%s\" does not exist"),
                                268                 :                :         gettext_noop("view \"%s\" does not exist, skipping"),
                                269                 :                :         gettext_noop("\"%s\" is not a view"),
                                270                 :                :     gettext_noop("Use DROP VIEW to remove a view.")},
                                271                 :                :     {RELKIND_MATVIEW,
                                272                 :                :         ERRCODE_UNDEFINED_TABLE,
                                273                 :                :         gettext_noop("materialized view \"%s\" does not exist"),
                                274                 :                :         gettext_noop("materialized view \"%s\" does not exist, skipping"),
                                275                 :                :         gettext_noop("\"%s\" is not a materialized view"),
                                276                 :                :     gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
                                277                 :                :     {RELKIND_INDEX,
                                278                 :                :         ERRCODE_UNDEFINED_OBJECT,
                                279                 :                :         gettext_noop("index \"%s\" does not exist"),
                                280                 :                :         gettext_noop("index \"%s\" does not exist, skipping"),
                                281                 :                :         gettext_noop("\"%s\" is not an index"),
                                282                 :                :     gettext_noop("Use DROP INDEX to remove an index.")},
                                283                 :                :     {RELKIND_COMPOSITE_TYPE,
                                284                 :                :         ERRCODE_UNDEFINED_OBJECT,
                                285                 :                :         gettext_noop("type \"%s\" does not exist"),
                                286                 :                :         gettext_noop("type \"%s\" does not exist, skipping"),
                                287                 :                :         gettext_noop("\"%s\" is not a type"),
                                288                 :                :     gettext_noop("Use DROP TYPE to remove a type.")},
                                289                 :                :     {RELKIND_FOREIGN_TABLE,
                                290                 :                :         ERRCODE_UNDEFINED_OBJECT,
                                291                 :                :         gettext_noop("foreign table \"%s\" does not exist"),
                                292                 :                :         gettext_noop("foreign table \"%s\" does not exist, skipping"),
                                293                 :                :         gettext_noop("\"%s\" is not a foreign table"),
                                294                 :                :     gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
                                295                 :                :     {RELKIND_PARTITIONED_TABLE,
                                296                 :                :         ERRCODE_UNDEFINED_TABLE,
                                297                 :                :         gettext_noop("table \"%s\" does not exist"),
                                298                 :                :         gettext_noop("table \"%s\" does not exist, skipping"),
                                299                 :                :         gettext_noop("\"%s\" is not a table"),
                                300                 :                :     gettext_noop("Use DROP TABLE to remove a table.")},
                                301                 :                :     {RELKIND_PARTITIONED_INDEX,
                                302                 :                :         ERRCODE_UNDEFINED_OBJECT,
                                303                 :                :         gettext_noop("index \"%s\" does not exist"),
                                304                 :                :         gettext_noop("index \"%s\" does not exist, skipping"),
                                305                 :                :         gettext_noop("\"%s\" is not an index"),
                                306                 :                :     gettext_noop("Use DROP INDEX to remove an index.")},
                                307                 :                :     {'\0', 0, NULL, NULL, NULL, NULL}
                                308                 :                : };
                                309                 :                : 
                                310                 :                : /* communication between RemoveRelations and RangeVarCallbackForDropRelation */
                                311                 :                : struct DropRelationCallbackState
                                312                 :                : {
                                313                 :                :     /* These fields are set by RemoveRelations: */
                                314                 :                :     char        expected_relkind;
                                315                 :                :     LOCKMODE    heap_lockmode;
                                316                 :                :     /* These fields are state to track which subsidiary locks are held: */
                                317                 :                :     Oid         heapOid;
                                318                 :                :     Oid         partParentOid;
                                319                 :                :     /* These fields are passed back by RangeVarCallbackForDropRelation: */
                                320                 :                :     char        actual_relkind;
                                321                 :                :     char        actual_relpersistence;
                                322                 :                : };
                                323                 :                : 
                                324                 :                : /* Alter table target-type flags for ATSimplePermissions */
                                325                 :                : #define     ATT_TABLE               0x0001
                                326                 :                : #define     ATT_VIEW                0x0002
                                327                 :                : #define     ATT_MATVIEW             0x0004
                                328                 :                : #define     ATT_INDEX               0x0008
                                329                 :                : #define     ATT_COMPOSITE_TYPE      0x0010
                                330                 :                : #define     ATT_FOREIGN_TABLE       0x0020
                                331                 :                : #define     ATT_PARTITIONED_INDEX   0x0040
                                332                 :                : #define     ATT_SEQUENCE            0x0080
                                333                 :                : 
                                334                 :                : /*
                                335                 :                :  * ForeignTruncateInfo
                                336                 :                :  *
                                337                 :                :  * Information related to truncation of foreign tables.  This is used for
                                338                 :                :  * the elements in a hash table. It uses the server OID as lookup key,
                                339                 :                :  * and includes a per-server list of all foreign tables involved in the
                                340                 :                :  * truncation.
                                341                 :                :  */
                                342                 :                : typedef struct ForeignTruncateInfo
                                343                 :                : {
                                344                 :                :     Oid         serverid;
                                345                 :                :     List       *rels;
                                346                 :                : } ForeignTruncateInfo;
                                347                 :                : 
                                348                 :                : /*
                                349                 :                :  * Partition tables are expected to be dropped when the parent partitioned
                                350                 :                :  * table gets dropped. Hence for partitioning we use AUTO dependency.
                                351                 :                :  * Otherwise, for regular inheritance use NORMAL dependency.
                                352                 :                :  */
                                353                 :                : #define child_dependency_type(child_is_partition)   \
                                354                 :                :     ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
                                355                 :                : 
                                356                 :                : static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
                                357                 :                : static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
                                358                 :                : static void truncate_check_activity(Relation rel);
                                359                 :                : static void RangeVarCallbackForTruncate(const RangeVar *relation,
                                360                 :                :                                         Oid relId, Oid oldRelId, void *arg);
                                361                 :                : static List *MergeAttributes(List *columns, const List *supers, char relpersistence,
                                362                 :                :                              bool is_partition, List **supconstr,
                                363                 :                :                              List **supnotnulls);
                                364                 :                : static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr);
                                365                 :                : static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef);
                                366                 :                : static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef);
                                367                 :                : static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition);
                                368                 :                : static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
                                369                 :                : static void StoreCatalogInheritance(Oid relationId, List *supers,
                                370                 :                :                                     bool child_is_partition);
                                371                 :                : static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
                                372                 :                :                                      int32 seqNumber, Relation inhRelation,
                                373                 :                :                                      bool child_is_partition);
                                374                 :                : static int  findAttrByName(const char *attributeName, const List *columns);
                                375                 :                : static void AlterIndexNamespaces(Relation classRel, Relation rel,
                                376                 :                :                                  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
                                377                 :                : static void AlterSeqNamespaces(Relation classRel, Relation rel,
                                378                 :                :                                Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
                                379                 :                :                                LOCKMODE lockmode);
                                380                 :                : static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
                                381                 :                :                                            bool recurse, bool recursing, LOCKMODE lockmode);
                                382                 :                : static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
                                383                 :                :                                      Relation rel, HeapTuple contuple, List **otherrelids,
                                384                 :                :                                      LOCKMODE lockmode);
                                385                 :                : static ObjectAddress ATExecValidateConstraint(List **wqueue,
                                386                 :                :                                               Relation rel, char *constrName,
                                387                 :                :                                               bool recurse, bool recursing, LOCKMODE lockmode);
                                388                 :                : static int  transformColumnNameList(Oid relId, List *colList,
                                389                 :                :                                     int16 *attnums, Oid *atttypids);
                                390                 :                : static int  transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
                                391                 :                :                                        List **attnamelist,
                                392                 :                :                                        int16 *attnums, Oid *atttypids,
                                393                 :                :                                        Oid *opclasses, bool *pk_has_without_overlaps);
                                394                 :                : static Oid  transformFkeyCheckAttrs(Relation pkrel,
                                395                 :                :                                     int numattrs, int16 *attnums,
                                396                 :                :                                     bool with_period, Oid *opclasses,
                                397                 :                :                                     bool *pk_has_without_overlaps);
                                398                 :                : static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
                                399                 :                : static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
                                400                 :                :                                      Oid *funcid);
                                401                 :                : static void validateForeignKeyConstraint(char *conname,
                                402                 :                :                                          Relation rel, Relation pkrel,
                                403                 :                :                                          Oid pkindOid, Oid constraintOid, bool hasperiod);
                                404                 :                : static void ATController(AlterTableStmt *parsetree,
                                405                 :                :                          Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
                                406                 :                :                          AlterTableUtilityContext *context);
                                407                 :                : static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
                                408                 :                :                       bool recurse, bool recursing, LOCKMODE lockmode,
                                409                 :                :                       AlterTableUtilityContext *context);
                                410                 :                : static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
                                411                 :                :                               AlterTableUtilityContext *context);
                                412                 :                : static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
                                413                 :                :                       AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
                                414                 :                :                       AlterTableUtilityContext *context);
                                415                 :                : static AlterTableCmd *ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab,
                                416                 :                :                                           Relation rel, AlterTableCmd *cmd,
                                417                 :                :                                           bool recurse, LOCKMODE lockmode,
                                418                 :                :                                           AlterTablePass cur_pass,
                                419                 :                :                                           AlterTableUtilityContext *context);
                                420                 :                : static void ATRewriteTables(AlterTableStmt *parsetree,
                                421                 :                :                             List **wqueue, LOCKMODE lockmode,
                                422                 :                :                             AlterTableUtilityContext *context);
                                423                 :                : static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
                                424                 :                : static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
                                425                 :                : static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
                                426                 :                : static void ATSimpleRecursion(List **wqueue, Relation rel,
                                427                 :                :                               AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
                                428                 :                :                               AlterTableUtilityContext *context);
                                429                 :                : static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
                                430                 :                : static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
                                431                 :                :                                   LOCKMODE lockmode,
                                432                 :                :                                   AlterTableUtilityContext *context);
                                433                 :                : static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
                                434                 :                :                                            DropBehavior behavior);
                                435                 :                : static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                                436                 :                :                             bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
                                437                 :                :                             AlterTableUtilityContext *context);
                                438                 :                : static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
                                439                 :                :                                      Relation rel, AlterTableCmd **cmd,
                                440                 :                :                                      bool recurse, bool recursing,
                                441                 :                :                                      LOCKMODE lockmode, AlterTablePass cur_pass,
                                442                 :                :                                      AlterTableUtilityContext *context);
                                443                 :                : static bool check_for_column_name_collision(Relation rel, const char *colname,
                                444                 :                :                                             bool if_not_exists);
                                445                 :                : static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
                                446                 :                : static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
                                447                 :                : static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
                                448                 :                :                                        LOCKMODE lockmode);
                                449                 :                : static bool set_attnotnull(List **wqueue, Relation rel,
                                450                 :                :                            AttrNumber attnum, bool recurse, LOCKMODE lockmode);
                                451                 :                : static ObjectAddress ATExecSetNotNull(List **wqueue, Relation rel,
                                452                 :                :                                       char *constrname, char *colName,
                                453                 :                :                                       bool recurse, bool recursing,
                                454                 :                :                                       List **readyRels, LOCKMODE lockmode);
                                455                 :                : static ObjectAddress ATExecSetAttNotNull(List **wqueue, Relation rel,
                                456                 :                :                                          const char *colName, LOCKMODE lockmode);
                                457                 :                : static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr);
                                458                 :                : static bool ConstraintImpliedByRelConstraint(Relation scanrel,
                                459                 :                :                                              List *testConstraint, List *provenConstraint);
                                460                 :                : static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
                                461                 :                :                                          Node *newDefault, LOCKMODE lockmode);
                                462                 :                : static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
                                463                 :                :                                                Node *newDefault);
                                464                 :                : static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
                                465                 :                :                                        Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
                                466                 :                : static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
                                467                 :                :                                        Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
                                468                 :                : static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
                                469                 :                :                                         bool recurse, bool recursing);
                                470                 :                : static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
                                471                 :                :                                          Node *newExpr, LOCKMODE lockmode);
                                472                 :                : static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
                                473                 :                : static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
                                474                 :                : static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
                                475                 :                :                                          Node *newValue, LOCKMODE lockmode);
                                476                 :                : static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
                                477                 :                :                                       Node *options, bool isReset, LOCKMODE lockmode);
                                478                 :                : static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
                                479                 :                :                                       Node *newValue, LOCKMODE lockmode);
                                480                 :                : static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                                481                 :                :                              AlterTableCmd *cmd, LOCKMODE lockmode,
                                482                 :                :                              AlterTableUtilityContext *context);
                                483                 :                : static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
                                484                 :                :                                       DropBehavior behavior,
                                485                 :                :                                       bool recurse, bool recursing,
                                486                 :                :                                       bool missing_ok, LOCKMODE lockmode,
                                487                 :                :                                       ObjectAddresses *addrs);
                                488                 :                : static void ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd,
                                489                 :                :                                 LOCKMODE lockmode, AlterTableUtilityContext *context);
                                490                 :                : static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
                                491                 :                :                                     IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
                                492                 :                : static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
                                493                 :                :                                          CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
                                494                 :                : static ObjectAddress ATExecAddConstraint(List **wqueue,
                                495                 :                :                                          AlteredTableInfo *tab, Relation rel,
                                496                 :                :                                          Constraint *newConstraint, bool recurse, bool is_readd,
                                497                 :                :                                          LOCKMODE lockmode);
                                498                 :                : static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
                                499                 :                : static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
                                500                 :                :                                               IndexStmt *stmt, LOCKMODE lockmode);
                                501                 :                : static ObjectAddress ATAddCheckNNConstraint(List **wqueue,
                                502                 :                :                                             AlteredTableInfo *tab, Relation rel,
                                503                 :                :                                             Constraint *constr,
                                504                 :                :                                             bool recurse, bool recursing, bool is_readd,
                                505                 :                :                                             LOCKMODE lockmode);
                                506                 :                : static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab,
                                507                 :                :                                                Relation rel, Constraint *fkconstraint,
                                508                 :                :                                                bool recurse, bool recursing,
                                509                 :                :                                                LOCKMODE lockmode);
                                510                 :                : static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
                                511                 :                :                                             Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
                                512                 :                :                                             int numfks, int16 *pkattnum, int16 *fkattnum,
                                513                 :                :                                             Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
                                514                 :                :                                             int numfkdelsetcols, int16 *fkdelsetcols,
                                515                 :                :                                             bool old_check_ok,
                                516                 :                :                                             Oid parentDelTrigger, Oid parentUpdTrigger,
                                517                 :                :                                             bool with_period);
                                518                 :                : static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
                                519                 :                :                                          int numfksetcols, const int16 *fksetcolsattnums,
                                520                 :                :                                          List *fksetcols);
                                521                 :                : static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
                                522                 :                :                                     Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
                                523                 :                :                                     int numfks, int16 *pkattnum, int16 *fkattnum,
                                524                 :                :                                     Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
                                525                 :                :                                     int numfkdelsetcols, int16 *fkdelsetcols,
                                526                 :                :                                     bool old_check_ok, LOCKMODE lockmode,
                                527                 :                :                                     Oid parentInsTrigger, Oid parentUpdTrigger,
                                528                 :                :                                     bool with_period);
                                529                 :                : 
                                530                 :                : static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
                                531                 :                :                                        Relation partitionRel);
                                532                 :                : static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
                                533                 :                : static void CloneFkReferencing(List **wqueue, Relation parentRel,
                                534                 :                :                                Relation partRel);
                                535                 :                : static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
                                536                 :                :                                           Constraint *fkconstraint, Oid constraintOid,
                                537                 :                :                                           Oid indexOid,
                                538                 :                :                                           Oid parentInsTrigger, Oid parentUpdTrigger,
                                539                 :                :                                           Oid *insertTrigOid, Oid *updateTrigOid);
                                540                 :                : static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
                                541                 :                :                                            Constraint *fkconstraint, Oid constraintOid,
                                542                 :                :                                            Oid indexOid,
                                543                 :                :                                            Oid parentDelTrigger, Oid parentUpdTrigger,
                                544                 :                :                                            Oid *deleteTrigOid, Oid *updateTrigOid);
                                545                 :                : static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
                                546                 :                :                                          Oid partRelid,
                                547                 :                :                                          Oid parentConstrOid, int numfks,
                                548                 :                :                                          AttrNumber *mapped_conkey, AttrNumber *confkey,
                                549                 :                :                                          Oid *conpfeqop,
                                550                 :                :                                          Oid parentInsTrigger,
                                551                 :                :                                          Oid parentUpdTrigger,
                                552                 :                :                                          Relation trigrel);
                                553                 :                : static void GetForeignKeyActionTriggers(Relation trigrel,
                                554                 :                :                                         Oid conoid, Oid confrelid, Oid conrelid,
                                555                 :                :                                         Oid *deleteTriggerOid,
                                556                 :                :                                         Oid *updateTriggerOid);
                                557                 :                : static void GetForeignKeyCheckTriggers(Relation trigrel,
                                558                 :                :                                        Oid conoid, Oid confrelid, Oid conrelid,
                                559                 :                :                                        Oid *insertTriggerOid,
                                560                 :                :                                        Oid *updateTriggerOid);
                                561                 :                : static void ATExecDropConstraint(Relation rel, const char *constrName,
                                562                 :                :                                  DropBehavior behavior, bool recurse,
                                563                 :                :                                  bool missing_ok, LOCKMODE lockmode);
                                564                 :                : static ObjectAddress dropconstraint_internal(Relation rel,
                                565                 :                :                                              HeapTuple constraintTup, DropBehavior behavior,
                                566                 :                :                                              bool recurse, bool recursing,
                                567                 :                :                                              bool missing_ok, List **readyRels,
                                568                 :                :                                              LOCKMODE lockmode);
                                569                 :                : static void ATPrepAlterColumnType(List **wqueue,
                                570                 :                :                                   AlteredTableInfo *tab, Relation rel,
                                571                 :                :                                   bool recurse, bool recursing,
                                572                 :                :                                   AlterTableCmd *cmd, LOCKMODE lockmode,
                                573                 :                :                                   AlterTableUtilityContext *context);
                                574                 :                : static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
                                575                 :                : static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                                576                 :                :                                            AlterTableCmd *cmd, LOCKMODE lockmode);
                                577                 :                : static void RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype,
                                578                 :                :                                               Relation rel, AttrNumber attnum, const char *colName);
                                579                 :                : static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
                                580                 :                : static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
                                581                 :                : static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
                                582                 :                : static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
                                583                 :                :                                    LOCKMODE lockmode);
                                584                 :                : static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
                                585                 :                :                                  char *cmd, List **wqueue, LOCKMODE lockmode,
                                586                 :                :                                  bool rewrite);
                                587                 :                : static void RebuildConstraintComment(AlteredTableInfo *tab, AlterTablePass pass,
                                588                 :                :                                      Oid objid, Relation rel, List *domname,
                                589                 :                :                                      const char *conname);
                                590                 :                : static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
                                591                 :                : static void TryReuseForeignKey(Oid oldId, Constraint *con);
                                592                 :                : static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
                                593                 :                :                                                      List *options, LOCKMODE lockmode);
                                594                 :                : static void change_owner_fix_column_acls(Oid relationOid,
                                595                 :                :                                          Oid oldOwnerId, Oid newOwnerId);
                                596                 :                : static void change_owner_recurse_to_sequences(Oid relationOid,
                                597                 :                :                                               Oid newOwnerId, LOCKMODE lockmode);
                                598                 :                : static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
                                599                 :                :                                      LOCKMODE lockmode);
                                600                 :                : static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
                                601                 :                : static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname);
                                602                 :                : static void ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethod);
                                603                 :                : static bool ATPrepChangePersistence(Relation rel, bool toLogged);
                                604                 :                : static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
                                605                 :                :                                 const char *tablespacename, LOCKMODE lockmode);
                                606                 :                : static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
                                607                 :                : static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
                                608                 :                : static void ATExecSetRelOptions(Relation rel, List *defList,
                                609                 :                :                                 AlterTableType operation,
                                610                 :                :                                 LOCKMODE lockmode);
                                611                 :                : static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
                                612                 :                :                                        char fires_when, bool skip_system, bool recurse,
                                613                 :                :                                        LOCKMODE lockmode);
                                614                 :                : static void ATExecEnableDisableRule(Relation rel, const char *rulename,
                                615                 :                :                                     char fires_when, LOCKMODE lockmode);
                                616                 :                : static void ATPrepAddInherit(Relation child_rel);
                                617                 :                : static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
                                618                 :                : static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
                                619                 :                : static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
                                620                 :                :                                    DependencyType deptype);
                                621                 :                : static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
                                622                 :                : static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
                                623                 :                : static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
                                624                 :                : static void ATExecGenericOptions(Relation rel, List *options);
                                625                 :                : static void ATExecSetRowSecurity(Relation rel, bool rls);
                                626                 :                : static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
                                627                 :                : static ObjectAddress ATExecSetCompression(Relation rel,
                                628                 :                :                                           const char *column, Node *newValue, LOCKMODE lockmode);
                                629                 :                : 
                                630                 :                : static void index_copy_data(Relation rel, RelFileLocator newrlocator);
                                631                 :                : static const char *storage_name(char c);
                                632                 :                : 
                                633                 :                : static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
                                634                 :                :                                             Oid oldRelOid, void *arg);
                                635                 :                : static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
                                636                 :                :                                              Oid oldrelid, void *arg);
                                637                 :                : static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec);
                                638                 :                : static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
                                639                 :                :                                   List **partexprs, Oid *partopclass, Oid *partcollation,
                                640                 :                :                                   PartitionStrategy strategy);
                                641                 :                : static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition);
                                642                 :                : static void RemoveInheritance(Relation child_rel, Relation parent_rel,
                                643                 :                :                               bool expect_detached);
                                644                 :                : static void ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel,
                                645                 :                :                                     int inhcount);
                                646                 :                : static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
                                647                 :                :                                            PartitionCmd *cmd,
                                648                 :                :                                            AlterTableUtilityContext *context);
                                649                 :                : static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel);
                                650                 :                : static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
                                651                 :                :                                                List *partConstraint,
                                652                 :                :                                                bool validate_default);
                                653                 :                : static void CloneRowTriggersToPartition(Relation parent, Relation partition);
                                654                 :                : static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
                                655                 :                : static void DropClonedTriggersFromPartition(Oid partitionId);
                                656                 :                : static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab,
                                657                 :                :                                            Relation rel, RangeVar *name,
                                658                 :                :                                            bool concurrent);
                                659                 :                : static void DetachPartitionFinalize(Relation rel, Relation partRel,
                                660                 :                :                                     bool concurrent, Oid defaultPartOid);
                                661                 :                : static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name);
                                662                 :                : static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx,
                                663                 :                :                                               RangeVar *name);
                                664                 :                : static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
                                665                 :                : static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
                                666                 :                :                                   Relation partitionTbl);
                                667                 :                : static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partIdx);
                                668                 :                : static List *GetParentedForeignKeyRefs(Relation partition);
                                669                 :                : static void ATDetachCheckNoForeignKeyRefs(Relation partition);
                                670                 :                : static char GetAttributeCompression(Oid atttypid, const char *compression);
                                671                 :                : static char GetAttributeStorage(Oid atttypid, const char *storagemode);
                                672                 :                : 
                                673                 :                : static void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab,
                                674                 :                :                                  Relation rel, PartitionCmd *cmd,
                                675                 :                :                                  AlterTableUtilityContext *context);
                                676                 :                : static void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
                                677                 :                :                                   PartitionCmd *cmd, AlterTableUtilityContext *context);
                                678                 :                : 
                                679                 :                : /* ----------------------------------------------------------------
                                680                 :                :  *      DefineRelation
                                681                 :                :  *              Creates a new relation.
                                682                 :                :  *
                                683                 :                :  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
                                684                 :                :  * The other arguments are used to extend the behavior for other cases:
                                685                 :                :  * relkind: relkind to assign to the new relation
                                686                 :                :  * ownerId: if not InvalidOid, use this as the new relation's owner.
                                687                 :                :  * typaddress: if not null, it's set to the pg_type entry's address.
                                688                 :                :  * queryString: for error reporting
                                689                 :                :  *
                                690                 :                :  * Note that permissions checks are done against current user regardless of
                                691                 :                :  * ownerId.  A nonzero ownerId is used when someone is creating a relation
                                692                 :                :  * "on behalf of" someone else, so we still want to see that the current user
                                693                 :                :  * has permissions to do it.
                                694                 :                :  *
                                695                 :                :  * If successful, returns the address of the new relation.
                                696                 :                :  * ----------------------------------------------------------------
                                697                 :                :  */
                                698                 :                : ObjectAddress
 3330 alvherre@alvh.no-ip.      699                 :CBC       26364 : DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
                                700                 :                :                ObjectAddress *typaddress, const char *queryString)
                                701                 :                : {
                                702                 :                :     char        relname[NAMEDATALEN];
                                703                 :                :     Oid         namespaceId;
                                704                 :                :     Oid         relationId;
                                705                 :                :     Oid         tablespaceId;
                                706                 :                :     Relation    rel;
                                707                 :                :     TupleDesc   descriptor;
                                708                 :                :     List       *inheritOids;
                                709                 :                :     List       *old_constraints;
                                710                 :                :     List       *old_notnulls;
                                711                 :                :     List       *rawDefaults;
                                712                 :                :     List       *cookedDefaults;
                                713                 :                :     List       *nncols;
                                714                 :                :     Datum       reloptions;
                                715                 :                :     ListCell   *listptr;
                                716                 :                :     AttrNumber  attnum;
                                717                 :                :     bool        partitioned;
                                718                 :                :     static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
                                719                 :                :     Oid         ofTypeId;
                                720                 :                :     ObjectAddress address;
                                721                 :                :     LOCKMODE    parentLockmode;
 1866 andres@anarazel.de        722                 :          26364 :     Oid         accessMethodId = InvalidOid;
                                723                 :                : 
                                724                 :                :     /*
                                725                 :                :      * Truncate relname to appropriate length (probably a waste of time, as
                                726                 :                :      * parser should have done this already).
                                727                 :                :      */
 1343 peter@eisentraut.org      728                 :          26364 :     strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
                                729                 :                : 
                                730                 :                :     /*
                                731                 :                :      * Check consistency of arguments
                                732                 :                :      */
 4753 bruce@momjian.us          733         [ +  + ]:          26364 :     if (stmt->oncommit != ONCOMMIT_NOOP
 4871 rhaas@postgresql.org      734         [ +  + ]:             89 :         && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
 7574 tgl@sss.pgh.pa.us         735         [ +  - ]:              6 :         ereport(ERROR,
                                736                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                                737                 :                :                  errmsg("ON COMMIT can only be used on temporary tables")));
                                738                 :                : 
 2685 rhaas@postgresql.org      739         [ +  + ]:          26358 :     if (stmt->partspec != NULL)
                                740                 :                :     {
                                741         [ -  + ]:           2435 :         if (relkind != RELKIND_RELATION)
 2685 rhaas@postgresql.org      742         [ #  # ]:UBC           0 :             elog(ERROR, "unexpected relkind: %d", (int) relkind);
                                743                 :                : 
 2685 rhaas@postgresql.org      744                 :CBC        2435 :         relkind = RELKIND_PARTITIONED_TABLE;
 1816 alvherre@alvh.no-ip.      745                 :           2435 :         partitioned = true;
                                746                 :                :     }
                                747                 :                :     else
                                748                 :          23923 :         partitioned = false;
                                749                 :                : 
                                750                 :                :     /*
                                751                 :                :      * Look up the namespace in which we are supposed to create the relation,
                                752                 :                :      * check we have permission to create there, lock it against concurrent
                                753                 :                :      * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
                                754                 :                :      * namespace is selected.
                                755                 :                :      */
                                756                 :                :     namespaceId =
 4472 rhaas@postgresql.org      757                 :          26358 :         RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
                                758                 :                : 
                                759                 :                :     /*
                                760                 :                :      * Security check: disallow creating temp tables from security-restricted
                                761                 :                :      * code.  This is needed because calling code might not expect untrusted
                                762                 :                :      * tables to appear in pg_temp at the front of its search path.
                                763                 :                :      */
 4871                           764         [ +  + ]:          26358 :     if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
                                765         [ -  + ]:           1485 :         && InSecurityRestrictedOperation())
 5240 tgl@sss.pgh.pa.us         766         [ #  # ]:UBC           0 :         ereport(ERROR,
                                767                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                768                 :                :                  errmsg("cannot create temporary table within security-restricted operation")));
                                769                 :                : 
                                770                 :                :     /*
                                771                 :                :      * Determine the lockmode to use when scanning parents.  A self-exclusive
                                772                 :                :      * lock is needed here.
                                773                 :                :      *
                                774                 :                :      * For regular inheritance, if two backends attempt to add children to the
                                775                 :                :      * same parent simultaneously, and that parent has no pre-existing
                                776                 :                :      * children, then both will attempt to update the parent's relhassubclass
                                777                 :                :      * field, leading to a "tuple concurrently updated" error.  Also, this
                                778                 :                :      * interlocks against a concurrent ANALYZE on the parent table, which
                                779                 :                :      * might otherwise be attempting to clear the parent's relhassubclass
                                780                 :                :      * field, if its previous children were recently dropped.
                                781                 :                :      *
                                782                 :                :      * If the child table is a partition, then we instead grab an exclusive
                                783                 :                :      * lock on the parent because its partition descriptor will be changed by
                                784                 :                :      * addition of the new partition.
                                785                 :                :      */
 1945 alvherre@alvh.no-ip.      786         [ +  + ]:CBC       26358 :     parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
                                787                 :                :                       ShareUpdateExclusiveLock);
                                788                 :                : 
                                789                 :                :     /* Determine the list of OIDs of the parents. */
                                790                 :          26358 :     inheritOids = NIL;
                                791   [ +  +  +  +  :          31522 :     foreach(listptr, stmt->inhRelations)
                                              +  + ]
                                792                 :                :     {
                                793                 :           5164 :         RangeVar   *rv = (RangeVar *) lfirst(listptr);
                                794                 :                :         Oid         parentOid;
                                795                 :                : 
                                796                 :           5164 :         parentOid = RangeVarGetRelid(rv, parentLockmode, false);
                                797                 :                : 
                                798                 :                :         /*
                                799                 :                :          * Reject duplications in the list of parents.
                                800                 :                :          */
                                801         [ -  + ]:           5164 :         if (list_member_oid(inheritOids, parentOid))
 1945 alvherre@alvh.no-ip.      802         [ #  # ]:UBC           0 :             ereport(ERROR,
                                803                 :                :                     (errcode(ERRCODE_DUPLICATE_TABLE),
                                804                 :                :                      errmsg("relation \"%s\" would be inherited from more than once",
                                805                 :                :                             get_rel_name(parentOid))));
                                806                 :                : 
 1945 alvherre@alvh.no-ip.      807                 :CBC        5164 :         inheritOids = lappend_oid(inheritOids, parentOid);
                                808                 :                :     }
                                809                 :                : 
                                810                 :                :     /*
                                811                 :                :      * Select tablespace to use: an explicitly indicated one, or (in the case
                                812                 :                :      * of a partitioned table) the parent's, if it has one.
                                813                 :                :      */
 7240 tgl@sss.pgh.pa.us         814         [ +  + ]:          26358 :     if (stmt->tablespacename)
                                815                 :                :     {
 5001 rhaas@postgresql.org      816                 :             55 :         tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
                                817                 :                : 
 1816 alvherre@alvh.no-ip.      818   [ +  +  +  + ]:             52 :         if (partitioned && tablespaceId == MyDatabaseTableSpace)
                                819         [ +  - ]:              3 :             ereport(ERROR,
                                820                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                821                 :                :                      errmsg("cannot specify default tablespace for partitioned relations")));
                                822                 :                :     }
 1945                           823         [ +  + ]:          26303 :     else if (stmt->partbound)
                                824                 :                :     {
                                825         [ -  + ]:           4131 :         Assert(list_length(inheritOids) == 1);
 1816                           826                 :           4131 :         tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
                                827                 :                :     }
                                828                 :                :     else
 1773                           829                 :          22172 :         tablespaceId = InvalidOid;
                                830                 :                : 
                                831                 :                :     /* still nothing? use the default */
                                832         [ +  + ]:          26352 :     if (!OidIsValid(tablespaceId))
 1816                           833                 :          26292 :         tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
                                834                 :                :                                             partitioned);
                                835                 :                : 
                                836                 :                :     /* Check permissions except when using database's default */
 5911 tgl@sss.pgh.pa.us         837   [ +  +  +  + ]:          26349 :     if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
                                838                 :                :     {
                                839                 :                :         AclResult   aclresult;
                                840                 :                : 
  518 peter@eisentraut.org      841                 :             69 :         aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
                                842                 :                :                                     ACL_CREATE);
 7240 tgl@sss.pgh.pa.us         843         [ +  + ]:             69 :         if (aclresult != ACLCHECK_OK)
 2325 peter_e@gmx.net           844                 :              3 :             aclcheck_error(aclresult, OBJECT_TABLESPACE,
 7100 tgl@sss.pgh.pa.us         845                 :              3 :                            get_tablespace_name(tablespaceId));
                                846                 :                :     }
                                847                 :                : 
                                848                 :                :     /* In all cases disallow placing user relations in pg_global */
 5180                           849         [ +  + ]:          26346 :     if (tablespaceId == GLOBALTABLESPACE_OID)
                                850         [ +  - ]:              9 :         ereport(ERROR,
                                851                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                852                 :                :                  errmsg("only shared relations can be placed in pg_global tablespace")));
                                853                 :                : 
                                854                 :                :     /* Identify user ID that will own the table */
 4988                           855         [ +  + ]:          26337 :     if (!OidIsValid(ownerId))
                                856                 :          26223 :         ownerId = GetUserId();
                                857                 :                : 
                                858                 :                :     /*
                                859                 :                :      * Parse and validate reloptions, if any.
                                860                 :                :      */
 5550 alvherre@alvh.no-ip.      861                 :          26337 :     reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
                                862                 :                :                                      true, false);
                                863                 :                : 
 1613 michael@paquier.xyz       864      [ +  +  + ]:          26328 :     switch (relkind)
                                865                 :                :     {
                                866                 :           6542 :         case RELKIND_VIEW:
                                867                 :           6542 :             (void) view_reloptions(reloptions, true);
                                868                 :           6533 :             break;
                                869                 :           2426 :         case RELKIND_PARTITIONED_TABLE:
                                870                 :           2426 :             (void) partitioned_table_reloptions(reloptions, true);
                                871                 :           2423 :             break;
                                872                 :          17360 :         default:
    3 akorotkov@postgresql      873                 :          17360 :             (void) heap_reloptions(relkind, reloptions, true);
                                874                 :                :     }
                                875                 :                : 
 5190 peter_e@gmx.net           876         [ +  + ]:          26268 :     if (stmt->ofTypename)
                                877                 :                :     {
                                878                 :                :         AclResult   aclresult;
                                879                 :                : 
 4920                           880                 :             43 :         ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
                                881                 :                : 
  518 peter@eisentraut.org      882                 :             43 :         aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
 4499 peter_e@gmx.net           883         [ +  + ]:             43 :         if (aclresult != ACLCHECK_OK)
 4321                           884                 :              3 :             aclcheck_error_type(aclresult, ofTypeId);
                                885                 :                :     }
                                886                 :                :     else
 5190                           887                 :          26225 :         ofTypeId = InvalidOid;
                                888                 :                : 
                                889                 :                :     /*
                                890                 :                :      * Look up inheritance ancestors and generate relation schema, including
                                891                 :                :      * inherited attributes.  (Note that stmt->tableElts is destructively
                                892                 :                :      * modified by MergeAttributes.)
                                893                 :                :      */
 2522 rhaas@postgresql.org      894                 :          26181 :     stmt->tableElts =
 1945 alvherre@alvh.no-ip.      895                 :          26265 :         MergeAttributes(stmt->tableElts, inheritOids,
 2522 rhaas@postgresql.org      896                 :          26265 :                         stmt->relation->relpersistence,
                                897                 :          26265 :                         stmt->partbound != NULL,
                                898                 :                :                         &old_constraints, &old_notnulls);
                                899                 :                : 
                                900                 :                :     /*
                                901                 :                :      * Create a tuple descriptor from the relation schema.  Note that this
                                902                 :                :      * deals with column names, types, and in-descriptor NOT NULL flags, but
                                903                 :                :      * not default values, NOT NULL or CHECK constraints; we handle those
                                904                 :                :      * below.
                                905                 :                :      */
                                906                 :          26181 :     descriptor = BuildDescForRelation(stmt->tableElts);
                                907                 :                : 
                                908                 :                :     /*
                                909                 :                :      * Find columns with default values and prepare for insertion of the
                                910                 :                :      * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
                                911                 :                :      * CookedConstraint structs that we'll pass to heap_create_with_catalog,
                                912                 :                :      * while raw defaults go into a list of RawColumnDefault structs that will
                                913                 :                :      * be processed by AddRelationNewConstraints.  (We can't deal with raw
                                914                 :                :      * expressions until we can do transformExpr.)
                                915                 :                :      *
                                916                 :                :      * We can set the atthasdef flags now in the tuple descriptor; this just
                                917                 :                :      * saves StoreAttrDefault from having to do an immediate update of the
                                918                 :                :      * pg_attribute rows.
                                919                 :                :      */
 5819 tgl@sss.pgh.pa.us         920                 :          26157 :     rawDefaults = NIL;
                                921                 :          26157 :     cookedDefaults = NIL;
                                922                 :          26157 :     attnum = 0;
                                923                 :                : 
 2522 rhaas@postgresql.org      924   [ +  +  +  +  :         131731 :     foreach(listptr, stmt->tableElts)
                                              +  + ]
                                925                 :                :     {
 5819 tgl@sss.pgh.pa.us         926                 :         105574 :         ColumnDef  *colDef = lfirst(listptr);
                                927                 :                :         Form_pg_attribute attr;
                                928                 :                : 
                                929                 :         105574 :         attnum++;
 2429 andres@anarazel.de        930                 :         105574 :         attr = TupleDescAttr(descriptor, attnum - 1);
                                931                 :                : 
 5819 tgl@sss.pgh.pa.us         932         [ +  + ]:         105574 :         if (colDef->raw_default != NULL)
                                933                 :                :         {
                                934                 :                :             RawColumnDefault *rawEnt;
                                935                 :                : 
                                936         [ -  + ]:           1203 :             Assert(colDef->cooked_default == NULL);
                                937                 :                : 
                                938                 :           1203 :             rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
                                939                 :           1203 :             rawEnt->attnum = attnum;
                                940                 :           1203 :             rawEnt->raw_default = colDef->raw_default;
 2209 andrew@dunslane.net       941                 :           1203 :             rawEnt->missingMode = false;
 1842 peter@eisentraut.org      942                 :           1203 :             rawEnt->generated = colDef->generated;
 5819 tgl@sss.pgh.pa.us         943                 :           1203 :             rawDefaults = lappend(rawDefaults, rawEnt);
 2429 andres@anarazel.de        944                 :           1203 :             attr->atthasdef = true;
                                945                 :                :         }
 5819 tgl@sss.pgh.pa.us         946         [ +  + ]:         104371 :         else if (colDef->cooked_default != NULL)
                                947                 :                :         {
                                948                 :                :             CookedConstraint *cooked;
                                949                 :                : 
                                950                 :            221 :             cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
                                951                 :            221 :             cooked->contype = CONSTR_DEFAULT;
 2489                           952                 :            221 :             cooked->conoid = InvalidOid; /* until created */
 5819                           953                 :            221 :             cooked->name = NULL;
                                954                 :            221 :             cooked->attnum = attnum;
 5304                           955                 :            221 :             cooked->expr = colDef->cooked_default;
 4701 alvherre@alvh.no-ip.      956                 :            221 :             cooked->skip_validation = false;
 5819 tgl@sss.pgh.pa.us         957                 :            221 :             cooked->is_local = true; /* not used for defaults */
 2489                           958                 :            221 :             cooked->inhcount = 0;    /* ditto */
 4377 alvherre@alvh.no-ip.      959                 :            221 :             cooked->is_no_inherit = false;
 5819 tgl@sss.pgh.pa.us         960                 :            221 :             cookedDefaults = lappend(cookedDefaults, cooked);
 2429 andres@anarazel.de        961                 :            221 :             attr->atthasdef = true;
                                962                 :                :         }
                                963                 :                :     }
                                964                 :                : 
                                965                 :                :     /*
                                966                 :                :      * For relations with table AM and partitioned tables, select access
                                967                 :                :      * method to use: an explicitly indicated one, or (in the case of a
                                968                 :                :      * partitioned table) the parent's, if it has one.
                                969                 :                :      */
    3 akorotkov@postgresql      970         [ +  + ]:          26157 :     if (stmt->accessMethod != NULL)
                                971                 :                :     {
    3 akorotkov@postgresql      972   [ +  +  +  -  :GNC          58 :         Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
                                        +  +  -  + ]
                                973                 :             58 :         accessMethodId = get_table_am_oid(stmt->accessMethod, false);
                                974                 :                :     }
                                975   [ +  +  +  -  :          26099 :     else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
                                        +  +  +  + ]
                                976                 :                :     {
                                977         [ +  + ]:          18176 :         if (stmt->partbound)
                                978                 :                :         {
                                979         [ -  + ]:           4052 :             Assert(list_length(inheritOids) == 1);
                                980                 :           4052 :             accessMethodId = get_rel_relam(linitial_oid(inheritOids));
                                981                 :                :         }
                                982                 :                : 
                                983   [ +  +  +  -  :          18176 :         if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
                                        +  +  +  + ]
                                984                 :          15743 :             accessMethodId = get_table_am_oid(default_table_access_method, false);
                                985                 :                :     }
                                986                 :                : 
                                987                 :                :     /*
                                988                 :                :      * Create the relation.  Inherited defaults and constraints are passed in
                                989                 :                :      * for immediate handling --- since they don't need parsing, they can be
                                990                 :                :      * stored immediately.
                                991                 :                :      */
 8024 tgl@sss.pgh.pa.us         992                 :CBC       26148 :     relationId = heap_create_with_catalog(relname,
                                993                 :                :                                           namespaceId,
                                994                 :                :                                           tablespaceId,
                                995                 :                :                                           InvalidOid,
                                996                 :                :                                           InvalidOid,
                                997                 :                :                                           ofTypeId,
                                998                 :                :                                           ownerId,
                                999                 :                :                                           accessMethodId,
                               1000                 :                :                                           descriptor,
                               1001                 :                :                                           list_concat(cookedDefaults,
                               1002                 :                :                                                       old_constraints),
                               1003                 :                :                                           relkind,
 4871 rhaas@postgresql.org     1004                 :          26148 :                                           stmt->relation->relpersistence,
                               1005                 :                :                                           false,
                               1006                 :                :                                           false,
                               1007                 :                :                                           stmt->oncommit,
                               1008                 :                :                                           reloptions,
                               1009                 :                :                                           true,
                               1010                 :                :                                           allowSystemTableMods,
                               1011                 :                :                                           false,
                               1012                 :                :                                           InvalidOid,
                               1013                 :                :                                           typaddress);
                               1014                 :                : 
                               1015                 :                :     /*
                               1016                 :                :      * We must bump the command counter to make the newly-created relation
                               1017                 :                :      * tuple visible for opening.
                               1018                 :                :      */
 8024 tgl@sss.pgh.pa.us        1019                 :          26136 :     CommandCounterIncrement();
                               1020                 :                : 
                               1021                 :                :     /*
                               1022                 :                :      * Open the new relation and acquire exclusive lock on it.  This isn't
                               1023                 :                :      * really necessary for locking out other backends (since they can't see
                               1024                 :                :      * the new rel anyway until we commit), but it keeps the lock manager from
                               1025                 :                :      * complaining about deadlock risks.
                               1026                 :                :      */
 7899                          1027                 :          26136 :     rel = relation_open(relationId, AccessExclusiveLock);
                               1028                 :                : 
                               1029                 :                :     /*
                               1030                 :                :      * Now add any newly specified column default and generation expressions
                               1031                 :                :      * to the new relation.  These are passed to us in the form of raw
                               1032                 :                :      * parsetrees; we need to transform them to executable expression trees
                               1033                 :                :      * before they can be added. The most convenient way to do that is to
                               1034                 :                :      * apply the parser's transformExpr routine, but transformExpr doesn't
                               1035                 :                :      * work unless we have a pre-existing relation. So, the transformation has
                               1036                 :                :      * to be postponed to this final step of CREATE TABLE.
                               1037                 :                :      *
                               1038                 :                :      * This needs to be before processing the partitioning clauses because
                               1039                 :                :      * those could refer to generated columns.
                               1040                 :                :      */
 1842 peter@eisentraut.org     1041         [ +  + ]:          26136 :     if (rawDefaults)
                               1042                 :           1017 :         AddRelationNewConstraints(rel, rawDefaults, NIL,
                               1043                 :                :                                   true, true, false, queryString);
                               1044                 :                : 
                               1045                 :                :     /*
                               1046                 :                :      * Make column generation expressions visible for use by partitioning.
                               1047                 :                :      */
                               1048                 :          26085 :     CommandCounterIncrement();
                               1049                 :                : 
                               1050                 :                :     /* Process and store partition bound, if any. */
 2685 rhaas@postgresql.org     1051         [ +  + ]:          26085 :     if (stmt->partbound)
                               1052                 :                :     {
                               1053                 :                :         PartitionBoundSpec *bound;
                               1054                 :                :         ParseState *pstate;
 2410                          1055                 :           4104 :         Oid         parentId = linitial_oid(inheritOids),
                               1056                 :                :                     defaultPartOid;
                               1057                 :                :         Relation    parent,
                               1058                 :           4104 :                     defaultRel = NULL;
                               1059                 :                :         ParseNamespaceItem *nsitem;
                               1060                 :                : 
                               1061                 :                :         /* Already have strong enough lock on the parent */
 1910 andres@anarazel.de       1062                 :           4104 :         parent = table_open(parentId, NoLock);
                               1063                 :                : 
                               1064                 :                :         /*
                               1065                 :                :          * We are going to try to validate the partition bound specification
                               1066                 :                :          * against the partition key of parentRel, so it better have one.
                               1067                 :                :          */
 2685 rhaas@postgresql.org     1068         [ +  + ]:           4104 :         if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
                               1069         [ +  - ]:              9 :             ereport(ERROR,
                               1070                 :                :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                               1071                 :                :                      errmsg("\"%s\" is not partitioned",
                               1072                 :                :                             RelationGetRelationName(parent))));
                               1073                 :                : 
                               1074                 :                :         /*
                               1075                 :                :          * The partition constraint of the default partition depends on the
                               1076                 :                :          * partition bounds of every other partition. It is possible that
                               1077                 :                :          * another backend might be about to execute a query on the default
                               1078                 :                :          * partition table, and that the query relies on previously cached
                               1079                 :                :          * default partition constraints. We must therefore take a table lock
                               1080                 :                :          * strong enough to prevent all queries on the default partition from
                               1081                 :                :          * proceeding until we commit and send out a shared-cache-inval notice
                               1082                 :                :          * that will make them update their index lists.
                               1083                 :                :          *
                               1084                 :                :          * Order of locking: The relation being added won't be visible to
                               1085                 :                :          * other backends until it is committed, hence here in
                               1086                 :                :          * DefineRelation() the order of locking the default partition and the
                               1087                 :                :          * relation being added does not matter. But at all other places we
                               1088                 :                :          * need to lock the default relation before we lock the relation being
                               1089                 :                :          * added or removed i.e. we should take the lock in same order at all
                               1090                 :                :          * the places such that lock parent, lock default partition and then
                               1091                 :                :          * lock the partition so as to avoid a deadlock.
                               1092                 :                :          */
                               1093                 :                :         defaultPartOid =
 1116 alvherre@alvh.no-ip.     1094                 :           4095 :             get_default_oid_from_partdesc(RelationGetPartitionDesc(parent,
                               1095                 :                :                                                                    true));
 2410 rhaas@postgresql.org     1096         [ +  + ]:           4095 :         if (OidIsValid(defaultPartOid))
 1910 andres@anarazel.de       1097                 :            189 :             defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
                               1098                 :                : 
                               1099                 :                :         /* Transform the bound values */
 2685 rhaas@postgresql.org     1100                 :           4095 :         pstate = make_parsestate(NULL);
                               1101                 :           4095 :         pstate->p_sourcetext = queryString;
                               1102                 :                : 
                               1103                 :                :         /*
                               1104                 :                :          * Add an nsitem containing this relation, so that transformExpr
                               1105                 :                :          * called on partition bound expressions is able to report errors
                               1106                 :                :          * using a proper context.
                               1107                 :                :          */
 1564 tgl@sss.pgh.pa.us        1108                 :           4095 :         nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
                               1109                 :                :                                                NULL, false, false);
                               1110                 :           4095 :         addNSItemToQuery(pstate, nsitem, false, true, true);
                               1111                 :                : 
 2685 rhaas@postgresql.org     1112                 :           4095 :         bound = transformPartitionBound(pstate, parent, stmt->partbound);
                               1113                 :                : 
                               1114                 :                :         /*
                               1115                 :                :          * Check first that the new partition's bound is valid and does not
                               1116                 :                :          * overlap with any of existing partitions of the parent.
                               1117                 :                :          */
 1299 tgl@sss.pgh.pa.us        1118                 :           3993 :         check_new_partition_bound(relname, parent, bound, pstate);
                               1119                 :                : 
                               1120                 :                :         /*
                               1121                 :                :          * If the default partition exists, its partition constraints will
                               1122                 :                :          * change after the addition of this new partition such that it won't
                               1123                 :                :          * allow any row that qualifies for this new partition. So, check that
                               1124                 :                :          * the existing data in the default partition satisfies the constraint
                               1125                 :                :          * as it will exist after adding this partition.
                               1126                 :                :          */
 2410 rhaas@postgresql.org     1127         [ +  + ]:           3936 :         if (OidIsValid(defaultPartOid))
                               1128                 :                :         {
 2132 tgl@sss.pgh.pa.us        1129                 :            174 :             check_default_partition_contents(parent, defaultRel, bound);
                               1130                 :                :             /* Keep the lock until commit. */
 1910 andres@anarazel.de       1131                 :            165 :             table_close(defaultRel, NoLock);
                               1132                 :                :         }
                               1133                 :                : 
                               1134                 :                :         /* Update the pg_class entry. */
 2673 rhaas@postgresql.org     1135                 :           3927 :         StorePartitionBound(rel, parent, bound);
                               1136                 :                : 
 1910 andres@anarazel.de       1137                 :           3927 :         table_close(parent, NoLock);
                               1138                 :                :     }
                               1139                 :                : 
                               1140                 :                :     /* Store inheritance information for new rel. */
 2048 alvherre@alvh.no-ip.     1141                 :          25908 :     StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
                               1142                 :                : 
                               1143                 :                :     /*
                               1144                 :                :      * Process the partitioning specification (if any) and store the partition
                               1145                 :                :      * key information into the catalog.
                               1146                 :                :      */
 1816                          1147         [ +  + ]:          25908 :     if (partitioned)
                               1148                 :                :     {
                               1149                 :                :         ParseState *pstate;
                               1150                 :                :         int         partnatts;
                               1151                 :                :         AttrNumber  partattrs[PARTITION_MAX_KEYS];
                               1152                 :                :         Oid         partopclass[PARTITION_MAX_KEYS];
                               1153                 :                :         Oid         partcollation[PARTITION_MAX_KEYS];
 2679 rhaas@postgresql.org     1154                 :           2423 :         List       *partexprs = NIL;
                               1155                 :                : 
 2062 peter_e@gmx.net          1156                 :           2423 :         pstate = make_parsestate(NULL);
                               1157                 :           2423 :         pstate->p_sourcetext = queryString;
                               1158                 :                : 
 2513 tgl@sss.pgh.pa.us        1159                 :           2423 :         partnatts = list_length(stmt->partspec->partParams);
                               1160                 :                : 
                               1161                 :                :         /* Protect fixed-size arrays here and in executor */
                               1162         [ -  + ]:           2423 :         if (partnatts > PARTITION_MAX_KEYS)
 2513 tgl@sss.pgh.pa.us        1163         [ #  # ]:UBC           0 :             ereport(ERROR,
                               1164                 :                :                     (errcode(ERRCODE_TOO_MANY_COLUMNS),
                               1165                 :                :                      errmsg("cannot partition using more than %d columns",
                               1166                 :                :                             PARTITION_MAX_KEYS)));
                               1167                 :                : 
                               1168                 :                :         /*
                               1169                 :                :          * We need to transform the raw parsetrees corresponding to partition
                               1170                 :                :          * expressions into executable expression trees.  Like column defaults
                               1171                 :                :          * and CHECK constraints, we could not have done the transformation
                               1172                 :                :          * earlier.
                               1173                 :                :          */
  528 alvherre@alvh.no-ip.     1174                 :CBC        2423 :         stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
                               1175                 :                : 
 2062 peter_e@gmx.net          1176                 :           2408 :         ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
                               1177                 :                :                               partattrs, &partexprs, partopclass,
  528 alvherre@alvh.no-ip.     1178                 :           2408 :                               partcollation, stmt->partspec->strategy);
                               1179                 :                : 
                               1180                 :           2366 :         StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
                               1181                 :                :                           partexprs,
                               1182                 :                :                           partopclass, partcollation);
                               1183                 :                : 
                               1184                 :                :         /* make it all visible */
 2277                          1185                 :           2366 :         CommandCounterIncrement();
                               1186                 :                :     }
                               1187                 :                : 
                               1188                 :                :     /*
                               1189                 :                :      * If we're creating a partition, create now all the indexes, triggers,
                               1190                 :                :      * FKs defined in the parent.
                               1191                 :                :      *
                               1192                 :                :      * We can't do it earlier, because DefineIndex wants to know the partition
                               1193                 :                :      * key which we just stored.
                               1194                 :                :      */
                               1195         [ +  + ]:          25851 :     if (stmt->partbound)
                               1196                 :                :     {
                               1197                 :           3924 :         Oid         parentId = linitial_oid(inheritOids);
                               1198                 :                :         Relation    parent;
                               1199                 :                :         List       *idxlist;
                               1200                 :                :         ListCell   *cell;
                               1201                 :                : 
                               1202                 :                :         /* Already have strong enough lock on the parent */
 1910 andres@anarazel.de       1203                 :           3924 :         parent = table_open(parentId, NoLock);
 2277 alvherre@alvh.no-ip.     1204                 :           3924 :         idxlist = RelationGetIndexList(parent);
                               1205                 :                : 
                               1206                 :                :         /*
                               1207                 :                :          * For each index in the parent table, create one in the partition
                               1208                 :                :          */
                               1209   [ +  +  +  +  :           4638 :         foreach(cell, idxlist)
                                              +  + ]
                               1210                 :                :         {
                               1211                 :            723 :             Relation    idxRel = index_open(lfirst_oid(cell), AccessShareLock);
                               1212                 :                :             AttrMap    *attmap;
                               1213                 :                :             IndexStmt  *idxstmt;
                               1214                 :                :             Oid         constraintOid;
                               1215                 :                : 
 1754                          1216         [ +  + ]:            723 :             if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
                               1217                 :                :             {
                               1218         [ +  + ]:             18 :                 if (idxRel->rd_index->indisunique)
                               1219         [ +  - ]:              6 :                     ereport(ERROR,
                               1220                 :                :                             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               1221                 :                :                              errmsg("cannot create foreign partition of partitioned table \"%s\"",
                               1222                 :                :                                     RelationGetRelationName(parent)),
                               1223                 :                :                              errdetail("Table \"%s\" contains indexes that are unique.",
                               1224                 :                :                                        RelationGetRelationName(parent))));
                               1225                 :                :                 else
                               1226                 :                :                 {
                               1227                 :             12 :                     index_close(idxRel, AccessShareLock);
                               1228                 :             12 :                     continue;
                               1229                 :                :                 }
                               1230                 :                :             }
                               1231                 :                : 
 1579 michael@paquier.xyz      1232                 :            705 :             attmap = build_attrmap_by_name(RelationGetDescr(rel),
                               1233                 :                :                                            RelationGetDescr(parent),
                               1234                 :                :                                            false);
                               1235                 :                :             idxstmt =
 1818 tgl@sss.pgh.pa.us        1236                 :            705 :                 generateClonedIndexStmt(NULL, idxRel,
                               1237                 :                :                                         attmap, &constraintOid);
 2277 alvherre@alvh.no-ip.     1238                 :            705 :             DefineIndex(RelationGetRelid(rel),
                               1239                 :                :                         idxstmt,
                               1240                 :                :                         InvalidOid,
                               1241                 :                :                         RelationGetRelid(idxRel),
                               1242                 :                :                         constraintOid,
                               1243                 :                :                         -1,
                               1244                 :                :                         false, false, false, false, false);
                               1245                 :                : 
                               1246                 :            702 :             index_close(idxRel, AccessShareLock);
                               1247                 :                :         }
                               1248                 :                : 
                               1249                 :           3915 :         list_free(idxlist);
                               1250                 :                : 
                               1251                 :                :         /*
                               1252                 :                :          * If there are any row-level triggers, clone them to the new
                               1253                 :                :          * partition.
                               1254                 :                :          */
 2214                          1255         [ +  + ]:           3915 :         if (parent->trigdesc != NULL)
                               1256                 :            213 :             CloneRowTriggersToPartition(parent, rel);
                               1257                 :                : 
                               1258                 :                :         /*
                               1259                 :                :          * And foreign keys too.  Note that because we're freshly creating the
                               1260                 :                :          * table, there is no need to verify these new constraints.
                               1261                 :                :          */
 1838                          1262                 :           3915 :         CloneForeignKeyConstraints(NULL, parent, rel);
                               1263                 :                : 
 1910 andres@anarazel.de       1264                 :           3915 :         table_close(parent, NoLock);
                               1265                 :                :     }
                               1266                 :                : 
                               1267                 :                :     /*
                               1268                 :                :      * Now add any newly specified CHECK constraints to the new relation. Same
                               1269                 :                :      * as for defaults above, but these need to come after partitioning is set
                               1270                 :                :      * up.
                               1271                 :                :      */
 1842 peter@eisentraut.org     1272         [ +  + ]:          25842 :     if (stmt->constraints)
                               1273                 :            324 :         AddRelationNewConstraints(rel, NIL, stmt->constraints,
                               1274                 :                :                                   true, true, false, queryString);
                               1275                 :                : 
                               1276                 :                :     /*
                               1277                 :                :      * Finally, merge the not-null constraints that are declared directly with
                               1278                 :                :      * those that come from parent relations (making sure to count inheritance
                               1279                 :                :      * appropriately for each), create them, and set the attnotnull flag on
                               1280                 :                :      * columns that don't yet have it.
                               1281                 :                :      */
  233 alvherre@alvh.no-ip.     1282                 :GNC       25833 :     nncols = AddRelationNotNullConstraints(rel, stmt->nnconstraints,
                               1283                 :                :                                            old_notnulls);
                               1284   [ +  +  +  +  :          29567 :     foreach(listptr, nncols)
                                              +  + ]
                               1285                 :           3740 :         set_attnotnull(NULL, rel, lfirst_int(listptr), false, NoLock);
                               1286                 :                : 
 3330 alvherre@alvh.no-ip.     1287                 :CBC       25827 :     ObjectAddressSet(address, RelationRelationId, relationId);
                               1288                 :                : 
                               1289                 :                :     /*
                               1290                 :                :      * Clean up.  We keep lock on new relation (although it shouldn't be
                               1291                 :                :      * visible to anyone else anyway, until commit).
                               1292                 :                :      */
 7899 tgl@sss.pgh.pa.us        1293                 :          25827 :     relation_close(rel, NoLock);
                               1294                 :                : 
 3330 alvherre@alvh.no-ip.     1295                 :          25827 :     return address;
                               1296                 :                : }
                               1297                 :                : 
                               1298                 :                : /*
                               1299                 :                :  * BuildDescForRelation
                               1300                 :                :  *
                               1301                 :                :  * Given a list of ColumnDef nodes, build a TupleDesc.
                               1302                 :                :  *
                               1303                 :                :  * Note: tdtypeid will need to be filled in later on.
                               1304                 :                :  */
                               1305                 :                : TupleDesc
  192 peter@eisentraut.org     1306                 :GNC       27517 : BuildDescForRelation(const List *columns)
                               1307                 :                : {
                               1308                 :                :     int         natts;
                               1309                 :                :     AttrNumber  attnum;
                               1310                 :                :     ListCell   *l;
                               1311                 :                :     TupleDesc   desc;
                               1312                 :                :     bool        has_not_null;
                               1313                 :                :     char       *attname;
                               1314                 :                :     Oid         atttypid;
                               1315                 :                :     int32       atttypmod;
                               1316                 :                :     Oid         attcollation;
                               1317                 :                :     int         attdim;
                               1318                 :                : 
                               1319                 :                :     /*
                               1320                 :                :      * allocate a new tuple descriptor
                               1321                 :                :      */
                               1322                 :          27517 :     natts = list_length(columns);
                               1323                 :          27517 :     desc = CreateTemplateTupleDesc(natts);
                               1324                 :          27517 :     has_not_null = false;
                               1325                 :                : 
                               1326                 :          27517 :     attnum = 0;
                               1327                 :                : 
                               1328   [ +  +  +  +  :         134559 :     foreach(l, columns)
                                              +  + ]
                               1329                 :                :     {
                               1330                 :         107072 :         ColumnDef  *entry = lfirst(l);
                               1331                 :                :         AclResult   aclresult;
                               1332                 :                :         Form_pg_attribute att;
                               1333                 :                : 
                               1334                 :                :         /*
                               1335                 :                :          * for each entry in the list, get the name and type information from
                               1336                 :                :          * the list and have TupleDescInitEntry fill in the attribute
                               1337                 :                :          * information we need.
                               1338                 :                :          */
                               1339                 :         107072 :         attnum++;
                               1340                 :                : 
                               1341                 :         107072 :         attname = entry->colname;
                               1342                 :         107072 :         typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
                               1343                 :                : 
                               1344                 :         107072 :         aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
                               1345         [ +  + ]:         107072 :         if (aclresult != ACLCHECK_OK)
                               1346                 :             21 :             aclcheck_error_type(aclresult, atttypid);
                               1347                 :                : 
                               1348                 :         107051 :         attcollation = GetColumnDefCollation(NULL, entry, atttypid);
                               1349                 :         107051 :         attdim = list_length(entry->typeName->arrayBounds);
                               1350         [ -  + ]:         107051 :         if (attdim > PG_INT16_MAX)
  192 peter@eisentraut.org     1351         [ #  # ]:UNC           0 :             ereport(ERROR,
                               1352                 :                :                     errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               1353                 :                :                     errmsg("too many array dimensions"));
                               1354                 :                : 
  192 peter@eisentraut.org     1355         [ -  + ]:GNC      107051 :         if (entry->typeName->setof)
  192 peter@eisentraut.org     1356         [ #  # ]:UNC           0 :             ereport(ERROR,
                               1357                 :                :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               1358                 :                :                      errmsg("column \"%s\" cannot be declared SETOF",
                               1359                 :                :                             attname)));
                               1360                 :                : 
  192 peter@eisentraut.org     1361                 :GNC      107051 :         TupleDescInitEntry(desc, attnum, attname,
                               1362                 :                :                            atttypid, atttypmod, attdim);
                               1363                 :         107051 :         att = TupleDescAttr(desc, attnum - 1);
                               1364                 :                : 
                               1365                 :                :         /* Override TupleDescInitEntry's settings as requested */
                               1366                 :         107051 :         TupleDescInitEntryCollation(desc, attnum, attcollation);
                               1367                 :                : 
                               1368                 :                :         /* Fill in additional stuff not handled by TupleDescInitEntry */
                               1369                 :         107051 :         att->attnotnull = entry->is_not_null;
                               1370                 :         107051 :         has_not_null |= entry->is_not_null;
                               1371                 :         107051 :         att->attislocal = entry->is_local;
                               1372                 :         107051 :         att->attinhcount = entry->inhcount;
                               1373                 :         107051 :         att->attidentity = entry->identity;
                               1374                 :         107051 :         att->attgenerated = entry->generated;
                               1375                 :         107051 :         att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
   54                          1376         [ +  + ]:         107045 :         if (entry->storage)
                               1377                 :          11335 :             att->attstorage = entry->storage;
                               1378         [ +  + ]:          95710 :         else if (entry->storage_name)
  192                          1379                 :             10 :             att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
                               1380                 :                :     }
                               1381                 :                : 
                               1382         [ +  + ]:          27487 :     if (has_not_null)
                               1383                 :                :     {
                               1384                 :           6037 :         TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
                               1385                 :                : 
                               1386                 :           6037 :         constr->has_not_null = true;
                               1387                 :           6037 :         constr->has_generated_stored = false;
                               1388                 :           6037 :         constr->defval = NULL;
                               1389                 :           6037 :         constr->missing = NULL;
                               1390                 :           6037 :         constr->num_defval = 0;
                               1391                 :           6037 :         constr->check = NULL;
                               1392                 :           6037 :         constr->num_check = 0;
                               1393                 :           6037 :         desc->constr = constr;
                               1394                 :                :     }
                               1395                 :                :     else
                               1396                 :                :     {
                               1397                 :          21450 :         desc->constr = NULL;
                               1398                 :                :     }
                               1399                 :                : 
                               1400                 :          27487 :     return desc;
                               1401                 :                : }
                               1402                 :                : 
                               1403                 :                : /*
                               1404                 :                :  * Emit the right error or warning message for a "DROP" command issued on a
                               1405                 :                :  * non-existent relation
                               1406                 :                :  */
                               1407                 :                : static void
 3734 alvherre@alvh.no-ip.     1408                 :CBC         538 : DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
                               1409                 :                : {
                               1410                 :                :     const struct dropmsgstrings *rentry;
                               1411                 :                : 
                               1412   [ +  +  +  + ]:            598 :     if (rel->schemaname != NULL &&
                               1413                 :             60 :         !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
                               1414                 :                :     {
                               1415         [ -  + ]:             21 :         if (!missing_ok)
                               1416                 :                :         {
 3734 alvherre@alvh.no-ip.     1417         [ #  # ]:UBC           0 :             ereport(ERROR,
                               1418                 :                :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
                               1419                 :                :                      errmsg("schema \"%s\" does not exist", rel->schemaname)));
                               1420                 :                :         }
                               1421                 :                :         else
                               1422                 :                :         {
 3734 alvherre@alvh.no-ip.     1423         [ +  - ]:CBC          21 :             ereport(NOTICE,
                               1424                 :                :                     (errmsg("schema \"%s\" does not exist, skipping",
                               1425                 :                :                             rel->schemaname)));
                               1426                 :                :         }
                               1427                 :             21 :         return;
                               1428                 :                :     }
                               1429                 :                : 
 5783 tgl@sss.pgh.pa.us        1430         [ +  - ]:            677 :     for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
                               1431                 :                :     {
                               1432         [ +  + ]:            677 :         if (rentry->kind == rightkind)
                               1433                 :                :         {
                               1434         [ +  + ]:            517 :             if (!missing_ok)
                               1435                 :                :             {
                               1436         [ +  - ]:             65 :                 ereport(ERROR,
                               1437                 :                :                         (errcode(rentry->nonexistent_code),
                               1438                 :                :                          errmsg(rentry->nonexistent_msg, rel->relname)));
                               1439                 :                :             }
                               1440                 :                :             else
                               1441                 :                :             {
 3734 alvherre@alvh.no-ip.     1442         [ +  - ]:            452 :                 ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
 5783 tgl@sss.pgh.pa.us        1443                 :            452 :                 break;
                               1444                 :                :             }
                               1445                 :                :         }
                               1446                 :                :     }
                               1447                 :                : 
 2489                          1448         [ -  + ]:            452 :     Assert(rentry->kind != '\0');    /* Should be impossible */
                               1449                 :                : }
                               1450                 :                : 
                               1451                 :                : /*
                               1452                 :                :  * Emit the right error message for a "DROP" command issued on a
                               1453                 :                :  * relation of the wrong type
                               1454                 :                :  */
                               1455                 :                : static void
 5783 tgl@sss.pgh.pa.us        1456                 :UBC           0 : DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
                               1457                 :                : {
                               1458                 :                :     const struct dropmsgstrings *rentry;
                               1459                 :                :     const struct dropmsgstrings *wentry;
                               1460                 :                : 
                               1461         [ #  # ]:              0 :     for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
                               1462         [ #  # ]:              0 :         if (rentry->kind == rightkind)
                               1463                 :              0 :             break;
                               1464         [ #  # ]:              0 :     Assert(rentry->kind != '\0');
                               1465                 :                : 
                               1466         [ #  # ]:              0 :     for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
                               1467         [ #  # ]:              0 :         if (wentry->kind == wrongkind)
                               1468                 :              0 :             break;
                               1469                 :                :     /* wrongkind could be something we don't have in our table... */
                               1470                 :                : 
                               1471   [ #  #  #  # ]:              0 :     ereport(ERROR,
                               1472                 :                :             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               1473                 :                :              errmsg(rentry->nota_msg, relname),
                               1474                 :                :              (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
                               1475                 :                : }
                               1476                 :                : 
                               1477                 :                : /*
                               1478                 :                :  * RemoveRelations
                               1479                 :                :  *      Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
                               1480                 :                :  *      DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
                               1481                 :                :  */
                               1482                 :                : void
 5783 tgl@sss.pgh.pa.us        1483                 :CBC        8043 : RemoveRelations(DropStmt *drop)
                               1484                 :                : {
                               1485                 :                :     ObjectAddresses *objects;
                               1486                 :                :     char        relkind;
                               1487                 :                :     ListCell   *cell;
 4391 simon@2ndQuadrant.co     1488                 :           8043 :     int         flags = 0;
                               1489                 :           8043 :     LOCKMODE    lockmode = AccessExclusiveLock;
                               1490                 :                : 
                               1491                 :                :     /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
                               1492         [ +  + ]:           8043 :     if (drop->concurrent)
                               1493                 :                :     {
                               1494                 :                :         /*
                               1495                 :                :          * Note that for temporary relations this lock may get upgraded later
                               1496                 :                :          * on, but as no other session can access a temporary relation, this
                               1497                 :                :          * is actually fine.
                               1498                 :                :          */
                               1499                 :             70 :         lockmode = ShareUpdateExclusiveLock;
 4155 tgl@sss.pgh.pa.us        1500         [ -  + ]:             70 :         Assert(drop->removeType == OBJECT_INDEX);
                               1501         [ +  + ]:             70 :         if (list_length(drop->objects) != 1)
 4391 simon@2ndQuadrant.co     1502         [ +  - ]:              3 :             ereport(ERROR,
                               1503                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1504                 :                :                      errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
                               1505         [ -  + ]:             67 :         if (drop->behavior == DROP_CASCADE)
 4391 simon@2ndQuadrant.co     1506         [ #  # ]:UBC           0 :             ereport(ERROR,
                               1507                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1508                 :                :                      errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
                               1509                 :                :     }
                               1510                 :                : 
                               1511                 :                :     /*
                               1512                 :                :      * First we identify all the relations, then we delete them in a single
                               1513                 :                :      * performMultipleDeletions() call.  This is to avoid unwanted DROP
                               1514                 :                :      * RESTRICT errors if one of the relations depends on another.
                               1515                 :                :      */
                               1516                 :                : 
                               1517                 :                :     /* Determine required relkind */
 5783 tgl@sss.pgh.pa.us        1518   [ +  +  +  +  :CBC        8040 :     switch (drop->removeType)
                                           +  +  - ]
                               1519                 :                :     {
                               1520                 :           6987 :         case OBJECT_TABLE:
                               1521                 :           6987 :             relkind = RELKIND_RELATION;
                               1522                 :           6987 :             break;
                               1523                 :                : 
                               1524                 :            393 :         case OBJECT_INDEX:
                               1525                 :            393 :             relkind = RELKIND_INDEX;
                               1526                 :            393 :             break;
                               1527                 :                : 
                               1528                 :             86 :         case OBJECT_SEQUENCE:
                               1529                 :             86 :             relkind = RELKIND_SEQUENCE;
                               1530                 :             86 :             break;
                               1531                 :                : 
                               1532                 :            440 :         case OBJECT_VIEW:
                               1533                 :            440 :             relkind = RELKIND_VIEW;
                               1534                 :            440 :             break;
                               1535                 :                : 
 4060 kgrittn@postgresql.o     1536                 :             60 :         case OBJECT_MATVIEW:
                               1537                 :             60 :             relkind = RELKIND_MATVIEW;
                               1538                 :             60 :             break;
                               1539                 :                : 
 4852 rhaas@postgresql.org     1540                 :             74 :         case OBJECT_FOREIGN_TABLE:
                               1541                 :             74 :             relkind = RELKIND_FOREIGN_TABLE;
                               1542                 :             74 :             break;
                               1543                 :                : 
 5783 tgl@sss.pgh.pa.us        1544                 :UBC           0 :         default:
                               1545         [ #  # ]:              0 :             elog(ERROR, "unrecognized drop object type: %d",
                               1546                 :                :                  (int) drop->removeType);
                               1547                 :                :             relkind = 0;        /* keep compiler quiet */
                               1548                 :                :             break;
                               1549                 :                :     }
                               1550                 :                : 
                               1551                 :                :     /* Lock and validate each relation; build a list of object addresses */
 5783 tgl@sss.pgh.pa.us        1552                 :CBC        8040 :     objects = new_object_addresses();
                               1553                 :                : 
                               1554   [ +  -  +  +  :          17822 :     foreach(cell, drop->objects)
                                              +  + ]
                               1555                 :                :     {
                               1556                 :           9860 :         RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
                               1557                 :                :         Oid         relOid;
                               1558                 :                :         ObjectAddress obj;
                               1559                 :                :         struct DropRelationCallbackState state;
                               1560                 :                : 
                               1561                 :                :         /*
                               1562                 :                :          * These next few steps are a great deal like relation_openrv, but we
                               1563                 :                :          * don't bother building a relcache entry since we don't need it.
                               1564                 :                :          *
                               1565                 :                :          * Check for shared-cache-inval messages before trying to access the
                               1566                 :                :          * relation.  This is needed to cover the case where the name
                               1567                 :                :          * identifies a rel that has been dropped and recreated since the
                               1568                 :                :          * start of our transaction: if we don't flush the old syscache entry,
                               1569                 :                :          * then we'll latch onto that entry and suffer an error later.
                               1570                 :                :          */
                               1571                 :           9860 :         AcceptInvalidationMessages();
                               1572                 :                : 
                               1573                 :                :         /* Look up the appropriate relation using namespace search. */
  755                          1574                 :           9860 :         state.expected_relkind = relkind;
                               1575                 :          19720 :         state.heap_lockmode = drop->concurrent ?
                               1576         [ +  + ]:           9860 :             ShareUpdateExclusiveLock : AccessExclusiveLock;
                               1577                 :                :         /* We must initialize these fields to show that no locks are held: */
 4519 rhaas@postgresql.org     1578                 :           9860 :         state.heapOid = InvalidOid;
 2560                          1579                 :           9860 :         state.partParentOid = InvalidOid;
                               1580                 :                : 
 2207 andres@anarazel.de       1581                 :           9860 :         relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
                               1582                 :                :                                           RangeVarCallbackForDropRelation,
                               1583                 :                :                                           (void *) &state);
                               1584                 :                : 
                               1585                 :                :         /* Not there? */
 5783 tgl@sss.pgh.pa.us        1586         [ +  + ]:           9850 :         if (!OidIsValid(relOid))
                               1587                 :                :         {
 3734 alvherre@alvh.no-ip.     1588                 :            538 :             DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
 5783 tgl@sss.pgh.pa.us        1589                 :            473 :             continue;
                               1590                 :                :         }
                               1591                 :                : 
                               1592                 :                :         /*
                               1593                 :                :          * Decide if concurrent mode needs to be used here or not.  The
                               1594                 :                :          * callback retrieved the rel's persistence for us.
                               1595                 :                :          */
 1544 michael@paquier.xyz      1596         [ +  + ]:           9312 :         if (drop->concurrent &&
  755 tgl@sss.pgh.pa.us        1597         [ +  + ]:             64 :             state.actual_relpersistence != RELPERSISTENCE_TEMP)
                               1598                 :                :         {
 1544 michael@paquier.xyz      1599   [ +  -  -  + ]:             55 :             Assert(list_length(drop->objects) == 1 &&
                               1600                 :                :                    drop->removeType == OBJECT_INDEX);
                               1601                 :             55 :             flags |= PERFORM_DELETION_CONCURRENTLY;
                               1602                 :                :         }
                               1603                 :                : 
                               1604                 :                :         /*
                               1605                 :                :          * Concurrent index drop cannot be used with partitioned indexes,
                               1606                 :                :          * either.
                               1607                 :                :          */
 1321 alvherre@alvh.no-ip.     1608         [ +  + ]:           9312 :         if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
  755 tgl@sss.pgh.pa.us        1609         [ +  + ]:             55 :             state.actual_relkind == RELKIND_PARTITIONED_INDEX)
 1321 alvherre@alvh.no-ip.     1610         [ +  - ]:              3 :             ereport(ERROR,
                               1611                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1612                 :                :                      errmsg("cannot drop partitioned index \"%s\" concurrently",
                               1613                 :                :                             rel->relname)));
                               1614                 :                : 
                               1615                 :                :         /*
                               1616                 :                :          * If we're told to drop a partitioned index, we must acquire lock on
                               1617                 :                :          * all the children of its parent partitioned table before proceeding.
                               1618                 :                :          * Otherwise we'd try to lock the child index partitions before their
                               1619                 :                :          * tables, leading to potential deadlock against other sessions that
                               1620                 :                :          * will lock those objects in the other order.
                               1621                 :                :          */
  755 tgl@sss.pgh.pa.us        1622         [ +  + ]:           9309 :         if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
                               1623                 :             35 :             (void) find_all_inheritors(state.heapOid,
                               1624                 :                :                                        state.heap_lockmode,
                               1625                 :                :                                        NULL);
                               1626                 :                : 
                               1627                 :                :         /* OK, we're ready to delete this one */
 5783                          1628                 :           9309 :         obj.classId = RelationRelationId;
                               1629                 :           9309 :         obj.objectId = relOid;
                               1630                 :           9309 :         obj.objectSubId = 0;
                               1631                 :                : 
                               1632                 :           9309 :         add_exact_object_address(&obj, objects);
                               1633                 :                :     }
                               1634                 :                : 
 4391 simon@2ndQuadrant.co     1635                 :           7962 :     performMultipleDeletions(objects, drop->behavior, flags);
                               1636                 :                : 
 5783 tgl@sss.pgh.pa.us        1637                 :           7894 :     free_object_addresses(objects);
 8855 peter_e@gmx.net          1638                 :           7894 : }
                               1639                 :                : 
                               1640                 :                : /*
                               1641                 :                :  * Before acquiring a table lock, check whether we have sufficient rights.
                               1642                 :                :  * In the case of DROP INDEX, also try to lock the table before the index.
                               1643                 :                :  * Also, if the table to be dropped is a partition, we try to lock the parent
                               1644                 :                :  * first.
                               1645                 :                :  */
                               1646                 :                : static void
 4519 rhaas@postgresql.org     1647                 :          10039 : RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
                               1648                 :                :                                 void *arg)
                               1649                 :                : {
                               1650                 :                :     HeapTuple   tuple;
                               1651                 :                :     struct DropRelationCallbackState *state;
                               1652                 :                :     char        expected_relkind;
                               1653                 :                :     bool        is_partition;
                               1654                 :                :     Form_pg_class classform;
                               1655                 :                :     LOCKMODE    heap_lockmode;
 1843 peter@eisentraut.org     1656                 :          10039 :     bool        invalid_system_index = false;
                               1657                 :                : 
 4519 rhaas@postgresql.org     1658                 :          10039 :     state = (struct DropRelationCallbackState *) arg;
  755 tgl@sss.pgh.pa.us        1659                 :          10039 :     heap_lockmode = state->heap_lockmode;
                               1660                 :                : 
                               1661                 :                :     /*
                               1662                 :                :      * If we previously locked some other index's heap, and the name we're
                               1663                 :                :      * looking up no longer refers to that relation, release the now-useless
                               1664                 :                :      * lock.
                               1665                 :                :      */
 4519 rhaas@postgresql.org     1666   [ +  +  -  + ]:          10039 :     if (relOid != oldRelOid && OidIsValid(state->heapOid))
                               1667                 :                :     {
 4391 simon@2ndQuadrant.co     1668                 :UBC           0 :         UnlockRelationOid(state->heapOid, heap_lockmode);
 4519 rhaas@postgresql.org     1669                 :              0 :         state->heapOid = InvalidOid;
                               1670                 :                :     }
                               1671                 :                : 
                               1672                 :                :     /*
                               1673                 :                :      * Similarly, if we previously locked some other partition's heap, and the
                               1674                 :                :      * name we're looking up no longer refers to that relation, release the
                               1675                 :                :      * now-useless lock.
                               1676                 :                :      */
 2560 rhaas@postgresql.org     1677   [ +  +  -  + ]:CBC       10039 :     if (relOid != oldRelOid && OidIsValid(state->partParentOid))
                               1678                 :                :     {
 2560 rhaas@postgresql.org     1679                 :UBC           0 :         UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
                               1680                 :              0 :         state->partParentOid = InvalidOid;
                               1681                 :                :     }
                               1682                 :                : 
                               1683                 :                :     /* Didn't find a relation, so no need for locking or permission checks. */
 4519 rhaas@postgresql.org     1684         [ +  + ]:CBC       10039 :     if (!OidIsValid(relOid))
                               1685                 :            546 :         return;
                               1686                 :                : 
                               1687                 :           9493 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
                               1688         [ -  + ]:           9493 :     if (!HeapTupleIsValid(tuple))
 4519 rhaas@postgresql.org     1689                 :UBC           0 :         return;                 /* concurrently dropped, so nothing to do */
 4519 rhaas@postgresql.org     1690                 :CBC        9493 :     classform = (Form_pg_class) GETSTRUCT(tuple);
 2560                          1691                 :           9493 :     is_partition = classform->relispartition;
                               1692                 :                : 
                               1693                 :                :     /* Pass back some data to save lookups in RemoveRelations */
  755 tgl@sss.pgh.pa.us        1694                 :           9493 :     state->actual_relkind = classform->relkind;
                               1695                 :           9493 :     state->actual_relpersistence = classform->relpersistence;
                               1696                 :                : 
                               1697                 :                :     /*
                               1698                 :                :      * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
                               1699                 :                :      * but RemoveRelations() can only pass one relkind for a given relation.
                               1700                 :                :      * It chooses RELKIND_RELATION for both regular and partitioned tables.
                               1701                 :                :      * That means we must be careful before giving the wrong type error when
                               1702                 :                :      * the relation is RELKIND_PARTITIONED_TABLE.  An equivalent problem
                               1703                 :                :      * exists with indexes.
                               1704                 :                :      */
 2685 rhaas@postgresql.org     1705         [ +  + ]:           9493 :     if (classform->relkind == RELKIND_PARTITIONED_TABLE)
                               1706                 :           1484 :         expected_relkind = RELKIND_RELATION;
 2277 alvherre@alvh.no-ip.     1707         [ +  + ]:           8009 :     else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
                               1708                 :             41 :         expected_relkind = RELKIND_INDEX;
                               1709                 :                :     else
 2685 rhaas@postgresql.org     1710                 :           7968 :         expected_relkind = classform->relkind;
                               1711                 :                : 
  755 tgl@sss.pgh.pa.us        1712         [ -  + ]:           9493 :     if (state->expected_relkind != expected_relkind)
  755 tgl@sss.pgh.pa.us        1713                 :UBC           0 :         DropErrorMsgWrongType(rel->relname, classform->relkind,
                               1714                 :              0 :                               state->expected_relkind);
                               1715                 :                : 
                               1716                 :                :     /* Allow DROP to either table owner or schema owner */
  518 peter@eisentraut.org     1717         [ +  + ]:CBC        9493 :     if (!object_ownercheck(RelationRelationId, relOid, GetUserId()) &&
                               1718         [ +  - ]:              9 :         !object_ownercheck(NamespaceRelationId, classform->relnamespace, GetUserId()))
  755 tgl@sss.pgh.pa.us        1719                 :              9 :         aclcheck_error(ACLCHECK_NOT_OWNER,
                               1720                 :              9 :                        get_relkind_objtype(classform->relkind),
 4519 rhaas@postgresql.org     1721                 :              9 :                        rel->relname);
                               1722                 :                : 
                               1723                 :                :     /*
                               1724                 :                :      * Check the case of a system index that might have been invalidated by a
                               1725                 :                :      * failed concurrent process and allow its drop. For the time being, this
                               1726                 :                :      * only concerns indexes of toast relations that became invalid during a
                               1727                 :                :      * REINDEX CONCURRENTLY process.
                               1728                 :                :      */
  755 tgl@sss.pgh.pa.us        1729   [ +  +  -  + ]:           9484 :     if (IsSystemClass(relOid, classform) && classform->relkind == RELKIND_INDEX)
                               1730                 :                :     {
                               1731                 :                :         HeapTuple   locTuple;
                               1732                 :                :         Form_pg_index indexform;
                               1733                 :                :         bool        indisvalid;
                               1734                 :                : 
 1843 peter@eisentraut.org     1735                 :UBC           0 :         locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
                               1736         [ #  # ]:              0 :         if (!HeapTupleIsValid(locTuple))
                               1737                 :                :         {
                               1738                 :              0 :             ReleaseSysCache(tuple);
                               1739                 :              0 :             return;
                               1740                 :                :         }
                               1741                 :                : 
                               1742                 :              0 :         indexform = (Form_pg_index) GETSTRUCT(locTuple);
                               1743                 :              0 :         indisvalid = indexform->indisvalid;
                               1744                 :              0 :         ReleaseSysCache(locTuple);
                               1745                 :                : 
                               1746                 :                :         /* Mark object as being an invalid index of system catalogs */
                               1747         [ #  # ]:              0 :         if (!indisvalid)
                               1748                 :              0 :             invalid_system_index = true;
                               1749                 :                :     }
                               1750                 :                : 
                               1751                 :                :     /* In the case of an invalid index, it is fine to bypass this check */
 1843 peter@eisentraut.org     1752   [ +  -  +  +  :CBC        9484 :     if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
                                              +  + ]
 4519 rhaas@postgresql.org     1753         [ +  - ]:              1 :         ereport(ERROR,
                               1754                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                               1755                 :                :                  errmsg("permission denied: \"%s\" is a system catalog",
                               1756                 :                :                         rel->relname)));
                               1757                 :                : 
                               1758                 :           9483 :     ReleaseSysCache(tuple);
                               1759                 :                : 
                               1760                 :                :     /*
                               1761                 :                :      * In DROP INDEX, attempt to acquire lock on the parent table before
                               1762                 :                :      * locking the index.  index_drop() will need this anyway, and since
                               1763                 :                :      * regular queries lock tables before their indexes, we risk deadlock if
                               1764                 :                :      * we do it the other way around.  No error if we don't find a pg_index
                               1765                 :                :      * entry, though --- the relation may have been dropped.  Note that this
                               1766                 :                :      * code will execute for either plain or partitioned indexes.
                               1767                 :                :      */
  755 tgl@sss.pgh.pa.us        1768   [ +  +  +  + ]:           9483 :     if (expected_relkind == RELKIND_INDEX &&
                               1769                 :                :         relOid != oldRelOid)
                               1770                 :                :     {
 4519 rhaas@postgresql.org     1771                 :            387 :         state->heapOid = IndexGetRelation(relOid, true);
                               1772         [ +  - ]:            387 :         if (OidIsValid(state->heapOid))
 4391 simon@2ndQuadrant.co     1773                 :            387 :             LockRelationOid(state->heapOid, heap_lockmode);
                               1774                 :                :     }
                               1775                 :                : 
                               1776                 :                :     /*
                               1777                 :                :      * Similarly, if the relation is a partition, we must acquire lock on its
                               1778                 :                :      * parent before locking the partition.  That's because queries lock the
                               1779                 :                :      * parent before its partitions, so we risk deadlock if we do it the other
                               1780                 :                :      * way around.
                               1781                 :                :      */
 2560 rhaas@postgresql.org     1782   [ +  +  +  + ]:           9483 :     if (is_partition && relOid != oldRelOid)
                               1783                 :                :     {
 1116 alvherre@alvh.no-ip.     1784                 :            294 :         state->partParentOid = get_partition_parent(relOid, true);
 2560 rhaas@postgresql.org     1785         [ +  - ]:            294 :         if (OidIsValid(state->partParentOid))
                               1786                 :            294 :             LockRelationOid(state->partParentOid, AccessExclusiveLock);
                               1787                 :                :     }
                               1788                 :                : }
                               1789                 :                : 
                               1790                 :                : /*
                               1791                 :                :  * ExecuteTruncate
                               1792                 :                :  *      Executes a TRUNCATE command.
                               1793                 :                :  *
                               1794                 :                :  * This is a multi-relation truncate.  We first open and grab exclusive
                               1795                 :                :  * lock on all relations involved, checking permissions and otherwise
                               1796                 :                :  * verifying that the relation is OK for truncation.  Note that if relations
                               1797                 :                :  * are foreign tables, at this stage, we have not yet checked that their
                               1798                 :                :  * foreign data in external data sources are OK for truncation.  These are
                               1799                 :                :  * checked when foreign data are actually truncated later.  In CASCADE mode,
                               1800                 :                :  * relations having FK references to the targeted relations are automatically
                               1801                 :                :  * added to the group; in RESTRICT mode, we check that all FK references are
                               1802                 :                :  * internal to the group that's being truncated.  Finally all the relations
                               1803                 :                :  * are truncated and reindexed.
                               1804                 :                :  */
                               1805                 :                : void
 6617 tgl@sss.pgh.pa.us        1806                 :            696 : ExecuteTruncate(TruncateStmt *stmt)
                               1807                 :                : {
 6756 bruce@momjian.us         1808                 :            696 :     List       *rels = NIL;
 6617 tgl@sss.pgh.pa.us        1809                 :            696 :     List       *relids = NIL;
 2199 peter_e@gmx.net          1810                 :            696 :     List       *relids_logged = NIL;
                               1811                 :                :     ListCell   *cell;
                               1812                 :                : 
                               1813                 :                :     /*
                               1814                 :                :      * Open, exclusive-lock, and check all the explicitly-specified relations
                               1815                 :                :      */
 6617 tgl@sss.pgh.pa.us        1816   [ +  -  +  +  :           1505 :     foreach(cell, stmt->relations)
                                              +  + ]
                               1817                 :                :     {
 7017                          1818                 :            833 :         RangeVar   *rv = lfirst(cell);
                               1819                 :                :         Relation    rel;
 2669                          1820                 :            833 :         bool        recurse = rv->inh;
                               1821                 :                :         Oid         myrelid;
 1935 michael@paquier.xyz      1822                 :            833 :         LOCKMODE    lockmode = AccessExclusiveLock;
                               1823                 :                : 
                               1824                 :            833 :         myrelid = RangeVarGetRelidExtended(rv, lockmode,
                               1825                 :                :                                            0, RangeVarCallbackForTruncate,
                               1826                 :                :                                            NULL);
                               1827                 :                : 
                               1828                 :                :         /* don't throw error for "TRUNCATE foo, foo" */
 5571 peter_e@gmx.net          1829         [ +  + ]:            815 :         if (list_member_oid(relids, myrelid))
 5751 tgl@sss.pgh.pa.us        1830                 :              1 :             continue;
                               1831                 :                : 
                               1832                 :                :         /* open the relation, we already hold a lock on it */
 1098 fujii@postgresql.org     1833                 :            814 :         rel = table_open(myrelid, NoLock);
                               1834                 :                : 
                               1835                 :                :         /*
                               1836                 :                :          * RangeVarGetRelidExtended() has done most checks with its callback,
                               1837                 :                :          * but other checks with the now-opened Relation remain.
                               1838                 :                :          */
 2074 michael@paquier.xyz      1839                 :            814 :         truncate_check_activity(rel);
                               1840                 :                : 
 6617 tgl@sss.pgh.pa.us        1841                 :            814 :         rels = lappend(rels, rel);
 5571 peter_e@gmx.net          1842                 :            814 :         relids = lappend_oid(relids, myrelid);
                               1843                 :                : 
                               1844                 :                :         /* Log this relation only if needed for logical decoding */
 2199                          1845   [ +  +  +  -  :            814 :         if (RelationIsLogicallyLogged(rel))
                                     -  +  -  -  -  
                                        -  +  -  +  
                                                 + ]
                               1846                 :             32 :             relids_logged = lappend_oid(relids_logged, myrelid);
                               1847                 :                : 
 5571                          1848         [ +  + ]:            814 :         if (recurse)
                               1849                 :                :         {
                               1850                 :                :             ListCell   *child;
                               1851                 :                :             List       *children;
                               1852                 :                : 
 1935 michael@paquier.xyz      1853                 :            787 :             children = find_all_inheritors(myrelid, lockmode, NULL);
                               1854                 :                : 
 5571 peter_e@gmx.net          1855   [ +  -  +  +  :           2440 :             foreach(child, children)
                                              +  + ]
                               1856                 :                :             {
                               1857                 :           1653 :                 Oid         childrelid = lfirst_oid(child);
                               1858                 :                : 
                               1859         [ +  + ]:           1653 :                 if (list_member_oid(relids, childrelid))
                               1860                 :            787 :                     continue;
                               1861                 :                : 
                               1862                 :                :                 /* find_all_inheritors already got lock */
 1910 andres@anarazel.de       1863                 :            866 :                 rel = table_open(childrelid, NoLock);
                               1864                 :                : 
                               1865                 :                :                 /*
                               1866                 :                :                  * It is possible that the parent table has children that are
                               1867                 :                :                  * temp tables of other backends.  We cannot safely access
                               1868                 :                :                  * such tables (because of buffering issues), and the best
                               1869                 :                :                  * thing to do is to silently ignore them.  Note that this
                               1870                 :                :                  * check is the same as one of the checks done in
                               1871                 :                :                  * truncate_check_activity() called below, still it is kept
                               1872                 :                :                  * here for simplicity.
                               1873                 :                :                  */
 1935 michael@paquier.xyz      1874   [ +  +  +  + ]:            866 :                 if (RELATION_IS_OTHER_TEMP(rel))
                               1875                 :                :                 {
 1910 andres@anarazel.de       1876                 :              4 :                     table_close(rel, lockmode);
 1935 michael@paquier.xyz      1877                 :              4 :                     continue;
                               1878                 :                :                 }
                               1879                 :                : 
                               1880                 :                :                 /*
                               1881                 :                :                  * Inherited TRUNCATE commands perform access permission
                               1882                 :                :                  * checks on the parent table only. So we skip checking the
                               1883                 :                :                  * children's permissions and don't call
                               1884                 :                :                  * truncate_check_perms() here.
                               1885                 :                :                  */
 2074                          1886                 :            862 :                 truncate_check_rel(RelationGetRelid(rel), rel->rd_rel);
                               1887                 :            862 :                 truncate_check_activity(rel);
                               1888                 :                : 
 5571 peter_e@gmx.net          1889                 :            862 :                 rels = lappend(rels, rel);
                               1890                 :            862 :                 relids = lappend_oid(relids, childrelid);
                               1891                 :                : 
                               1892                 :                :                 /* Log this relation only if needed for logical decoding */
 2199                          1893   [ +  +  +  -  :            862 :                 if (RelationIsLogicallyLogged(rel))
                                     -  +  -  -  -  
                                        -  +  -  +  
                                                 - ]
                               1894                 :             11 :                     relids_logged = lappend_oid(relids_logged, childrelid);
                               1895                 :                :             }
                               1896                 :                :         }
 2685 rhaas@postgresql.org     1897         [ +  + ]:             27 :         else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               1898         [ +  - ]:              6 :             ereport(ERROR,
                               1899                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               1900                 :                :                      errmsg("cannot truncate only a partitioned table"),
                               1901                 :                :                      errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
                               1902                 :                :     }
                               1903                 :                : 
 1083 fujii@postgresql.org     1904                 :            672 :     ExecuteTruncateGuts(rels, relids, relids_logged,
  376 rhaas@postgresql.org     1905                 :            672 :                         stmt->behavior, stmt->restart_seqs, false);
                               1906                 :                : 
                               1907                 :                :     /* And close the rels */
 2199 peter_e@gmx.net          1908   [ +  -  +  +  :           2224 :     foreach(cell, rels)
                                              +  + ]
                               1909                 :                :     {
                               1910                 :           1593 :         Relation    rel = (Relation) lfirst(cell);
                               1911                 :                : 
 1910 andres@anarazel.de       1912                 :           1593 :         table_close(rel, NoLock);
                               1913                 :                :     }
 2199 peter_e@gmx.net          1914                 :            631 : }
                               1915                 :                : 
                               1916                 :                : /*
                               1917                 :                :  * ExecuteTruncateGuts
                               1918                 :                :  *
                               1919                 :                :  * Internal implementation of TRUNCATE.  This is called by the actual TRUNCATE
                               1920                 :                :  * command (see above) as well as replication subscribers that execute a
                               1921                 :                :  * replicated TRUNCATE action.
                               1922                 :                :  *
                               1923                 :                :  * explicit_rels is the list of Relations to truncate that the command
                               1924                 :                :  * specified.  relids is the list of Oids corresponding to explicit_rels.
                               1925                 :                :  * relids_logged is the list of Oids (a subset of relids) that require
                               1926                 :                :  * WAL-logging.  This is all a bit redundant, but the existing callers have
                               1927                 :                :  * this information handy in this form.
                               1928                 :                :  */
                               1929                 :                : void
 1102 fujii@postgresql.org     1930                 :            691 : ExecuteTruncateGuts(List *explicit_rels,
                               1931                 :                :                     List *relids,
                               1932                 :                :                     List *relids_logged,
                               1933                 :                :                     DropBehavior behavior, bool restart_seqs,
                               1934                 :                :                     bool run_as_table_owner)
                               1935                 :                : {
                               1936                 :                :     List       *rels;
 2199 peter_e@gmx.net          1937                 :            691 :     List       *seq_relids = NIL;
 1102 fujii@postgresql.org     1938                 :            691 :     HTAB       *ft_htab = NULL;
                               1939                 :                :     EState     *estate;
                               1940                 :                :     ResultRelInfo *resultRelInfos;
                               1941                 :                :     ResultRelInfo *resultRelInfo;
                               1942                 :                :     SubTransactionId mySubid;
                               1943                 :                :     ListCell   *cell;
                               1944                 :                :     Oid        *logrelids;
                               1945                 :                : 
                               1946                 :                :     /*
                               1947                 :                :      * Check the explicitly-specified relations.
                               1948                 :                :      *
                               1949                 :                :      * In CASCADE mode, suck in all referencing relations as well.  This
                               1950                 :                :      * requires multiple iterations to find indirectly-dependent relations. At
                               1951                 :                :      * each phase, we need to exclusive-lock new rels before looking for their
                               1952                 :                :      * dependencies, else we might miss something.  Also, we check each rel as
                               1953                 :                :      * soon as we open it, to avoid a faux pas such as holding lock for a long
                               1954                 :                :      * time on a rel we have no permissions for.
                               1955                 :                :      */
 2199 peter_e@gmx.net          1956                 :            691 :     rels = list_copy(explicit_rels);
                               1957         [ +  + ]:            691 :     if (behavior == DROP_CASCADE)
                               1958                 :                :     {
                               1959                 :                :         for (;;)
 6617 tgl@sss.pgh.pa.us        1960                 :             20 :         {
                               1961                 :                :             List       *newrelids;
                               1962                 :                : 
                               1963                 :             40 :             newrelids = heap_truncate_find_FKs(relids);
                               1964         [ +  + ]:             40 :             if (newrelids == NIL)
                               1965                 :             20 :                 break;          /* nothing else to add */
                               1966                 :                : 
                               1967   [ +  -  +  +  :             67 :             foreach(cell, newrelids)
                                              +  + ]
                               1968                 :                :             {
 6402 bruce@momjian.us         1969                 :             47 :                 Oid         relid = lfirst_oid(cell);
                               1970                 :                :                 Relation    rel;
                               1971                 :                : 
 1910 andres@anarazel.de       1972                 :             47 :                 rel = table_open(relid, AccessExclusiveLock);
 6617 tgl@sss.pgh.pa.us        1973         [ +  - ]:             47 :                 ereport(NOTICE,
                               1974                 :                :                         (errmsg("truncate cascades to table \"%s\"",
                               1975                 :                :                                 RelationGetRelationName(rel))));
 2074 michael@paquier.xyz      1976                 :             47 :                 truncate_check_rel(relid, rel->rd_rel);
 1535 fujii@postgresql.org     1977                 :             47 :                 truncate_check_perms(relid, rel->rd_rel);
 2074 michael@paquier.xyz      1978                 :             47 :                 truncate_check_activity(rel);
 6617 tgl@sss.pgh.pa.us        1979                 :             47 :                 rels = lappend(rels, rel);
                               1980                 :             47 :                 relids = lappend_oid(relids, relid);
                               1981                 :                : 
                               1982                 :                :                 /* Log this relation only if needed for logical decoding */
 2199 peter_e@gmx.net          1983   [ -  +  -  -  :             47 :                 if (RelationIsLogicallyLogged(rel))
                                     -  -  -  -  -  
                                        -  -  -  -  
                                                 - ]
 2199 peter_e@gmx.net          1984                 :UBC           0 :                     relids_logged = lappend_oid(relids_logged, relid);
                               1985                 :                :             }
                               1986                 :                :         }
                               1987                 :                :     }
                               1988                 :                : 
                               1989                 :                :     /*
                               1990                 :                :      * Check foreign key references.  In CASCADE mode, this should be
                               1991                 :                :      * unnecessary since we just pulled in all the references; but as a
                               1992                 :                :      * cross-check, do it anyway if in an Assert-enabled build.
                               1993                 :                :      */
                               1994                 :                : #ifdef USE_ASSERT_CHECKING
 7017 tgl@sss.pgh.pa.us        1995                 :CBC         691 :     heap_truncate_check_FKs(rels, false);
                               1996                 :                : #else
                               1997                 :                :     if (behavior == DROP_RESTRICT)
                               1998                 :                :         heap_truncate_check_FKs(rels, false);
                               1999                 :                : #endif
                               2000                 :                : 
                               2001                 :                :     /*
                               2002                 :                :      * If we are asked to restart sequences, find all the sequences, lock them
                               2003                 :                :      * (we need AccessExclusiveLock for ResetSequence), and check permissions.
                               2004                 :                :      * We want to do this early since it's pointless to do all the truncation
                               2005                 :                :      * work only to fail on sequence permissions.
                               2006                 :                :      */
 2199 peter_e@gmx.net          2007         [ +  + ]:            654 :     if (restart_seqs)
                               2008                 :                :     {
 5812 tgl@sss.pgh.pa.us        2009   [ +  -  +  +  :             26 :         foreach(cell, rels)
                                              +  + ]
                               2010                 :                :         {
                               2011                 :             13 :             Relation    rel = (Relation) lfirst(cell);
 1728 peter@eisentraut.org     2012                 :             13 :             List       *seqlist = getOwnedSequences(RelationGetRelid(rel));
                               2013                 :                :             ListCell   *seqcell;
                               2014                 :                : 
 5812 tgl@sss.pgh.pa.us        2015   [ +  +  +  +  :             31 :             foreach(seqcell, seqlist)
                                              +  + ]
                               2016                 :                :             {
 5421 bruce@momjian.us         2017                 :             18 :                 Oid         seq_relid = lfirst_oid(seqcell);
                               2018                 :                :                 Relation    seq_rel;
                               2019                 :                : 
 4897 tgl@sss.pgh.pa.us        2020                 :             18 :                 seq_rel = relation_open(seq_relid, AccessExclusiveLock);
                               2021                 :                : 
                               2022                 :                :                 /* This check must match AlterSequence! */
  518 peter@eisentraut.org     2023         [ -  + ]:             18 :                 if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
 2325 peter_e@gmx.net          2024                 :UBC           0 :                     aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SEQUENCE,
 5812 tgl@sss.pgh.pa.us        2025                 :              0 :                                    RelationGetRelationName(seq_rel));
                               2026                 :                : 
 5812 tgl@sss.pgh.pa.us        2027                 :CBC          18 :                 seq_relids = lappend_oid(seq_relids, seq_relid);
                               2028                 :                : 
                               2029                 :             18 :                 relation_close(seq_rel, NoLock);
                               2030                 :                :             }
                               2031                 :                :         }
                               2032                 :                :     }
                               2033                 :                : 
                               2034                 :                :     /* Prepare to catch AFTER triggers. */
 5861                          2035                 :            654 :     AfterTriggerBeginQuery();
                               2036                 :                : 
                               2037                 :                :     /*
                               2038                 :                :      * To fire triggers, we'll need an EState as well as a ResultRelInfo for
                               2039                 :                :      * each relation.  We don't need to call ExecOpenIndices, though.
                               2040                 :                :      *
                               2041                 :                :      * We put the ResultRelInfos in the es_opened_result_relations list, even
                               2042                 :                :      * though we don't have a range table and don't populate the
                               2043                 :                :      * es_result_relations array.  That's a bit bogus, but it's enough to make
                               2044                 :                :      * ExecGetTriggerResultRel() find them.
                               2045                 :                :      */
                               2046                 :            654 :     estate = CreateExecutorState();
                               2047                 :                :     resultRelInfos = (ResultRelInfo *)
                               2048                 :            654 :         palloc(list_length(rels) * sizeof(ResultRelInfo));
                               2049                 :            654 :     resultRelInfo = resultRelInfos;
                               2050   [ +  -  +  +  :           2333 :     foreach(cell, rels)
                                              +  + ]
                               2051                 :                :     {
                               2052                 :           1679 :         Relation    rel = (Relation) lfirst(cell);
                               2053                 :                : 
                               2054                 :           1679 :         InitResultRelInfo(resultRelInfo,
                               2055                 :                :                           rel,
                               2056                 :                :                           0,    /* dummy rangetable index */
                               2057                 :                :                           NULL,
                               2058                 :                :                           0);
 1279 heikki.linnakangas@i     2059                 :           1679 :         estate->es_opened_result_relations =
                               2060                 :           1679 :             lappend(estate->es_opened_result_relations, resultRelInfo);
 5861 tgl@sss.pgh.pa.us        2061                 :           1679 :         resultRelInfo++;
                               2062                 :                :     }
                               2063                 :                : 
                               2064                 :                :     /*
                               2065                 :                :      * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
                               2066                 :                :      * truncating (this is because one of them might throw an error). Also, if
                               2067                 :                :      * we were to allow them to prevent statement execution, that would need
                               2068                 :                :      * to be handled here.
                               2069                 :                :      */
                               2070                 :            654 :     resultRelInfo = resultRelInfos;
                               2071   [ +  -  +  +  :           2333 :     foreach(cell, rels)
                                              +  + ]
                               2072                 :                :     {
                               2073                 :                :         UserContext ucxt;
                               2074                 :                : 
  376 rhaas@postgresql.org     2075         [ +  + ]:           1679 :         if (run_as_table_owner)
                               2076                 :             35 :             SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
                               2077                 :                :                                   &ucxt);
 5861 tgl@sss.pgh.pa.us        2078                 :           1679 :         ExecBSTruncateTriggers(estate, resultRelInfo);
  376 rhaas@postgresql.org     2079         [ +  + ]:           1679 :         if (run_as_table_owner)
                               2080                 :             35 :             RestoreUserContext(&ucxt);
 5861 tgl@sss.pgh.pa.us        2081                 :           1679 :         resultRelInfo++;
                               2082                 :                :     }
                               2083                 :                : 
                               2084                 :                :     /*
                               2085                 :                :      * OK, truncate each table.
                               2086                 :                :      */
 5348                          2087                 :            654 :     mySubid = GetCurrentSubTransactionId();
                               2088                 :                : 
 1083 fujii@postgresql.org     2089   [ +  -  +  +  :           2333 :     foreach(cell, rels)
                                              +  + ]
                               2090                 :                :     {
                               2091                 :           1679 :         Relation    rel = (Relation) lfirst(cell);
                               2092                 :                : 
                               2093                 :                :         /* Skip partitioned tables as there is nothing to do */
 2600 rhaas@postgresql.org     2094         [ +  + ]:           1679 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               2095                 :            346 :             continue;
                               2096                 :                : 
                               2097                 :                :         /*
                               2098                 :                :          * Build the lists of foreign tables belonging to each foreign server
                               2099                 :                :          * and pass each list to the foreign data wrapper's callback function,
                               2100                 :                :          * so that each server can truncate its all foreign tables in bulk.
                               2101                 :                :          * Each list is saved as a single entry in a hash table that uses the
                               2102                 :                :          * server OID as lookup key.
                               2103                 :                :          */
 1102 fujii@postgresql.org     2104         [ +  + ]:           1333 :         if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
                               2105                 :             17 :         {
                               2106                 :             17 :             Oid         serverid = GetForeignServerIdByRelId(RelationGetRelid(rel));
                               2107                 :                :             bool        found;
                               2108                 :                :             ForeignTruncateInfo *ft_info;
                               2109                 :                : 
                               2110                 :                :             /* First time through, initialize hashtable for foreign tables */
                               2111         [ +  + ]:             17 :             if (!ft_htab)
                               2112                 :                :             {
                               2113                 :                :                 HASHCTL     hctl;
                               2114                 :                : 
                               2115                 :             15 :                 memset(&hctl, 0, sizeof(HASHCTL));
                               2116                 :             15 :                 hctl.keysize = sizeof(Oid);
                               2117                 :             15 :                 hctl.entrysize = sizeof(ForeignTruncateInfo);
                               2118                 :             15 :                 hctl.hcxt = CurrentMemoryContext;
                               2119                 :                : 
                               2120                 :             15 :                 ft_htab = hash_create("TRUNCATE for Foreign Tables",
                               2121                 :                :                                       32,   /* start small and extend */
                               2122                 :                :                                       &hctl,
                               2123                 :                :                                       HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
                               2124                 :                :             }
                               2125                 :                : 
                               2126                 :                :             /* Find or create cached entry for the foreign table */
                               2127                 :             17 :             ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
                               2128         [ +  + ]:             17 :             if (!found)
                               2129                 :             15 :                 ft_info->rels = NIL;
                               2130                 :                : 
                               2131                 :                :             /*
                               2132                 :                :              * Save the foreign table in the entry of the server that the
                               2133                 :                :              * foreign table belongs to.
                               2134                 :                :              */
                               2135                 :             17 :             ft_info->rels = lappend(ft_info->rels, rel);
                               2136                 :             17 :             continue;
                               2137                 :                :         }
                               2138                 :                : 
                               2139                 :                :         /*
                               2140                 :                :          * Normally, we need a transaction-safe truncation here.  However, if
                               2141                 :                :          * the table was either created in the current (sub)transaction or has
                               2142                 :                :          * a new relfilenumber in the current (sub)transaction, then we can
                               2143                 :                :          * just truncate it in-place, because a rollback would cause the whole
                               2144                 :                :          * table or the current physical file to be thrown away anyway.
                               2145                 :                :          */
 5348 tgl@sss.pgh.pa.us        2146         [ +  + ]:           1316 :         if (rel->rd_createSubid == mySubid ||
  648 rhaas@postgresql.org     2147         [ +  + ]:           1308 :             rel->rd_newRelfilelocatorSubid == mySubid)
                               2148                 :                :         {
                               2149                 :                :             /* Immediate, non-rollbackable truncation is OK */
 5348 tgl@sss.pgh.pa.us        2150                 :             24 :             heap_truncate_one_rel(rel);
                               2151                 :                :         }
                               2152                 :                :         else
                               2153                 :                :         {
                               2154                 :                :             Oid         heap_relid;
                               2155                 :                :             Oid         toast_relid;
 1182 michael@paquier.xyz      2156                 :           1292 :             ReindexParams reindex_params = {0};
                               2157                 :                : 
                               2158                 :                :             /*
                               2159                 :                :              * This effectively deletes all rows in the table, and may be done
                               2160                 :                :              * in a serializable transaction.  In that case we must record a
                               2161                 :                :              * rw-conflict in to this transaction from each transaction
                               2162                 :                :              * holding a predicate lock on the table.
                               2163                 :                :              */
 4694 heikki.linnakangas@i     2164                 :           1292 :             CheckTableForSerializableConflictIn(rel);
                               2165                 :                : 
                               2166                 :                :             /*
                               2167                 :                :              * Need the full transaction-safe pushups.
                               2168                 :                :              *
                               2169                 :                :              * Create a new empty storage file for the relation, and assign it
                               2170                 :                :              * as the relfilenumber value. The old storage file is scheduled
                               2171                 :                :              * for deletion at commit.
                               2172                 :                :              */
  648 rhaas@postgresql.org     2173                 :           1292 :             RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
                               2174                 :                : 
 5348 tgl@sss.pgh.pa.us        2175                 :           1292 :             heap_relid = RelationGetRelid(rel);
                               2176                 :                : 
                               2177                 :                :             /*
                               2178                 :                :              * The same for the toast table, if any.
                               2179                 :                :              */
 1955                          2180                 :           1292 :             toast_relid = rel->rd_rel->reltoastrelid;
 5348                          2181         [ +  + ]:           1292 :             if (OidIsValid(toast_relid))
                               2182                 :                :             {
 1955                          2183                 :            798 :                 Relation    toastrel = relation_open(toast_relid,
                               2184                 :                :                                                      AccessExclusiveLock);
                               2185                 :                : 
  648 rhaas@postgresql.org     2186                 :            798 :                 RelationSetNewRelfilenumber(toastrel,
                               2187                 :            798 :                                             toastrel->rd_rel->relpersistence);
 1910 andres@anarazel.de       2188                 :            798 :                 table_close(toastrel, NoLock);
                               2189                 :                :             }
                               2190                 :                : 
                               2191                 :                :             /*
                               2192                 :                :              * Reconstruct the indexes to match, and we're done.
                               2193                 :                :              */
  132 michael@paquier.xyz      2194                 :GNC        1292 :             reindex_relation(NULL, heap_relid, REINDEX_REL_PROCESS_TOAST,
                               2195                 :                :                              &reindex_params);
                               2196                 :                :         }
                               2197                 :                : 
 3341 alvherre@alvh.no-ip.     2198                 :CBC        1316 :         pgstat_count_truncate(rel);
                               2199                 :                :     }
                               2200                 :                : 
                               2201                 :                :     /* Now go through the hash table, and truncate foreign tables */
 1102 fujii@postgresql.org     2202         [ +  + ]:            654 :     if (ft_htab)
                               2203                 :                :     {
                               2204                 :                :         ForeignTruncateInfo *ft_info;
                               2205                 :                :         HASH_SEQ_STATUS seq;
                               2206                 :                : 
                               2207                 :             15 :         hash_seq_init(&seq, ft_htab);
                               2208                 :                : 
                               2209         [ +  + ]:             15 :         PG_TRY();
                               2210                 :                :         {
                               2211         [ +  + ]:             26 :             while ((ft_info = hash_seq_search(&seq)) != NULL)
                               2212                 :                :             {
                               2213                 :             15 :                 FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
                               2214                 :                : 
                               2215                 :                :                 /* truncate_check_rel() has checked that already */
                               2216         [ -  + ]:             15 :                 Assert(routine->ExecForeignTruncate != NULL);
                               2217                 :                : 
                               2218                 :             15 :                 routine->ExecForeignTruncate(ft_info->rels,
                               2219                 :                :                                              behavior,
                               2220                 :                :                                              restart_seqs);
                               2221                 :                :             }
                               2222                 :                :         }
                               2223                 :              4 :         PG_FINALLY();
                               2224                 :                :         {
                               2225                 :             15 :             hash_destroy(ft_htab);
                               2226                 :                :         }
                               2227         [ +  + ]:             15 :         PG_END_TRY();
                               2228                 :                :     }
                               2229                 :                : 
                               2230                 :                :     /*
                               2231                 :                :      * Restart owned sequences if we were asked to.
                               2232                 :                :      */
 4897 tgl@sss.pgh.pa.us        2233   [ +  +  +  +  :            668 :     foreach(cell, seq_relids)
                                              +  + ]
                               2234                 :                :     {
                               2235                 :             18 :         Oid         seq_relid = lfirst_oid(cell);
                               2236                 :                : 
                               2237                 :             18 :         ResetSequence(seq_relid);
                               2238                 :                :     }
                               2239                 :                : 
                               2240                 :                :     /*
                               2241                 :                :      * Write a WAL record to allow this set of actions to be logically
                               2242                 :                :      * decoded.
                               2243                 :                :      *
                               2244                 :                :      * Assemble an array of relids so we can write a single WAL record for the
                               2245                 :                :      * whole action.
                               2246                 :                :      */
  606                          2247         [ +  + ]:            650 :     if (relids_logged != NIL)
                               2248                 :                :     {
                               2249                 :                :         xl_heap_truncate xlrec;
 2199 peter_e@gmx.net          2250                 :             25 :         int         i = 0;
                               2251                 :                : 
                               2252                 :                :         /* should only get here if wal_level >= logical */
                               2253         [ -  + ]:             25 :         Assert(XLogLogicalInfoActive());
                               2254                 :                : 
                               2255                 :             25 :         logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
 2180 tgl@sss.pgh.pa.us        2256   [ +  -  +  +  :             68 :         foreach(cell, relids_logged)
                                              +  + ]
 2199 peter_e@gmx.net          2257                 :             43 :             logrelids[i++] = lfirst_oid(cell);
                               2258                 :                : 
                               2259                 :             25 :         xlrec.dbId = MyDatabaseId;
                               2260                 :             25 :         xlrec.nrelids = list_length(relids_logged);
                               2261                 :             25 :         xlrec.flags = 0;
                               2262         [ +  + ]:             25 :         if (behavior == DROP_CASCADE)
                               2263                 :              1 :             xlrec.flags |= XLH_TRUNCATE_CASCADE;
                               2264         [ +  + ]:             25 :         if (restart_seqs)
                               2265                 :              2 :             xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
                               2266                 :                : 
                               2267                 :             25 :         XLogBeginInsert();
                               2268                 :             25 :         XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
                               2269                 :             25 :         XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
                               2270                 :                : 
                               2271                 :             25 :         XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
                               2272                 :                : 
                               2273                 :             25 :         (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
                               2274                 :                :     }
                               2275                 :                : 
                               2276                 :                :     /*
                               2277                 :                :      * Process all AFTER STATEMENT TRUNCATE triggers.
                               2278                 :                :      */
 5861 tgl@sss.pgh.pa.us        2279                 :            650 :     resultRelInfo = resultRelInfos;
                               2280   [ +  -  +  +  :           2325 :     foreach(cell, rels)
                                              +  + ]
                               2281                 :                :     {
                               2282                 :                :         UserContext ucxt;
                               2283                 :                : 
  376 rhaas@postgresql.org     2284         [ +  + ]:           1675 :         if (run_as_table_owner)
                               2285                 :             35 :             SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
                               2286                 :                :                                   &ucxt);
 5861 tgl@sss.pgh.pa.us        2287                 :           1675 :         ExecASTruncateTriggers(estate, resultRelInfo);
  376 rhaas@postgresql.org     2288         [ +  + ]:           1675 :         if (run_as_table_owner)
                               2289                 :             35 :             RestoreUserContext(&ucxt);
 5861 tgl@sss.pgh.pa.us        2290                 :           1675 :         resultRelInfo++;
                               2291                 :                :     }
                               2292                 :                : 
                               2293                 :                :     /* Handle queued AFTER triggers */
                               2294                 :            650 :     AfterTriggerEndQuery(estate);
                               2295                 :                : 
                               2296                 :                :     /* We can clean up the EState now */
                               2297                 :            650 :     FreeExecutorState(estate);
                               2298                 :                : 
                               2299                 :                :     /*
                               2300                 :                :      * Close any rels opened by CASCADE (can't do this while EState still
                               2301                 :                :      * holds refs)
                               2302                 :                :      */
 2199 peter_e@gmx.net          2303                 :            650 :     rels = list_difference_ptr(rels, explicit_rels);
 5858 tgl@sss.pgh.pa.us        2304   [ +  +  +  +  :            697 :     foreach(cell, rels)
                                              +  + ]
                               2305                 :                :     {
                               2306                 :             47 :         Relation    rel = (Relation) lfirst(cell);
                               2307                 :                : 
 1910 andres@anarazel.de       2308                 :             47 :         table_close(rel, NoLock);
                               2309                 :                :     }
 8024 tgl@sss.pgh.pa.us        2310                 :            650 : }
                               2311                 :                : 
                               2312                 :                : /*
                               2313                 :                :  * Check that a given relation is safe to truncate.  Subroutine for
                               2314                 :                :  * ExecuteTruncate() and RangeVarCallbackForTruncate().
                               2315                 :                :  */
                               2316                 :                : static void
 2074 michael@paquier.xyz      2317                 :           1826 : truncate_check_rel(Oid relid, Form_pg_class reltuple)
                               2318                 :                : {
                               2319                 :           1826 :     char       *relname = NameStr(reltuple->relname);
                               2320                 :                : 
                               2321                 :                :     /*
                               2322                 :                :      * Only allow truncate on regular tables, foreign tables using foreign
                               2323                 :                :      * data wrappers supporting TRUNCATE and partitioned tables (although, the
                               2324                 :                :      * latter are only being included here for the following checks; no
                               2325                 :                :      * physical truncation will occur in their case.).
                               2326                 :                :      */
 1102 fujii@postgresql.org     2327         [ +  + ]:           1826 :     if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
                               2328                 :                :     {
                               2329                 :             18 :         Oid         serverid = GetForeignServerIdByRelId(relid);
                               2330                 :             18 :         FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
                               2331                 :                : 
                               2332         [ +  + ]:             18 :         if (!fdwroutine->ExecForeignTruncate)
                               2333         [ +  - ]:              1 :             ereport(ERROR,
                               2334                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2335                 :                :                      errmsg("cannot truncate foreign table \"%s\"",
                               2336                 :                :                             relname)));
                               2337                 :                :     }
                               2338         [ +  + ]:           1808 :     else if (reltuple->relkind != RELKIND_RELATION &&
                               2339         [ -  + ]:            355 :              reltuple->relkind != RELKIND_PARTITIONED_TABLE)
 6617 tgl@sss.pgh.pa.us        2340         [ #  # ]:UBC           0 :         ereport(ERROR,
                               2341                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2342                 :                :                  errmsg("\"%s\" is not a table", relname)));
                               2343                 :                : 
                               2344                 :                :     /*
                               2345                 :                :      * Most system catalogs can't be truncated at all, or at least not unless
                               2346                 :                :      * allow_system_table_mods=on. As an exception, however, we allow
                               2347                 :                :      * pg_largeobject to be truncated as part of pg_upgrade, because we need
                               2348                 :                :      * to change its relfilenode to match the old cluster, and allowing a
                               2349                 :                :      * TRUNCATE command to be executed is the easiest way of doing that.
                               2350                 :                :      */
  626 rhaas@postgresql.org     2351   [ +  +  +  + ]:CBC        1825 :     if (!allowSystemTableMods && IsSystemClass(relid, reltuple)
                               2352   [ +  +  -  + ]:             11 :         && (!IsBinaryUpgrade || relid != LargeObjectRelationId))
 6617 tgl@sss.pgh.pa.us        2353         [ +  - ]:              1 :         ereport(ERROR,
                               2354                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                               2355                 :                :                  errmsg("permission denied: \"%s\" is a system catalog",
                               2356                 :                :                         relname)));
                               2357                 :                : 
 1604 mail@joeconway.com       2358         [ -  + ]:           1824 :     InvokeObjectTruncateHook(relid);
 2074 michael@paquier.xyz      2359                 :           1824 : }
                               2360                 :                : 
                               2361                 :                : /*
                               2362                 :                :  * Check that current user has the permission to truncate given relation.
                               2363                 :                :  */
                               2364                 :                : static void
 1535 fujii@postgresql.org     2365                 :            962 : truncate_check_perms(Oid relid, Form_pg_class reltuple)
                               2366                 :                : {
                               2367                 :            962 :     char       *relname = NameStr(reltuple->relname);
                               2368                 :                :     AclResult   aclresult;
                               2369                 :                : 
                               2370                 :                :     /* Permissions checks */
                               2371                 :            962 :     aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
                               2372         [ +  + ]:            962 :     if (aclresult != ACLCHECK_OK)
                               2373                 :             16 :         aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
                               2374                 :                :                        relname);
                               2375                 :            946 : }
                               2376                 :                : 
                               2377                 :                : /*
                               2378                 :                :  * Set of extra sanity checks to check if a given relation is safe to
                               2379                 :                :  * truncate.  This is split with truncate_check_rel() as
                               2380                 :                :  * RangeVarCallbackForTruncate() cannot open a Relation yet.
                               2381                 :                :  */
                               2382                 :                : static void
 2074 michael@paquier.xyz      2383                 :           1723 : truncate_check_activity(Relation rel)
                               2384                 :                : {
                               2385                 :                :     /*
                               2386                 :                :      * Don't allow truncate on temp tables of other backends ... their local
                               2387                 :                :      * buffer manager is not going to cope.
                               2388                 :                :      */
 5493 tgl@sss.pgh.pa.us        2389   [ +  +  -  + ]:           1723 :     if (RELATION_IS_OTHER_TEMP(rel))
 6617 tgl@sss.pgh.pa.us        2390         [ #  # ]:UBC           0 :         ereport(ERROR,
                               2391                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2392                 :                :                  errmsg("cannot truncate temporary tables of other sessions")));
                               2393                 :                : 
                               2394                 :                :     /*
                               2395                 :                :      * Also check for active uses of the relation in the current transaction,
                               2396                 :                :      * including open scans and pending AFTER trigger events.
                               2397                 :                :      */
 5919 tgl@sss.pgh.pa.us        2398                 :CBC        1723 :     CheckTableNotInUse(rel, "TRUNCATE");
 6617                          2399                 :           1723 : }
                               2400                 :                : 
                               2401                 :                : /*
                               2402                 :                :  * storage_name
                               2403                 :                :  *    returns the name corresponding to a typstorage/attstorage enum value
                               2404                 :                :  */
                               2405                 :                : static const char *
   54 peter@eisentraut.org     2406                 :             12 : storage_name(char c)
                               2407                 :                : {
                               2408   [ -  -  +  +  :             12 :     switch (c)
                                                 - ]
                               2409                 :                :     {
   54 peter@eisentraut.org     2410                 :UBC           0 :         case TYPSTORAGE_PLAIN:
                               2411                 :              0 :             return "PLAIN";
                               2412                 :              0 :         case TYPSTORAGE_EXTERNAL:
                               2413                 :              0 :             return "EXTERNAL";
   54 peter@eisentraut.org     2414                 :CBC           6 :         case TYPSTORAGE_EXTENDED:
                               2415                 :              6 :             return "EXTENDED";
                               2416                 :              6 :         case TYPSTORAGE_MAIN:
                               2417                 :              6 :             return "MAIN";
   54 peter@eisentraut.org     2418                 :UBC           0 :         default:
                               2419                 :              0 :             return "???";
                               2420                 :                :     }
                               2421                 :                : }
                               2422                 :                : 
                               2423                 :                : /*----------
                               2424                 :                :  * MergeAttributes
                               2425                 :                :  *      Returns new schema given initial schema and superclasses.
                               2426                 :                :  *
                               2427                 :                :  * Input arguments:
                               2428                 :                :  * 'columns' is the column/attribute definition for the table. (It's a list
                               2429                 :                :  *      of ColumnDef's.) It is destructively changed.
                               2430                 :                :  * 'supers' is a list of OIDs of parent relations, already locked by caller.
                               2431                 :                :  * 'relpersistence' is the persistence type of the table.
                               2432                 :                :  * 'is_partition' tells if the table is a partition.
                               2433                 :                :  *
                               2434                 :                :  * Output arguments:
                               2435                 :                :  * 'supconstr' receives a list of constraints belonging to the parents,
                               2436                 :                :  *      updated as necessary to be valid for the child.
                               2437                 :                :  * 'supnotnulls' receives a list of CookedConstraints that corresponds to
                               2438                 :                :  *      constraints coming from inheritance parents.
                               2439                 :                :  *
                               2440                 :                :  * Return value:
                               2441                 :                :  * Completed schema list.
                               2442                 :                :  *
                               2443                 :                :  * Notes:
                               2444                 :                :  *    The order in which the attributes are inherited is very important.
                               2445                 :                :  *    Intuitively, the inherited attributes should come first. If a table
                               2446                 :                :  *    inherits from multiple parents, the order of those attributes are
                               2447                 :                :  *    according to the order of the parents specified in CREATE TABLE.
                               2448                 :                :  *
                               2449                 :                :  *    Here's an example:
                               2450                 :                :  *
                               2451                 :                :  *      create table person (name text, age int4, location point);
                               2452                 :                :  *      create table emp (salary int4, manager text) inherits(person);
                               2453                 :                :  *      create table student (gpa float8) inherits (person);
                               2454                 :                :  *      create table stud_emp (percent int4) inherits (emp, student);
                               2455                 :                :  *
                               2456                 :                :  *    The order of the attributes of stud_emp is:
                               2457                 :                :  *
                               2458                 :                :  *                          person {1:name, 2:age, 3:location}
                               2459                 :                :  *                          /    \
                               2460                 :                :  *             {6:gpa}  student   emp {4:salary, 5:manager}
                               2461                 :                :  *                          \    /
                               2462                 :                :  *                         stud_emp {7:percent}
                               2463                 :                :  *
                               2464                 :                :  *     If the same attribute name appears multiple times, then it appears
                               2465                 :                :  *     in the result table in the proper location for its first appearance.
                               2466                 :                :  *
                               2467                 :                :  *     Constraints (including not-null constraints) for the child table
                               2468                 :                :  *     are the union of all relevant constraints, from both the child schema
                               2469                 :                :  *     and parent tables.  In addition, in legacy inheritance, each column that
                               2470                 :                :  *     appears in a primary key in any of the parents also gets a NOT NULL
                               2471                 :                :  *     constraint (partitioning doesn't need this, because the PK itself gets
                               2472                 :                :  *     inherited.)
                               2473                 :                :  *
                               2474                 :                :  *     The default value for a child column is defined as:
                               2475                 :                :  *      (1) If the child schema specifies a default, that value is used.
                               2476                 :                :  *      (2) If neither the child nor any parent specifies a default, then
                               2477                 :                :  *          the column will not have a default.
                               2478                 :                :  *      (3) If conflicting defaults are inherited from different parents
                               2479                 :                :  *          (and not overridden by the child), an error is raised.
                               2480                 :                :  *      (4) Otherwise the inherited default is used.
                               2481                 :                :  *
                               2482                 :                :  *      Note that the default-value infrastructure is used for generated
                               2483                 :                :  *      columns' expressions too, so most of the preceding paragraph applies
                               2484                 :                :  *      to generation expressions too.  We insist that a child column be
                               2485                 :                :  *      generated if and only if its parent(s) are, but it need not have
                               2486                 :                :  *      the same generation expression.
                               2487                 :                :  *----------
                               2488                 :                :  */
                               2489                 :                : static List *
  201 peter@eisentraut.org     2490                 :GNC       26265 : MergeAttributes(List *columns, const List *supers, char relpersistence,
                               2491                 :                :                 bool is_partition, List **supconstr, List **supnotnulls)
                               2492                 :                : {
                               2493                 :          26265 :     List       *inh_columns = NIL;
 8024 tgl@sss.pgh.pa.us        2494                 :CBC       26265 :     List       *constraints = NIL;
  233 alvherre@alvh.no-ip.     2495                 :GNC       26265 :     List       *nnconstraints = NIL;
   54 peter@eisentraut.org     2496                 :CBC       26265 :     bool        have_bogus_defaults = false;
                               2497                 :                :     int         child_attno;
                               2498                 :                :     static Node bogus_marker = {0}; /* marks conflicting defaults */
  201 peter@eisentraut.org     2499                 :GNC       26265 :     List       *saved_columns = NIL;
                               2500                 :                :     ListCell   *lc;
                               2501                 :                : 
                               2502                 :                :     /*
                               2503                 :                :      * Check for and reject tables with too many columns. We perform this
                               2504                 :                :      * check relatively early for two reasons: (a) we don't run the risk of
                               2505                 :                :      * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
                               2506                 :                :      * okay if we're processing <= 1600 columns, but could take minutes to
                               2507                 :                :      * execute if the user attempts to create a table with hundreds of
                               2508                 :                :      * thousands of columns.
                               2509                 :                :      *
                               2510                 :                :      * Note that we also need to check that we do not exceed this figure after
                               2511                 :                :      * including columns from inherited relations.
                               2512                 :                :      */
                               2513         [ -  + ]:          26265 :     if (list_length(columns) > MaxHeapAttributeNumber)
 7089 neilc@samurai.com        2514         [ #  # ]:UBC           0 :         ereport(ERROR,
                               2515                 :                :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
                               2516                 :                :                  errmsg("tables can have at most %d columns",
                               2517                 :                :                         MaxHeapAttributeNumber)));
                               2518                 :                : 
                               2519                 :                :     /*
                               2520                 :                :      * Check for duplicate names in the explicit list of attributes.
                               2521                 :                :      *
                               2522                 :                :      * Although we might consider merging such entries in the same way that we
                               2523                 :                :      * handle name conflicts for inherited attributes, it seems to make more
                               2524                 :                :      * sense to assume such conflicts are errors.
                               2525                 :                :      *
                               2526                 :                :      * We don't use foreach() here because we have two nested loops over the
                               2527                 :                :      * columns list, with possible element deletions in the inner one.  If we
                               2528                 :                :      * used foreach_delete_current() it could only fix up the state of one of
                               2529                 :                :      * the loops, so it seems cleaner to use looping over list indexes for
                               2530                 :                :      * both loops.  Note that any deletion will happen beyond where the outer
                               2531                 :                :      * loop is, so its index never needs adjustment.
                               2532                 :                :      */
  201 peter@eisentraut.org     2533         [ +  + ]:GNC      121576 :     for (int coldefpos = 0; coldefpos < list_length(columns); coldefpos++)
                               2534                 :                :     {
                               2535                 :          95323 :         ColumnDef  *coldef = list_nth_node(ColumnDef, columns, coldefpos);
                               2536                 :                : 
 1984 alvherre@alvh.no-ip.     2537   [ +  +  +  + ]:CBC       95323 :         if (!is_partition && coldef->typeName == NULL)
                               2538                 :                :         {
                               2539                 :                :             /*
                               2540                 :                :              * Typed table column option that does not belong to a column from
                               2541                 :                :              * the type.  This works because the columns from the type come
                               2542                 :                :              * first in the list.  (We omit this check for partition column
                               2543                 :                :              * lists; those are processed separately below.)
                               2544                 :                :              */
 5190 peter_e@gmx.net          2545         [ +  - ]:              3 :             ereport(ERROR,
                               2546                 :                :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               2547                 :                :                      errmsg("column \"%s\" does not exist",
                               2548                 :                :                             coldef->colname)));
                               2549                 :                :         }
                               2550                 :                : 
                               2551                 :                :         /* restpos scans all entries beyond coldef; incr is in loop body */
  201 peter@eisentraut.org     2552         [ +  + ]:GNC     3065783 :         for (int restpos = coldefpos + 1; restpos < list_length(columns);)
                               2553                 :                :         {
                               2554                 :        2970472 :             ColumnDef  *restdef = list_nth_node(ColumnDef, columns, restpos);
                               2555                 :                : 
 8024 tgl@sss.pgh.pa.us        2556         [ +  + ]:CBC     2970472 :             if (strcmp(coldef->colname, restdef->colname) == 0)
                               2557                 :                :             {
 5190 peter_e@gmx.net          2558         [ +  + ]:             25 :                 if (coldef->is_from_type)
                               2559                 :                :                 {
                               2560                 :                :                     /*
                               2561                 :                :                      * merge the column options into the column from the type
                               2562                 :                :                      */
                               2563                 :             16 :                     coldef->is_not_null = restdef->is_not_null;
                               2564                 :             16 :                     coldef->raw_default = restdef->raw_default;
                               2565                 :             16 :                     coldef->cooked_default = restdef->cooked_default;
                               2566                 :             16 :                     coldef->constraints = restdef->constraints;
                               2567                 :             16 :                     coldef->is_from_type = false;
  201 peter@eisentraut.org     2568                 :GNC          16 :                     columns = list_delete_nth_cell(columns, restpos);
                               2569                 :                :                 }
                               2570                 :                :                 else
 5190 peter_e@gmx.net          2571         [ +  - ]:CBC           9 :                     ereport(ERROR,
                               2572                 :                :                             (errcode(ERRCODE_DUPLICATE_COLUMN),
                               2573                 :                :                              errmsg("column \"%s\" specified more than once",
                               2574                 :                :                                     coldef->colname)));
                               2575                 :                :             }
                               2576                 :                :             else
 1735 tgl@sss.pgh.pa.us        2577                 :        2970447 :                 restpos++;
                               2578                 :                :         }
                               2579                 :                :     }
                               2580                 :                : 
                               2581                 :                :     /*
                               2582                 :                :      * In case of a partition, there are no new column definitions, only dummy
                               2583                 :                :      * ColumnDefs created for column constraints.  Set them aside for now and
                               2584                 :                :      * process them at the end.
                               2585                 :                :      */
 1984 alvherre@alvh.no-ip.     2586         [ +  + ]:          26253 :     if (is_partition)
                               2587                 :                :     {
  201 peter@eisentraut.org     2588                 :GNC        4125 :         saved_columns = columns;
                               2589                 :           4125 :         columns = NIL;
                               2590                 :                :     }
                               2591                 :                : 
                               2592                 :                :     /*
                               2593                 :                :      * Scan the parents left-to-right, and merge their attributes to form a
                               2594                 :                :      * list of inherited columns (inh_columns).
                               2595                 :                :      */
 8024 tgl@sss.pgh.pa.us        2596                 :CBC       26253 :     child_attno = 0;
  201 peter@eisentraut.org     2597   [ +  +  +  +  :GNC       31369 :     foreach(lc, supers)
                                              +  + ]
                               2598                 :                :     {
                               2599                 :           5152 :         Oid         parent = lfirst_oid(lc);
                               2600                 :                :         Relation    relation;
                               2601                 :                :         TupleDesc   tupleDesc;
                               2602                 :                :         TupleConstr *constr;
                               2603                 :                :         AttrMap    *newattmap;
                               2604                 :                :         List       *inherited_defaults;
                               2605                 :                :         List       *cols_with_defaults;
                               2606                 :                :         List       *nnconstrs;
                               2607                 :                :         ListCell   *lc1;
                               2608                 :                :         ListCell   *lc2;
                               2609                 :                :         Bitmapset  *pkattrs;
  233 alvherre@alvh.no-ip.     2610                 :           5152 :         Bitmapset  *nncols = NULL;
                               2611                 :                : 
                               2612                 :                :         /* caller already got lock */
 1910 andres@anarazel.de       2613                 :CBC        5152 :         relation = table_open(parent, NoLock);
                               2614                 :                : 
                               2615                 :                :         /*
                               2616                 :                :          * Check for active uses of the parent partitioned table in the
                               2617                 :                :          * current transaction, such as being used in some manner by an
                               2618                 :                :          * enclosing command.
                               2619                 :                :          */
 1987 michael@paquier.xyz      2620         [ +  + ]:           5152 :         if (is_partition)
                               2621                 :           4125 :             CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
                               2622                 :                : 
                               2623                 :                :         /*
                               2624                 :                :          * We do not allow partitioned tables and partitions to participate in
                               2625                 :                :          * regular inheritance.
                               2626                 :                :          */
  201 peter@eisentraut.org     2627   [ +  +  +  + ]:GNC        5149 :         if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !is_partition)
 2685 rhaas@postgresql.org     2628         [ +  - ]:CBC           3 :             ereport(ERROR,
                               2629                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2630                 :                :                      errmsg("cannot inherit from partitioned table \"%s\"",
                               2631                 :                :                             RelationGetRelationName(relation))));
                               2632   [ +  +  +  + ]:           5146 :         if (relation->rd_rel->relispartition && !is_partition)
                               2633         [ +  - ]:              3 :             ereport(ERROR,
                               2634                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2635                 :                :                      errmsg("cannot inherit from partition \"%s\"",
                               2636                 :                :                             RelationGetRelationName(relation))));
                               2637                 :                : 
 3311 tgl@sss.pgh.pa.us        2638         [ +  + ]:           5143 :         if (relation->rd_rel->relkind != RELKIND_RELATION &&
 2685 rhaas@postgresql.org     2639         [ +  + ]:           4123 :             relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
                               2640         [ -  + ]:           4113 :             relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 7574 tgl@sss.pgh.pa.us        2641         [ #  # ]:UBC           0 :             ereport(ERROR,
                               2642                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2643                 :                :                      errmsg("inherited relation \"%s\" is not a table or foreign table",
                               2644                 :                :                             RelationGetRelationName(relation))));
                               2645                 :                : 
                               2646                 :                :         /*
                               2647                 :                :          * If the parent is permanent, so must be all of its partitions.  Note
                               2648                 :                :          * that inheritance allows that case.
                               2649                 :                :          */
 2125 michael@paquier.xyz      2650         [ +  + ]:CBC        5143 :         if (is_partition &&
                               2651   [ +  +  +  + ]:           4122 :             relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
                               2652                 :                :             relpersistence == RELPERSISTENCE_TEMP)
                               2653         [ +  - ]:              3 :             ereport(ERROR,
                               2654                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2655                 :                :                      errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
                               2656                 :                :                             RelationGetRelationName(relation))));
                               2657                 :                : 
                               2658                 :                :         /* Permanent rels cannot inherit from temporary ones */
 4136 tgl@sss.pgh.pa.us        2659         [ +  + ]:           5140 :         if (relpersistence != RELPERSISTENCE_TEMP &&
                               2660         [ +  + ]:           4969 :             relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
 7574                          2661   [ +  -  +  + ]:             12 :             ereport(ERROR,
                               2662                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2663                 :                :                      errmsg(!is_partition
                               2664                 :                :                             ? "cannot inherit from temporary relation \"%s\""
                               2665                 :                :                             : "cannot create a permanent relation as partition of temporary relation \"%s\"",
                               2666                 :                :                             RelationGetRelationName(relation))));
                               2667                 :                : 
                               2668                 :                :         /* If existing rel is temp, it must belong to this session */
 4136                          2669         [ +  + ]:           5128 :         if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                               2670         [ -  + ]:            147 :             !relation->rd_islocaltemp)
 4136 tgl@sss.pgh.pa.us        2671   [ #  #  #  # ]:UBC           0 :             ereport(ERROR,
                               2672                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               2673                 :                :                      errmsg(!is_partition
                               2674                 :                :                             ? "cannot inherit from temporary relation of another session"
                               2675                 :                :                             : "cannot create as partition of temporary relation of another session")));
                               2676                 :                : 
                               2677                 :                :         /*
                               2678                 :                :          * We should have an UNDER permission flag for this, but for now,
                               2679                 :                :          * demand that creator of a child table own the parent.
                               2680                 :                :          */
  518 peter@eisentraut.org     2681         [ -  + ]:CBC        5128 :         if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), GetUserId()))
 2325 peter_e@gmx.net          2682                 :UBC           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(relation->rd_rel->relkind),
 8023 tgl@sss.pgh.pa.us        2683                 :              0 :                            RelationGetRelationName(relation));
                               2684                 :                : 
 8024 tgl@sss.pgh.pa.us        2685                 :CBC        5128 :         tupleDesc = RelationGetDescr(relation);
                               2686                 :           5128 :         constr = tupleDesc->constr;
                               2687                 :                : 
                               2688                 :                :         /*
                               2689                 :                :          * newattmap->attnums[] will contain the child-table attribute numbers
                               2690                 :                :          * for the attributes of this parent table.  (They are not the same
                               2691                 :                :          * for parents after the first one, nor if we have dropped columns.)
                               2692                 :                :          */
 1579 michael@paquier.xyz      2693                 :           5128 :         newattmap = make_attrmap(tupleDesc->natts);
                               2694                 :                : 
                               2695                 :                :         /* We can't process inherited defaults until newattmap is complete. */
 1332 tgl@sss.pgh.pa.us        2696                 :           5128 :         inherited_defaults = cols_with_defaults = NIL;
                               2697                 :                : 
                               2698                 :                :         /*
                               2699                 :                :          * All columns that are part of the parent's primary key need to be
                               2700                 :                :          * NOT NULL; if partition just the attnotnull bit, otherwise a full
                               2701                 :                :          * constraint (if they don't have one already).  Also, we request
                               2702                 :                :          * attnotnull on columns that have a not-null constraint that's not
                               2703                 :                :          * marked NO INHERIT.
                               2704                 :                :          */
  233 alvherre@alvh.no-ip.     2705                 :GNC        5128 :         pkattrs = RelationGetIndexAttrBitmap(relation,
                               2706                 :                :                                              INDEX_ATTR_BITMAP_PRIMARY_KEY);
                               2707                 :           5128 :         nnconstrs = RelationGetNotNullConstraints(RelationGetRelid(relation), true);
                               2708   [ +  +  +  +  :           5552 :         foreach(lc1, nnconstrs)
                                              +  + ]
                               2709                 :            424 :             nncols = bms_add_member(nncols,
                               2710                 :            424 :                                     ((CookedConstraint *) lfirst(lc1))->attnum);
                               2711                 :                : 
  201 peter@eisentraut.org     2712         [ +  + ]:          16026 :         for (AttrNumber parent_attno = 1; parent_attno <= tupleDesc->natts;
 8024 tgl@sss.pgh.pa.us        2713                 :CBC       10898 :              parent_attno++)
                               2714                 :                :         {
 2429 andres@anarazel.de       2715                 :          10910 :             Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
                               2716                 :                :                                                         parent_attno - 1);
 8024 tgl@sss.pgh.pa.us        2717                 :          10910 :             char       *attributeName = NameStr(attribute->attname);
                               2718                 :                :             int         exist_attno;
                               2719                 :                :             ColumnDef  *newdef;
                               2720                 :                :             ColumnDef  *mergeddef;
                               2721                 :                : 
                               2722                 :                :             /*
                               2723                 :                :              * Ignore dropped columns in the parent.
                               2724                 :                :              */
 7926                          2725         [ +  + ]:          10910 :             if (attribute->attisdropped)
 1579 michael@paquier.xyz      2726                 :             96 :                 continue;       /* leave newattmap->attnums entry as zero */
                               2727                 :                : 
                               2728                 :                :             /*
                               2729                 :                :              * Create new column definition
                               2730                 :                :              */
   80 peter@eisentraut.org     2731                 :GNC       10814 :             newdef = makeColumnDef(attributeName, attribute->atttypid,
                               2732                 :                :                                    attribute->atttypmod, attribute->attcollation);
   54                          2733                 :          10814 :             newdef->storage = attribute->attstorage;
   80                          2734                 :          10814 :             newdef->generated = attribute->attgenerated;
                               2735         [ +  + ]:          10814 :             if (CompressionMethodIsValid(attribute->attcompression))
   54                          2736                 :             12 :                 newdef->compression =
                               2737                 :             12 :                     pstrdup(GetCompressionMethodName(attribute->attcompression));
                               2738                 :                : 
                               2739                 :                :             /*
                               2740                 :                :              * Regular inheritance children are independent enough not to
                               2741                 :                :              * inherit identity columns.  But partitions are integral part of
                               2742                 :                :              * a partitioned table and inherit identity column.
                               2743                 :                :              */
   80                          2744         [ +  + ]:          10814 :             if (is_partition)
                               2745                 :           8866 :                 newdef->identity = attribute->attidentity;
                               2746                 :                : 
                               2747                 :                :             /*
                               2748                 :                :              * Does it match some previously considered column from another
                               2749                 :                :              * parent?
                               2750                 :                :              */
  201                          2751                 :          10814 :             exist_attno = findAttrByName(attributeName, inh_columns);
 8024 tgl@sss.pgh.pa.us        2752         [ +  + ]:CBC       10814 :             if (exist_attno > 0)
                               2753                 :                :             {
                               2754                 :                :                 /*
                               2755                 :                :                  * Yes, try to merge the two column definitions.
                               2756                 :                :                  */
   54 peter@eisentraut.org     2757                 :GNC         148 :                 mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef);
                               2758                 :                : 
   79 peter@eisentraut.org     2759                 :CBC         136 :                 newattmap->attnums[parent_attno - 1] = exist_attno;
                               2760                 :                : 
                               2761                 :                :                 /*
                               2762                 :                :                  * Partitions have only one parent, so conflict should never
                               2763                 :                :                  * occur.
                               2764                 :                :                  */
   79 peter@eisentraut.org     2765         [ -  + ]:GNC         136 :                 Assert(!is_partition);
                               2766                 :                :             }
                               2767                 :                :             else
                               2768                 :                :             {
                               2769                 :                :                 /*
                               2770                 :                :                  * No, create a new inherited column
                               2771                 :                :                  */
   80                          2772                 :          10666 :                 newdef->inhcount = 1;
                               2773                 :          10666 :                 newdef->is_local = false;
                               2774                 :          10666 :                 inh_columns = lappend(inh_columns, newdef);
                               2775                 :                : 
   79 peter@eisentraut.org     2776                 :CBC       10666 :                 newattmap->attnums[parent_attno - 1] = ++child_attno;
                               2777                 :                : 
   79 peter@eisentraut.org     2778                 :GNC       10666 :                 mergeddef = newdef;
                               2779                 :                :             }
                               2780                 :                : 
                               2781                 :                :             /*
                               2782                 :                :              * mark attnotnull if parent has it and it's not NO INHERIT
                               2783                 :                :              */
                               2784   [ +  +  +  + ]:          21180 :             if (bms_is_member(parent_attno, nncols) ||
                               2785                 :          10378 :                 bms_is_member(parent_attno - FirstLowInvalidHeapAttributeNumber,
                               2786                 :                :                               pkattrs))
                               2787                 :           1067 :                 mergeddef->is_not_null = true;
                               2788                 :                : 
                               2789                 :                :             /*
                               2790                 :                :              * In regular inheritance, columns in the parent's primary key get
                               2791                 :                :              * an extra not-null constraint.  Partitioning doesn't need this,
                               2792                 :                :              * because the PK itself is going to be cloned to the partition.
                               2793                 :                :              */
                               2794   [ +  +  +  + ]:          12738 :             if (!is_partition &&
                               2795                 :           1936 :                 bms_is_member(parent_attno -
                               2796                 :                :                               FirstLowInvalidHeapAttributeNumber,
                               2797                 :                :                               pkattrs))
                               2798                 :                :             {
                               2799                 :                :                 CookedConstraint *nn;
                               2800                 :                : 
                               2801                 :            128 :                 nn = palloc(sizeof(CookedConstraint));
                               2802                 :            128 :                 nn->contype = CONSTR_NOTNULL;
                               2803                 :            128 :                 nn->conoid = InvalidOid;
                               2804                 :            128 :                 nn->name = NULL;
                               2805                 :            128 :                 nn->attnum = newattmap->attnums[parent_attno - 1];
                               2806                 :            128 :                 nn->expr = NULL;
                               2807                 :            128 :                 nn->skip_validation = false;
                               2808                 :            128 :                 nn->is_local = false;
                               2809                 :            128 :                 nn->inhcount = 1;
                               2810                 :            128 :                 nn->is_no_inherit = false;
                               2811                 :                : 
                               2812                 :            128 :                 nnconstraints = lappend(nnconstraints, nn);
                               2813                 :                :             }
                               2814                 :                : 
                               2815                 :                :             /*
                               2816                 :                :              * Locate default/generation expression if any
                               2817                 :                :              */
 8024 tgl@sss.pgh.pa.us        2818         [ +  + ]:CBC       10802 :             if (attribute->atthasdef)
                               2819                 :                :             {
                               2820                 :                :                 Node       *this_default;
                               2821                 :                : 
  200 peter@eisentraut.org     2822                 :GNC         325 :                 this_default = TupleDescGetDefault(tupleDesc, parent_attno);
 1104 tgl@sss.pgh.pa.us        2823         [ -  + ]:CBC         325 :                 if (this_default == NULL)
 1104 tgl@sss.pgh.pa.us        2824         [ #  # ]:UBC           0 :                     elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
                               2825                 :                :                          parent_attno, RelationGetRelationName(relation));
                               2826                 :                : 
                               2827                 :                :                 /*
                               2828                 :                :                  * If it's a GENERATED default, it might contain Vars that
                               2829                 :                :                  * need to be mapped to the inherited column(s)' new numbers.
                               2830                 :                :                  * We can't do that till newattmap is ready, so just remember
                               2831                 :                :                  * all the inherited default expressions for the moment.
                               2832                 :                :                  */
 1332 tgl@sss.pgh.pa.us        2833                 :CBC         325 :                 inherited_defaults = lappend(inherited_defaults, this_default);
   79 peter@eisentraut.org     2834                 :GNC         325 :                 cols_with_defaults = lappend(cols_with_defaults, mergeddef);
                               2835                 :                :             }
                               2836                 :                :         }
                               2837                 :                : 
                               2838                 :                :         /*
                               2839                 :                :          * Now process any inherited default expressions, adjusting attnos
                               2840                 :                :          * using the completed newattmap map.
                               2841                 :                :          */
 1332 tgl@sss.pgh.pa.us        2842   [ +  +  +  +  :CBC        5441 :         forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
                                     +  +  +  +  +  
                                        +  +  -  +  
                                                 + ]
                               2843                 :                :         {
                               2844                 :            325 :             Node       *this_default = (Node *) lfirst(lc1);
                               2845                 :            325 :             ColumnDef  *def = (ColumnDef *) lfirst(lc2);
                               2846                 :                :             bool        found_whole_row;
                               2847                 :                : 
                               2848                 :                :             /* Adjust Vars to match new table's column numbering */
                               2849                 :            325 :             this_default = map_variable_attnos(this_default,
                               2850                 :                :                                                1, 0,
                               2851                 :                :                                                newattmap,
                               2852                 :                :                                                InvalidOid, &found_whole_row);
                               2853                 :                : 
                               2854                 :                :             /*
                               2855                 :                :              * For the moment we have to reject whole-row variables.  We could
                               2856                 :                :              * convert them, if we knew the new table's rowtype OID, but that
                               2857                 :                :              * hasn't been assigned yet.  (A variable could only appear in a
                               2858                 :                :              * generation expression, so the error message is correct.)
                               2859                 :                :              */
                               2860         [ -  + ]:            325 :             if (found_whole_row)
 1332 tgl@sss.pgh.pa.us        2861         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               2862                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2863                 :                :                          errmsg("cannot convert whole-row table reference"),
                               2864                 :                :                          errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
                               2865                 :                :                                    def->colname,
                               2866                 :                :                                    RelationGetRelationName(relation))));
                               2867                 :                : 
                               2868                 :                :             /*
                               2869                 :                :              * If we already had a default from some prior parent, check to
                               2870                 :                :              * see if they are the same.  If so, no problem; if not, mark the
                               2871                 :                :              * column as having a bogus default.  Below, we will complain if
                               2872                 :                :              * the bogus default isn't overridden by the child columns.
                               2873                 :                :              */
 1332 tgl@sss.pgh.pa.us        2874         [ -  + ]:CBC         325 :             Assert(def->raw_default == NULL);
                               2875         [ +  + ]:            325 :             if (def->cooked_default == NULL)
                               2876                 :            310 :                 def->cooked_default = this_default;
                               2877         [ +  + ]:             15 :             else if (!equal(def->cooked_default, this_default))
                               2878                 :                :             {
                               2879                 :             12 :                 def->cooked_default = &bogus_marker;
   54 peter@eisentraut.org     2880                 :             12 :                 have_bogus_defaults = true;
                               2881                 :                :             }
                               2882                 :                :         }
                               2883                 :                : 
                               2884                 :                :         /*
                               2885                 :                :          * Now copy the CHECK constraints of this parent, adjusting attnos
                               2886                 :                :          * using the completed newattmap map.  Identically named constraints
                               2887                 :                :          * are merged if possible, else we throw error.
                               2888                 :                :          */
 8024 tgl@sss.pgh.pa.us        2889   [ +  +  +  + ]:           5116 :         if (constr && constr->num_check > 0)
                               2890                 :                :         {
                               2891                 :            152 :             ConstrCheck *check = constr->check;
                               2892                 :                : 
  201 peter@eisentraut.org     2893         [ +  + ]:GNC         319 :             for (int i = 0; i < constr->num_check; i++)
                               2894                 :                :             {
 5819 tgl@sss.pgh.pa.us        2895                 :CBC         167 :                 char       *name = check[i].ccname;
                               2896                 :                :                 Node       *expr;
                               2897                 :                :                 bool        found_whole_row;
                               2898                 :                : 
                               2899                 :                :                 /* ignore if the constraint is non-inheritable */
 4377 alvherre@alvh.no-ip.     2900         [ +  + ]:            167 :                 if (check[i].ccnoinherit)
 4514                          2901                 :             24 :                     continue;
                               2902                 :                : 
                               2903                 :                :                 /* Adjust Vars to match new table's column numbering */
 4306 tgl@sss.pgh.pa.us        2904                 :            143 :                 expr = map_variable_attnos(stringToNode(check[i].ccbin),
                               2905                 :                :                                            1, 0,
                               2906                 :                :                                            newattmap,
                               2907                 :                :                                            InvalidOid, &found_whole_row);
                               2908                 :                : 
                               2909                 :                :                 /*
                               2910                 :                :                  * For the moment we have to reject whole-row variables. We
                               2911                 :                :                  * could convert them, if we knew the new table's rowtype OID,
                               2912                 :                :                  * but that hasn't been assigned yet.
                               2913                 :                :                  */
                               2914         [ -  + ]:            143 :                 if (found_whole_row)
 4306 tgl@sss.pgh.pa.us        2915         [ #  # ]:UBC           0 :                     ereport(ERROR,
                               2916                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2917                 :                :                              errmsg("cannot convert whole-row table reference"),
                               2918                 :                :                              errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
                               2919                 :                :                                        name,
                               2920                 :                :                                        RelationGetRelationName(relation))));
                               2921                 :                : 
  201 peter@eisentraut.org     2922                 :GNC         143 :                 constraints = MergeCheckConstraint(constraints, name, expr);
                               2923                 :                :             }
                               2924                 :                :         }
                               2925                 :                : 
                               2926                 :                :         /*
                               2927                 :                :          * Also copy the not-null constraints from this parent.  The
                               2928                 :                :          * attnotnull markings were already installed above.
                               2929                 :                :          */
  233 alvherre@alvh.no-ip.     2930   [ +  +  +  +  :           5540 :         foreach(lc1, nnconstrs)
                                              +  + ]
                               2931                 :                :         {
                               2932                 :            424 :             CookedConstraint *nn = lfirst(lc1);
                               2933                 :                : 
                               2934         [ -  + ]:            424 :             Assert(nn->contype == CONSTR_NOTNULL);
                               2935                 :                : 
                               2936                 :            424 :             nn->attnum = newattmap->attnums[nn->attnum - 1];
                               2937                 :            424 :             nn->is_local = false;
                               2938                 :            424 :             nn->inhcount = 1;
                               2939                 :                : 
                               2940                 :            424 :             nnconstraints = lappend(nnconstraints, nn);
                               2941                 :                :         }
                               2942                 :                : 
 1579 michael@paquier.xyz      2943                 :CBC        5116 :         free_attrmap(newattmap);
                               2944                 :                : 
                               2945                 :                :         /*
                               2946                 :                :          * Close the parent rel, but keep our lock on it until xact commit.
                               2947                 :                :          * That will prevent someone else from deleting or ALTERing the parent
                               2948                 :                :          * before the child is committed.
                               2949                 :                :          */
 1910 andres@anarazel.de       2950                 :           5116 :         table_close(relation, NoLock);
                               2951                 :                :     }
                               2952                 :                : 
                               2953                 :                :     /*
                               2954                 :                :      * If we had no inherited attributes, the result columns are just the
                               2955                 :                :      * explicitly declared columns.  Otherwise, we need to merge the declared
                               2956                 :                :      * columns into the inherited column list.  Although, we never have any
                               2957                 :                :      * explicitly declared columns if the table is a partition.
                               2958                 :                :      */
  201 peter@eisentraut.org     2959         [ +  + ]:GNC       26217 :     if (inh_columns != NIL)
                               2960                 :                :     {
                               2961                 :           4953 :         int         newcol_attno = 0;
                               2962                 :                : 
                               2963   [ +  +  +  +  :           5342 :         foreach(lc, columns)
                                              +  + ]
                               2964                 :                :         {
   79                          2965                 :            413 :             ColumnDef  *newdef = lfirst_node(ColumnDef, lc);
 8024 tgl@sss.pgh.pa.us        2966                 :CBC         413 :             char       *attributeName = newdef->colname;
                               2967                 :                :             int         exist_attno;
                               2968                 :                : 
                               2969                 :                :             /*
                               2970                 :                :              * Partitions have only one parent and have no column definitions
                               2971                 :                :              * of their own, so conflict should never occur.
                               2972                 :                :              */
   79 peter@eisentraut.org     2973         [ -  + ]:GNC         413 :             Assert(!is_partition);
                               2974                 :                : 
  201                          2975                 :            413 :             newcol_attno++;
                               2976                 :                : 
                               2977                 :                :             /*
                               2978                 :                :              * Does it match some inherited column?
                               2979                 :                :              */
                               2980                 :            413 :             exist_attno = findAttrByName(attributeName, inh_columns);
 8024 tgl@sss.pgh.pa.us        2981         [ +  + ]:CBC         413 :             if (exist_attno > 0)
                               2982                 :                :             {
                               2983                 :                :                 /*
                               2984                 :                :                  * Yes, try to merge the two column definitions.
                               2985                 :                :                  */
   79 peter@eisentraut.org     2986                 :GNC         134 :                 MergeChildAttribute(inh_columns, exist_attno, newcol_attno, newdef);
                               2987                 :                :             }
                               2988                 :                :             else
                               2989                 :                :             {
                               2990                 :                :                 /*
                               2991                 :                :                  * No, attach new column unchanged to result columns.
                               2992                 :                :                  */
  201                          2993                 :            279 :                 inh_columns = lappend(inh_columns, newdef);
                               2994                 :                :             }
                               2995                 :                :         }
                               2996                 :                : 
                               2997                 :           4929 :         columns = inh_columns;
                               2998                 :                : 
                               2999                 :                :         /*
                               3000                 :                :          * Check that we haven't exceeded the legal # of columns after merging
                               3001                 :                :          * in inherited columns.
                               3002                 :                :          */
                               3003         [ -  + ]:           4929 :         if (list_length(columns) > MaxHeapAttributeNumber)
 7089 neilc@samurai.com        3004         [ #  # ]:UBC           0 :             ereport(ERROR,
                               3005                 :                :                     (errcode(ERRCODE_TOO_MANY_COLUMNS),
                               3006                 :                :                      errmsg("tables can have at most %d columns",
                               3007                 :                :                             MaxHeapAttributeNumber)));
                               3008                 :                :     }
                               3009                 :                : 
                               3010                 :                :     /*
                               3011                 :                :      * Now that we have the column definition list for a partition, we can
                               3012                 :                :      * check whether the columns referenced in the column constraint specs
                               3013                 :                :      * actually exist.  Also, merge column defaults.
                               3014                 :                :      */
 1984 alvherre@alvh.no-ip.     3015         [ +  + ]:CBC       26193 :     if (is_partition)
                               3016                 :                :     {
  201 peter@eisentraut.org     3017   [ +  +  +  +  :GNC        4208 :         foreach(lc, saved_columns)
                                              +  + ]
                               3018                 :                :         {
                               3019                 :            104 :             ColumnDef  *restdef = lfirst(lc);
 1984 alvherre@alvh.no-ip.     3020                 :CBC         104 :             bool        found = false;
                               3021                 :                :             ListCell   *l;
                               3022                 :                : 
  201 peter@eisentraut.org     3023   [ +  -  +  +  :GNC         392 :             foreach(l, columns)
                                              +  + ]
                               3024                 :                :             {
 1984 alvherre@alvh.no-ip.     3025                 :CBC         294 :                 ColumnDef  *coldef = lfirst(l);
                               3026                 :                : 
 2685 rhaas@postgresql.org     3027         [ +  + ]:            294 :                 if (strcmp(coldef->colname, restdef->colname) == 0)
                               3028                 :                :                 {
 1984 alvherre@alvh.no-ip.     3029                 :            104 :                     found = true;
                               3030                 :                : 
                               3031                 :                :                     /*
                               3032                 :                :                      * Check for conflicts related to generated columns.
                               3033                 :                :                      *
                               3034                 :                :                      * Same rules as above: generated-ness has to match the
                               3035                 :                :                      * parent, but the contents of the generation expression
                               3036                 :                :                      * can be different.
                               3037                 :                :                      */
  423 tgl@sss.pgh.pa.us        3038         [ +  + ]:            104 :                     if (coldef->generated)
                               3039                 :                :                     {
                               3040   [ +  -  +  + ]:             53 :                         if (restdef->raw_default && !restdef->generated)
                               3041         [ +  - ]:              3 :                             ereport(ERROR,
                               3042                 :                :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3043                 :                :                                      errmsg("column \"%s\" inherits from generated column but specifies default",
                               3044                 :                :                                             restdef->colname)));
                               3045         [ -  + ]:             50 :                         if (restdef->identity)
  423 tgl@sss.pgh.pa.us        3046         [ #  # ]:UBC           0 :                             ereport(ERROR,
                               3047                 :                :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3048                 :                :                                      errmsg("column \"%s\" inherits from generated column but specifies identity",
                               3049                 :                :                                             restdef->colname)));
                               3050                 :                :                     }
                               3051                 :                :                     else
                               3052                 :                :                     {
  423 tgl@sss.pgh.pa.us        3053         [ +  + ]:CBC          51 :                         if (restdef->generated)
                               3054         [ +  - ]:              3 :                             ereport(ERROR,
                               3055                 :                :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3056                 :                :                                      errmsg("child column \"%s\" specifies generation expression",
                               3057                 :                :                                             restdef->colname),
                               3058                 :                :                                      errhint("A child table column cannot be generated unless its parent column is.")));
                               3059                 :                :                     }
                               3060                 :                : 
                               3061                 :                :                     /*
                               3062                 :                :                      * Override the parent's default value for this column
                               3063                 :                :                      * (coldef->cooked_default) with the partition's local
                               3064                 :                :                      * definition (restdef->raw_default), if there's one. It
                               3065                 :                :                      * should be physically impossible to get a cooked default
                               3066                 :                :                      * in the local definition or a raw default in the
                               3067                 :                :                      * inherited definition, but make sure they're nulls, for
                               3068                 :                :                      * future-proofing.
                               3069                 :                :                      */
 1984 alvherre@alvh.no-ip.     3070         [ -  + ]:             98 :                     Assert(restdef->cooked_default == NULL);
                               3071         [ -  + ]:             98 :                     Assert(coldef->raw_default == NULL);
                               3072         [ +  + ]:             98 :                     if (restdef->raw_default)
                               3073                 :                :                     {
 2543 rhaas@postgresql.org     3074                 :             62 :                         coldef->raw_default = restdef->raw_default;
 1984 alvherre@alvh.no-ip.     3075                 :             62 :                         coldef->cooked_default = NULL;
                               3076                 :                :                     }
                               3077                 :                :                 }
                               3078                 :                :             }
                               3079                 :                : 
                               3080                 :                :             /* complain for constraints on columns not in parent */
                               3081         [ -  + ]:             98 :             if (!found)
 1984 alvherre@alvh.no-ip.     3082         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               3083                 :                :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
                               3084                 :                :                          errmsg("column \"%s\" does not exist",
                               3085                 :                :                                 restdef->colname)));
                               3086                 :                :         }
                               3087                 :                :     }
                               3088                 :                : 
                               3089                 :                :     /*
                               3090                 :                :      * If we found any conflicting parent default values, check to make sure
                               3091                 :                :      * they were overridden by the child.
                               3092                 :                :      */
   54 peter@eisentraut.org     3093         [ +  + ]:CBC       26187 :     if (have_bogus_defaults)
                               3094                 :                :     {
  201 peter@eisentraut.org     3095   [ +  -  +  +  :GNC          27 :         foreach(lc, columns)
                                              +  + ]
                               3096                 :                :         {
                               3097                 :             21 :             ColumnDef  *def = lfirst(lc);
                               3098                 :                : 
 5304 tgl@sss.pgh.pa.us        3099         [ +  + ]:CBC          21 :             if (def->cooked_default == &bogus_marker)
                               3100                 :                :             {
 1439 peter@eisentraut.org     3101         [ +  + ]:              6 :                 if (def->generated)
                               3102         [ +  - ]:              3 :                     ereport(ERROR,
                               3103                 :                :                             (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3104                 :                :                              errmsg("column \"%s\" inherits conflicting generation expressions",
                               3105                 :                :                                     def->colname),
                               3106                 :                :                              errhint("To resolve the conflict, specify a generation expression explicitly.")));
                               3107                 :                :                 else
                               3108         [ +  - ]:              3 :                     ereport(ERROR,
                               3109                 :                :                             (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3110                 :                :                              errmsg("column \"%s\" inherits conflicting default values",
                               3111                 :                :                                     def->colname),
                               3112                 :                :                              errhint("To resolve the conflict, specify a default explicitly.")));
                               3113                 :                :             }
                               3114                 :                :         }
                               3115                 :                :     }
                               3116                 :                : 
 8024 tgl@sss.pgh.pa.us        3117                 :          26181 :     *supconstr = constraints;
  233 alvherre@alvh.no-ip.     3118                 :GNC       26181 :     *supnotnulls = nnconstraints;
                               3119                 :                : 
  201 peter@eisentraut.org     3120                 :          26181 :     return columns;
                               3121                 :                : }
                               3122                 :                : 
                               3123                 :                : 
                               3124                 :                : /*
                               3125                 :                :  * MergeCheckConstraint
                               3126                 :                :  *      Try to merge an inherited CHECK constraint with previous ones
                               3127                 :                :  *
                               3128                 :                :  * If we inherit identically-named constraints from multiple parents, we must
                               3129                 :                :  * merge them, or throw an error if they don't have identical definitions.
                               3130                 :                :  *
                               3131                 :                :  * constraints is a list of CookedConstraint structs for previous constraints.
                               3132                 :                :  *
                               3133                 :                :  * If the new constraint matches an existing one, then the existing
                               3134                 :                :  * constraint's inheritance count is updated.  If there is a conflict (same
                               3135                 :                :  * name but different expression), throw an error.  If the constraint neither
                               3136                 :                :  * matches nor conflicts with an existing one, a new constraint is appended to
                               3137                 :                :  * the list.
                               3138                 :                :  */
                               3139                 :                : static List *
                               3140                 :            143 : MergeCheckConstraint(List *constraints, const char *name, Node *expr)
                               3141                 :                : {
                               3142                 :                :     ListCell   *lc;
                               3143                 :                :     CookedConstraint *newcon;
                               3144                 :                : 
 5819 tgl@sss.pgh.pa.us        3145   [ +  +  +  +  :CBC         158 :     foreach(lc, constraints)
                                              +  + ]
                               3146                 :                :     {
                               3147                 :             36 :         CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
                               3148                 :                : 
                               3149         [ -  + ]:             36 :         Assert(ccon->contype == CONSTR_CHECK);
                               3150                 :                : 
                               3151                 :                :         /* Non-matching names never conflict */
                               3152         [ +  + ]:             36 :         if (strcmp(ccon->name, name) != 0)
 6501 bruce@momjian.us         3153                 :             15 :             continue;
                               3154                 :                : 
 5819 tgl@sss.pgh.pa.us        3155         [ +  - ]:             21 :         if (equal(expr, ccon->expr))
                               3156                 :                :         {
                               3157                 :                :             /* OK to merge constraint with existing */
                               3158                 :             21 :             ccon->inhcount++;
  383 peter@eisentraut.org     3159         [ -  + ]:             21 :             if (ccon->inhcount < 0)
  383 peter@eisentraut.org     3160         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               3161                 :                :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               3162                 :                :                         errmsg("too many inheritance parents"));
  201 peter@eisentraut.org     3163                 :GNC          21 :             return constraints;
                               3164                 :                :         }
                               3165                 :                : 
 6395 tgl@sss.pgh.pa.us        3166         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3167                 :                :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
                               3168                 :                :                  errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
                               3169                 :                :                         name)));
                               3170                 :                :     }
                               3171                 :                : 
                               3172                 :                :     /*
                               3173                 :                :      * Constraint couldn't be merged with an existing one and also didn't
                               3174                 :                :      * conflict with an existing one, so add it as a new one to the list.
                               3175                 :                :      */
  201 peter@eisentraut.org     3176                 :GNC         122 :     newcon = palloc0_object(CookedConstraint);
                               3177                 :            122 :     newcon->contype = CONSTR_CHECK;
                               3178                 :            122 :     newcon->name = pstrdup(name);
                               3179                 :            122 :     newcon->expr = expr;
                               3180                 :            122 :     newcon->inhcount = 1;
                               3181                 :            122 :     return lappend(constraints, newcon);
                               3182                 :                : }
                               3183                 :                : 
                               3184                 :                : /*
                               3185                 :                :  * MergeChildAttribute
                               3186                 :                :  *      Merge given child attribute definition into given inherited attribute.
                               3187                 :                :  *
                               3188                 :                :  * Input arguments:
                               3189                 :                :  * 'inh_columns' is the list of inherited ColumnDefs.
                               3190                 :                :  * 'exist_attno' is the number of the inherited attribute in inh_columns
                               3191                 :                :  * 'newcol_attno' is the attribute number in child table's schema definition
                               3192                 :                :  * 'newdef' is the column/attribute definition from the child table.
                               3193                 :                :  *
                               3194                 :                :  * The ColumnDef in 'inh_columns' list is modified.  The child attribute's
                               3195                 :                :  * ColumnDef remains unchanged.
                               3196                 :                :  *
                               3197                 :                :  * Notes:
                               3198                 :                :  * - The attribute is merged according to the rules laid out in the prologue
                               3199                 :                :  *   of MergeAttributes().
                               3200                 :                :  * - If matching inherited attribute exists but the child attribute can not be
                               3201                 :                :  *   merged into it, the function throws respective errors.
                               3202                 :                :  * - A partition can not have its own column definitions. Hence this function
                               3203                 :                :  *   is applicable only to a regular inheritance child.
                               3204                 :                :  */
                               3205                 :                : static void
   79                          3206                 :            134 : MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
                               3207                 :                : {
                               3208                 :            134 :     char       *attributeName = newdef->colname;
                               3209                 :                :     ColumnDef  *inhdef;
                               3210                 :                :     Oid         inhtypeid,
                               3211                 :                :                 newtypeid;
                               3212                 :                :     int32       inhtypmod,
                               3213                 :                :                 newtypmod;
                               3214                 :                :     Oid         inhcollid,
                               3215                 :                :                 newcollid;
                               3216                 :                : 
                               3217         [ +  + ]:            134 :     if (exist_attno == newcol_attno)
                               3218         [ +  - ]:            120 :         ereport(NOTICE,
                               3219                 :                :                 (errmsg("merging column \"%s\" with inherited definition",
                               3220                 :                :                         attributeName)));
                               3221                 :                :     else
                               3222         [ +  - ]:             14 :         ereport(NOTICE,
                               3223                 :                :                 (errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
                               3224                 :                :                  errdetail("User-specified column moved to the position of the inherited column.")));
                               3225                 :                : 
                               3226                 :            134 :     inhdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
                               3227                 :                : 
                               3228                 :                :     /*
                               3229                 :                :      * Must have the same type and typmod
                               3230                 :                :      */
                               3231                 :            134 :     typenameTypeIdAndMod(NULL, inhdef->typeName, &inhtypeid, &inhtypmod);
                               3232                 :            134 :     typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
                               3233   [ +  +  +  + ]:            134 :     if (inhtypeid != newtypeid || inhtypmod != newtypmod)
                               3234         [ +  - ]:              6 :         ereport(ERROR,
                               3235                 :                :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3236                 :                :                  errmsg("column \"%s\" has a type conflict",
                               3237                 :                :                         attributeName),
                               3238                 :                :                  errdetail("%s versus %s",
                               3239                 :                :                            format_type_with_typemod(inhtypeid, inhtypmod),
                               3240                 :                :                            format_type_with_typemod(newtypeid, newtypmod))));
                               3241                 :                : 
                               3242                 :                :     /*
                               3243                 :                :      * Must have the same collation
                               3244                 :                :      */
                               3245                 :            128 :     inhcollid = GetColumnDefCollation(NULL, inhdef, inhtypeid);
                               3246                 :            128 :     newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
                               3247         [ +  + ]:            128 :     if (inhcollid != newcollid)
                               3248         [ +  - ]:              3 :         ereport(ERROR,
                               3249                 :                :                 (errcode(ERRCODE_COLLATION_MISMATCH),
                               3250                 :                :                  errmsg("column \"%s\" has a collation conflict",
                               3251                 :                :                         attributeName),
                               3252                 :                :                  errdetail("\"%s\" versus \"%s\"",
                               3253                 :                :                            get_collation_name(inhcollid),
                               3254                 :                :                            get_collation_name(newcollid))));
                               3255                 :                : 
                               3256                 :                :     /*
                               3257                 :                :      * Identity is never inherited by a regular inheritance child. Pick
                               3258                 :                :      * child's identity definition if there's one.
                               3259                 :                :      */
                               3260                 :            125 :     inhdef->identity = newdef->identity;
                               3261                 :                : 
                               3262                 :                :     /*
                               3263                 :                :      * Copy storage parameter
                               3264                 :                :      */
   54                          3265         [ -  + ]:            125 :     if (inhdef->storage == 0)
   54 peter@eisentraut.org     3266                 :UNC           0 :         inhdef->storage = newdef->storage;
   54 peter@eisentraut.org     3267   [ +  +  +  + ]:GNC         125 :     else if (newdef->storage != 0 && inhdef->storage != newdef->storage)
                               3268         [ +  - ]:              3 :         ereport(ERROR,
                               3269                 :                :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3270                 :                :                  errmsg("column \"%s\" has a storage parameter conflict",
                               3271                 :                :                         attributeName),
                               3272                 :                :                  errdetail("%s versus %s",
                               3273                 :                :                            storage_name(inhdef->storage),
                               3274                 :                :                            storage_name(newdef->storage))));
                               3275                 :                : 
                               3276                 :                :     /*
                               3277                 :                :      * Copy compression parameter
                               3278                 :                :      */
                               3279         [ +  + ]:            122 :     if (inhdef->compression == NULL)
   79                          3280                 :            119 :         inhdef->compression = newdef->compression;
   54                          3281         [ +  - ]:              3 :     else if (newdef->compression != NULL)
                               3282                 :                :     {
                               3283         [ +  - ]:              3 :         if (strcmp(inhdef->compression, newdef->compression) != 0)
                               3284         [ +  - ]:              3 :             ereport(ERROR,
                               3285                 :                :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3286                 :                :                      errmsg("column \"%s\" has a compression method conflict",
                               3287                 :                :                             attributeName),
                               3288                 :                :                      errdetail("%s versus %s", inhdef->compression, newdef->compression)));
                               3289                 :                :     }
                               3290                 :                : 
                               3291                 :                :     /*
                               3292                 :                :      * Merge of not-null constraints = OR 'em together
                               3293                 :                :      */
   79                          3294                 :            119 :     inhdef->is_not_null |= newdef->is_not_null;
                               3295                 :                : 
                               3296                 :                :     /*
                               3297                 :                :      * Check for conflicts related to generated columns.
                               3298                 :                :      *
                               3299                 :                :      * If the parent column is generated, the child column will be made a
                               3300                 :                :      * generated column if it isn't already.  If it is a generated column,
                               3301                 :                :      * we'll take its generation expression in preference to the parent's.  We
                               3302                 :                :      * must check that the child column doesn't specify a default value or
                               3303                 :                :      * identity, which matches the rules for a single column in
                               3304                 :                :      * parse_utilcmd.c.
                               3305                 :                :      *
                               3306                 :                :      * Conversely, if the parent column is not generated, the child column
                               3307                 :                :      * can't be either.  (We used to allow that, but it results in being able
                               3308                 :                :      * to override the generation expression via UPDATEs through the parent.)
                               3309                 :                :      */
                               3310         [ +  + ]:            119 :     if (inhdef->generated)
                               3311                 :                :     {
                               3312   [ +  +  +  + ]:             13 :         if (newdef->raw_default && !newdef->generated)
                               3313         [ +  - ]:              3 :             ereport(ERROR,
                               3314                 :                :                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3315                 :                :                      errmsg("column \"%s\" inherits from generated column but specifies default",
                               3316                 :                :                             inhdef->colname)));
                               3317         [ +  + ]:             10 :         if (newdef->identity)
                               3318         [ +  - ]:              3 :             ereport(ERROR,
                               3319                 :                :                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3320                 :                :                      errmsg("column \"%s\" inherits from generated column but specifies identity",
                               3321                 :                :                             inhdef->colname)));
                               3322                 :                :     }
                               3323                 :                :     else
                               3324                 :                :     {
                               3325         [ +  + ]:            106 :         if (newdef->generated)
                               3326         [ +  - ]:              3 :             ereport(ERROR,
                               3327                 :                :                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                               3328                 :                :                      errmsg("child column \"%s\" specifies generation expression",
                               3329                 :                :                             inhdef->colname),
                               3330                 :                :                      errhint("A child table column cannot be generated unless its parent column is.")));
                               3331                 :                :     }
                               3332                 :                : 
                               3333                 :                :     /*
                               3334                 :                :      * If new def has a default, override previous default
                               3335                 :                :      */
                               3336         [ +  + ]:            110 :     if (newdef->raw_default != NULL)
                               3337                 :                :     {
                               3338                 :              9 :         inhdef->raw_default = newdef->raw_default;
                               3339                 :              9 :         inhdef->cooked_default = newdef->cooked_default;
                               3340                 :                :     }
                               3341                 :                : 
                               3342                 :                :     /* Mark the column as locally defined */
                               3343                 :            110 :     inhdef->is_local = true;
                               3344                 :            110 : }
                               3345                 :                : 
                               3346                 :                : /*
                               3347                 :                :  * MergeInheritedAttribute
                               3348                 :                :  *      Merge given parent attribute definition into specified attribute
                               3349                 :                :  *      inherited from the previous parents.
                               3350                 :                :  *
                               3351                 :                :  * Input arguments:
                               3352                 :                :  * 'inh_columns' is the list of previously inherited ColumnDefs.
                               3353                 :                :  * 'exist_attno' is the number the existing matching attribute in inh_columns.
                               3354                 :                :  * 'newdef' is the new parent column/attribute definition to be merged.
                               3355                 :                :  *
                               3356                 :                :  * The matching ColumnDef in 'inh_columns' list is modified and returned.
                               3357                 :                :  *
                               3358                 :                :  * Notes:
                               3359                 :                :  * - The attribute is merged according to the rules laid out in the prologue
                               3360                 :                :  *   of MergeAttributes().
                               3361                 :                :  * - If matching inherited attribute exists but the new attribute can not be
                               3362                 :                :  *   merged into it, the function throws respective errors.
                               3363                 :                :  * - A partition inherits from only a single parent. Hence this function is
                               3364                 :                :  *   applicable only to a regular inheritance.
                               3365                 :                :  */
                               3366                 :                : static ColumnDef *
                               3367                 :            148 : MergeInheritedAttribute(List *inh_columns,
                               3368                 :                :                         int exist_attno,
                               3369                 :                :                         const ColumnDef *newdef)
                               3370                 :                : {
                               3371                 :            148 :     char       *attributeName = newdef->colname;
                               3372                 :                :     ColumnDef  *prevdef;
                               3373                 :                :     Oid         prevtypeid,
                               3374                 :                :                 newtypeid;
                               3375                 :                :     int32       prevtypmod,
                               3376                 :                :                 newtypmod;
                               3377                 :                :     Oid         prevcollid,
                               3378                 :                :                 newcollid;
                               3379                 :                : 
                               3380         [ +  - ]:            148 :     ereport(NOTICE,
                               3381                 :                :             (errmsg("merging multiple inherited definitions of column \"%s\"",
                               3382                 :                :                     attributeName)));
                               3383                 :            148 :     prevdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
                               3384                 :                : 
                               3385                 :                :     /*
                               3386                 :                :      * Must have the same type and typmod
                               3387                 :                :      */
                               3388                 :            148 :     typenameTypeIdAndMod(NULL, prevdef->typeName, &prevtypeid, &prevtypmod);
                               3389                 :            148 :     typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
                               3390   [ +  -  -  + ]:            148 :     if (prevtypeid != newtypeid || prevtypmod != newtypmod)
   79 peter@eisentraut.org     3391         [ #  # ]:UNC           0 :         ereport(ERROR,
                               3392                 :                :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3393                 :                :                  errmsg("inherited column \"%s\" has a type conflict",
                               3394                 :                :                         attributeName),
                               3395                 :                :                  errdetail("%s versus %s",
                               3396                 :                :                            format_type_with_typemod(prevtypeid, prevtypmod),
                               3397                 :                :                            format_type_with_typemod(newtypeid, newtypmod))));
                               3398                 :                : 
                               3399                 :                :     /*
                               3400                 :                :      * Must have the same collation
                               3401                 :                :      */
   79 peter@eisentraut.org     3402                 :GNC         148 :     prevcollid = GetColumnDefCollation(NULL, prevdef, prevtypeid);
                               3403                 :            148 :     newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
                               3404         [ -  + ]:            148 :     if (prevcollid != newcollid)
   79 peter@eisentraut.org     3405         [ #  # ]:UNC           0 :         ereport(ERROR,
                               3406                 :                :                 (errcode(ERRCODE_COLLATION_MISMATCH),
                               3407                 :                :                  errmsg("inherited column \"%s\" has a collation conflict",
                               3408                 :                :                         attributeName),
                               3409                 :                :                  errdetail("\"%s\" versus \"%s\"",
                               3410                 :                :                            get_collation_name(prevcollid),
                               3411                 :                :                            get_collation_name(newcollid))));
                               3412                 :                : 
                               3413                 :                :     /*
                               3414                 :                :      * Copy/check storage parameter
                               3415                 :                :      */
   54 peter@eisentraut.org     3416         [ -  + ]:GNC         148 :     if (prevdef->storage == 0)
   54 peter@eisentraut.org     3417                 :UNC           0 :         prevdef->storage = newdef->storage;
   54 peter@eisentraut.org     3418         [ +  + ]:GNC         148 :     else if (prevdef->storage != newdef->storage)
                               3419         [ +  - ]:              3 :         ereport(ERROR,
                               3420                 :                :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3421                 :                :                  errmsg("inherited column \"%s\" has a storage parameter conflict",
                               3422                 :                :                         attributeName),
                               3423                 :                :                  errdetail("%s versus %s",
                               3424                 :                :                            storage_name(prevdef->storage),
                               3425                 :                :                            storage_name(newdef->storage))));
                               3426                 :                : 
                               3427                 :                :     /*
                               3428                 :                :      * Copy/check compression parameter
                               3429                 :                :      */
   79                          3430         [ +  + ]:            145 :     if (prevdef->compression == NULL)
                               3431                 :            142 :         prevdef->compression = newdef->compression;
   54                          3432         [ +  - ]:              3 :     else if (strcmp(prevdef->compression, newdef->compression) != 0)
                               3433         [ +  - ]:              3 :         ereport(ERROR,
                               3434                 :                :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3435                 :                :                  errmsg("column \"%s\" has a compression method conflict",
                               3436                 :                :                         attributeName),
                               3437                 :                :                  errdetail("%s versus %s", prevdef->compression, newdef->compression)));
                               3438                 :                : 
                               3439                 :                :     /*
                               3440                 :                :      * Check for GENERATED conflicts
                               3441                 :                :      */
   79                          3442         [ +  + ]:            142 :     if (prevdef->generated != newdef->generated)
                               3443         [ +  - ]:              6 :         ereport(ERROR,
                               3444                 :                :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                               3445                 :                :                  errmsg("inherited column \"%s\" has a generation conflict",
                               3446                 :                :                         attributeName)));
                               3447                 :                : 
                               3448                 :                :     /*
                               3449                 :                :      * Default and other constraints are handled by the caller.
                               3450                 :                :      */
                               3451                 :                : 
                               3452                 :            136 :     prevdef->inhcount++;
                               3453         [ -  + ]:            136 :     if (prevdef->inhcount < 0)
   79 peter@eisentraut.org     3454         [ #  # ]:UNC           0 :         ereport(ERROR,
                               3455                 :                :                 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               3456                 :                :                 errmsg("too many inheritance parents"));
                               3457                 :                : 
   79 peter@eisentraut.org     3458                 :GNC         136 :     return prevdef;
                               3459                 :                : }
                               3460                 :                : 
                               3461                 :                : /*
                               3462                 :                :  * StoreCatalogInheritance
                               3463                 :                :  *      Updates the system catalogs with proper inheritance information.
                               3464                 :                :  *
                               3465                 :                :  * supers is a list of the OIDs of the new relation's direct ancestors.
                               3466                 :                :  */
                               3467                 :                : static void
 2596 simon@2ndQuadrant.co     3468                 :CBC       25908 : StoreCatalogInheritance(Oid relationId, List *supers,
                               3469                 :                :                         bool child_is_partition)
                               3470                 :                : {
                               3471                 :                :     Relation    relation;
                               3472                 :                :     int32       seqNumber;
                               3473                 :                :     ListCell   *entry;
                               3474                 :                : 
                               3475                 :                :     /*
                               3476                 :                :      * sanity checks
                               3477                 :                :      */
  534 peter@eisentraut.org     3478         [ -  + ]:          25908 :     Assert(OidIsValid(relationId));
                               3479                 :                : 
 8024 tgl@sss.pgh.pa.us        3480         [ +  + ]:          25908 :     if (supers == NIL)
                               3481                 :          21153 :         return;
                               3482                 :                : 
                               3483                 :                :     /*
                               3484                 :                :      * Store INHERITS information in pg_inherits using direct ancestors only.
                               3485                 :                :      * Also enter dependencies on the direct ancestors, and make sure they are
                               3486                 :                :      * marked with relhassubclass = true.
                               3487                 :                :      *
                               3488                 :                :      * (Once upon a time, both direct and indirect ancestors were found here
                               3489                 :                :      * and then entered into pg_ipl.  Since that catalog doesn't exist
                               3490                 :                :      * anymore, there's no need to look for indirect ancestors.)
                               3491                 :                :      */
 1910 andres@anarazel.de       3492                 :           4755 :     relation = table_open(InheritsRelationId, RowExclusiveLock);
                               3493                 :                : 
 8024 tgl@sss.pgh.pa.us        3494                 :           4755 :     seqNumber = 1;
                               3495   [ +  -  +  +  :           9640 :     foreach(entry, supers)
                                              +  + ]
                               3496                 :                :     {
 6393                          3497                 :           4885 :         Oid         parentOid = lfirst_oid(entry);
                               3498                 :                : 
 2596 simon@2ndQuadrant.co     3499                 :           4885 :         StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
                               3500                 :                :                                  child_is_partition);
 6496 neilc@samurai.com        3501                 :           4885 :         seqNumber++;
                               3502                 :                :     }
                               3503                 :                : 
 1910 andres@anarazel.de       3504                 :           4755 :     table_close(relation, RowExclusiveLock);
                               3505                 :                : }
                               3506                 :                : 
                               3507                 :                : /*
                               3508                 :                :  * Make catalog entries showing relationId as being an inheritance child
                               3509                 :                :  * of parentOid.  inhRelation is the already-opened pg_inherits catalog.
                               3510                 :                :  */
                               3511                 :                : static void
 6496 neilc@samurai.com        3512                 :           6187 : StoreCatalogInheritance1(Oid relationId, Oid parentOid,
                               3513                 :                :                          int32 seqNumber, Relation inhRelation,
                               3514                 :                :                          bool child_is_partition)
                               3515                 :                : {
                               3516                 :                :     ObjectAddress childobject,
                               3517                 :                :                 parentobject;
                               3518                 :                : 
                               3519                 :                :     /* store the pg_inherits row */
 2277 alvherre@alvh.no-ip.     3520                 :           6187 :     StoreSingleInheritance(relationId, parentOid, seqNumber);
                               3521                 :                : 
                               3522                 :                :     /*
                               3523                 :                :      * Store a dependency too
                               3524                 :                :      */
 6496 neilc@samurai.com        3525                 :           6187 :     parentobject.classId = RelationRelationId;
                               3526                 :           6187 :     parentobject.objectId = parentOid;
                               3527                 :           6187 :     parentobject.objectSubId = 0;
                               3528                 :           6187 :     childobject.classId = RelationRelationId;
                               3529                 :           6187 :     childobject.objectId = relationId;
                               3530                 :           6187 :     childobject.objectSubId = 0;
                               3531                 :                : 
 2497 rhaas@postgresql.org     3532         [ +  + ]:           6187 :     recordDependencyOn(&childobject, &parentobject,
                               3533                 :                :                        child_dependency_type(child_is_partition));
                               3534                 :                : 
                               3535                 :                :     /*
                               3536                 :                :      * Post creation hook of this inheritance. Since object_access_hook
                               3537                 :                :      * doesn't take multiple object identifiers, we relay oid of parent
                               3538                 :                :      * relation using auxiliary_id argument.
                               3539                 :                :      */
 4046                          3540         [ -  + ]:           6187 :     InvokeObjectPostAlterHookArg(InheritsRelationId,
                               3541                 :                :                                  relationId, 0,
                               3542                 :                :                                  parentOid, false);
                               3543                 :                : 
                               3544                 :                :     /*
                               3545                 :                :      * Mark the parent as having subclasses.
                               3546                 :                :      */
 4608 tgl@sss.pgh.pa.us        3547                 :           6187 :     SetRelationHasSubclass(parentOid, true);
 8024                          3548                 :           6187 : }
                               3549                 :                : 
                               3550                 :                : /*
                               3551                 :                :  * Look for an existing column entry with the given name.
                               3552                 :                :  *
                               3553                 :                :  * Returns the index (starting with 1) if attribute already exists in columns,
                               3554                 :                :  * 0 if it doesn't.
                               3555                 :                :  */
                               3556                 :                : static int
  201 peter@eisentraut.org     3557                 :GNC       11227 : findAttrByName(const char *attributeName, const List *columns)
                               3558                 :                : {
                               3559                 :                :     ListCell   *lc;
 7263 neilc@samurai.com        3560                 :CBC       11227 :     int         i = 1;
                               3561                 :                : 
  201 peter@eisentraut.org     3562   [ +  +  +  +  :GNC       20983 :     foreach(lc, columns)
                                              +  + ]
                               3563                 :                :     {
                               3564         [ +  + ]:          10038 :         if (strcmp(attributeName, lfirst_node(ColumnDef, lc)->colname) == 0)
 8024 tgl@sss.pgh.pa.us        3565                 :CBC         282 :             return i;
                               3566                 :                : 
 7263 neilc@samurai.com        3567                 :           9756 :         i++;
                               3568                 :                :     }
 8024 tgl@sss.pgh.pa.us        3569                 :          10945 :     return 0;
                               3570                 :                : }
                               3571                 :                : 
                               3572                 :                : 
                               3573                 :                : /*
                               3574                 :                :  * SetRelationHasSubclass
                               3575                 :                :  *      Set the value of the relation's relhassubclass field in pg_class.
                               3576                 :                :  *
                               3577                 :                :  * NOTE: caller must be holding an appropriate lock on the relation.
                               3578                 :                :  * ShareUpdateExclusiveLock is sufficient.
                               3579                 :                :  *
                               3580                 :                :  * NOTE: an important side-effect of this operation is that an SI invalidation
                               3581                 :                :  * message is sent out to all backends --- including me --- causing plans
                               3582                 :                :  * referencing the relation to be rebuilt with the new list of children.
                               3583                 :                :  * This must happen even if we find that no change is needed in the pg_class
                               3584                 :                :  * row.
                               3585                 :                :  */
                               3586                 :                : void
 4608                          3587                 :           7827 : SetRelationHasSubclass(Oid relationId, bool relhassubclass)
                               3588                 :                : {
                               3589                 :                :     Relation    relationRelation;
                               3590                 :                :     HeapTuple   tuple;
                               3591                 :                :     Form_pg_class classtuple;
                               3592                 :                : 
                               3593                 :                :     /*
                               3594                 :                :      * Fetch a modifiable copy of the tuple, modify it, update pg_class.
                               3595                 :                :      */
 1910 andres@anarazel.de       3596                 :           7827 :     relationRelation = table_open(RelationRelationId, RowExclusiveLock);
 5173 rhaas@postgresql.org     3597                 :           7827 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
 8024 tgl@sss.pgh.pa.us        3598         [ -  + ]:           7827 :     if (!HeapTupleIsValid(tuple))
 7574 tgl@sss.pgh.pa.us        3599         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relationId);
 7489 tgl@sss.pgh.pa.us        3600                 :CBC        7827 :     classtuple = (Form_pg_class) GETSTRUCT(tuple);
                               3601                 :                : 
                               3602         [ +  + ]:           7827 :     if (classtuple->relhassubclass != relhassubclass)
                               3603                 :                :     {
                               3604                 :           3667 :         classtuple->relhassubclass = relhassubclass;
 2630 alvherre@alvh.no-ip.     3605                 :           3667 :         CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
                               3606                 :                :     }
                               3607                 :                :     else
                               3608                 :                :     {
                               3609                 :                :         /* no need to change tuple, but force relcache rebuild anyway */
 7369 tgl@sss.pgh.pa.us        3610                 :           4160 :         CacheInvalidateRelcacheByTuple(tuple);
                               3611                 :                :     }
                               3612                 :                : 
 8024                          3613                 :           7827 :     heap_freetuple(tuple);
 1910 andres@anarazel.de       3614                 :           7827 :     table_close(relationRelation, RowExclusiveLock);
 8024 tgl@sss.pgh.pa.us        3615                 :           7827 : }
                               3616                 :                : 
                               3617                 :                : /*
                               3618                 :                :  * CheckRelationTableSpaceMove
                               3619                 :                :  *      Check if relation can be moved to new tablespace.
                               3620                 :                :  *
                               3621                 :                :  * NOTE: The caller must hold AccessExclusiveLock on the relation.
                               3622                 :                :  *
                               3623                 :                :  * Returns true if the relation can be moved to the new tablespace; raises
                               3624                 :                :  * an error if it is not possible to do the move; returns false if the move
                               3625                 :                :  * would have no effect.
                               3626                 :                :  */
                               3627                 :                : bool
 1173 michael@paquier.xyz      3628                 :            215 : CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
                               3629                 :                : {
                               3630                 :                :     Oid         oldTableSpaceId;
                               3631                 :                : 
                               3632                 :                :     /*
                               3633                 :                :      * No work if no change in tablespace.  Note that MyDatabaseTableSpace is
                               3634                 :                :      * stored as 0.
                               3635                 :                :      */
                               3636                 :            215 :     oldTableSpaceId = rel->rd_rel->reltablespace;
                               3637         [ +  + ]:            215 :     if (newTableSpaceId == oldTableSpaceId ||
                               3638   [ +  +  +  + ]:            211 :         (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
                               3639                 :              5 :         return false;
                               3640                 :                : 
                               3641                 :                :     /*
                               3642                 :                :      * We cannot support moving mapped relations into different tablespaces.
                               3643                 :                :      * (In particular this eliminates all shared catalogs.)
                               3644                 :                :      */
                               3645   [ +  +  +  +  :            210 :     if (RelationIsMapped(rel))
                                     +  -  +  +  +  
                                           +  -  + ]
 1173 michael@paquier.xyz      3646         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3647                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               3648                 :                :                  errmsg("cannot move system relation \"%s\"",
                               3649                 :                :                         RelationGetRelationName(rel))));
                               3650                 :                : 
                               3651                 :                :     /* Cannot move a non-shared relation into pg_global */
 1173 michael@paquier.xyz      3652         [ +  + ]:CBC         210 :     if (newTableSpaceId == GLOBALTABLESPACE_OID)
                               3653         [ +  - ]:              6 :         ereport(ERROR,
                               3654                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               3655                 :                :                  errmsg("only shared relations can be placed in pg_global tablespace")));
                               3656                 :                : 
                               3657                 :                :     /*
                               3658                 :                :      * Do not allow moving temp tables of other backends ... their local
                               3659                 :                :      * buffer manager is not going to cope.
                               3660                 :                :      */
                               3661   [ +  +  -  + ]:            204 :     if (RELATION_IS_OTHER_TEMP(rel))
 1173 michael@paquier.xyz      3662         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3663                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               3664                 :                :                  errmsg("cannot move temporary tables of other sessions")));
                               3665                 :                : 
 1173 michael@paquier.xyz      3666                 :CBC         204 :     return true;
                               3667                 :                : }
                               3668                 :                : 
                               3669                 :                : /*
                               3670                 :                :  * SetRelationTableSpace
                               3671                 :                :  *      Set new reltablespace and relfilenumber in pg_class entry.
                               3672                 :                :  *
                               3673                 :                :  * newTableSpaceId is the new tablespace for the relation, and
                               3674                 :                :  * newRelFilenumber its new filenumber.  If newRelFilenumber is
                               3675                 :                :  * InvalidRelFileNumber, this field is not updated.
                               3676                 :                :  *
                               3677                 :                :  * NOTE: The caller must hold AccessExclusiveLock on the relation.
                               3678                 :                :  *
                               3679                 :                :  * The caller of this routine had better check if a relation can be
                               3680                 :                :  * moved to this new tablespace by calling CheckRelationTableSpaceMove()
                               3681                 :                :  * first, and is responsible for making the change visible with
                               3682                 :                :  * CommandCounterIncrement().
                               3683                 :                :  */
                               3684                 :                : void
                               3685                 :            102 : SetRelationTableSpace(Relation rel,
                               3686                 :                :                       Oid newTableSpaceId,
                               3687                 :                :                       RelFileNumber newRelFilenumber)
                               3688                 :                : {
                               3689                 :                :     Relation    pg_class;
                               3690                 :                :     HeapTuple   tuple;
                               3691                 :                :     Form_pg_class rd_rel;
                               3692                 :            102 :     Oid         reloid = RelationGetRelid(rel);
                               3693                 :                : 
                               3694         [ -  + ]:            102 :     Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
                               3695                 :                : 
                               3696                 :                :     /* Get a modifiable copy of the relation's pg_class row. */
                               3697                 :            102 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
                               3698                 :                : 
                               3699                 :            102 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
                               3700         [ -  + ]:            102 :     if (!HeapTupleIsValid(tuple))
 1173 michael@paquier.xyz      3701         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", reloid);
 1173 michael@paquier.xyz      3702                 :CBC         102 :     rd_rel = (Form_pg_class) GETSTRUCT(tuple);
                               3703                 :                : 
                               3704                 :                :     /* Update the pg_class row. */
                               3705                 :            204 :     rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
                               3706         [ +  + ]:            102 :         InvalidOid : newTableSpaceId;
  648 rhaas@postgresql.org     3707         [ +  + ]:            102 :     if (RelFileNumberIsValid(newRelFilenumber))
                               3708                 :             80 :         rd_rel->relfilenode = newRelFilenumber;
 1173 michael@paquier.xyz      3709                 :            102 :     CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
                               3710                 :                : 
                               3711                 :                :     /*
                               3712                 :                :      * Record dependency on tablespace.  This is only required for relations
                               3713                 :                :      * that have no physical storage.
                               3714                 :                :      */
                               3715   [ +  +  +  +  :            102 :     if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
                                     +  -  +  +  +  
                                                 + ]
                               3716                 :             15 :         changeDependencyOnTablespace(RelationRelationId, reloid,
                               3717                 :                :                                      rd_rel->reltablespace);
                               3718                 :                : 
                               3719                 :            102 :     heap_freetuple(tuple);
                               3720                 :            102 :     table_close(pg_class, RowExclusiveLock);
                               3721                 :            102 : }
                               3722                 :                : 
                               3723                 :                : /*
                               3724                 :                :  *      renameatt_check         - basic sanity checks before attribute rename
                               3725                 :                :  */
                               3726                 :                : static void
 4504 rhaas@postgresql.org     3727                 :            489 : renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
                               3728                 :                : {
                               3729                 :            489 :     char        relkind = classform->relkind;
                               3730                 :                : 
                               3731   [ +  +  +  + ]:            489 :     if (classform->reloftype && !recursing)
 5190 peter_e@gmx.net          3732         [ +  - ]:              3 :         ereport(ERROR,
                               3733                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               3734                 :                :                  errmsg("cannot rename column of typed table")));
                               3735                 :                : 
                               3736                 :                :     /*
                               3737                 :                :      * Renaming the columns of sequences or toast tables doesn't actually
                               3738                 :                :      * break anything from the system's point of view, since internal
                               3739                 :                :      * references are by attnum.  But it doesn't seem right to allow users to
                               3740                 :                :      * change names that are hardcoded into the system, hence the following
                               3741                 :                :      * restriction.
                               3742                 :                :      */
 5139 rhaas@postgresql.org     3743   [ +  +  +  + ]:            486 :     if (relkind != RELKIND_RELATION &&
                               3744         [ +  - ]:             42 :         relkind != RELKIND_VIEW &&
 4060 kgrittn@postgresql.o     3745         [ +  + ]:             42 :         relkind != RELKIND_MATVIEW &&
 5139 rhaas@postgresql.org     3746         [ +  - ]:             18 :         relkind != RELKIND_COMPOSITE_TYPE &&
 4852                          3747         [ +  - ]:             18 :         relkind != RELKIND_INDEX &&
 2277 alvherre@alvh.no-ip.     3748         [ -  + ]:             18 :         relkind != RELKIND_PARTITIONED_INDEX &&
 2685 rhaas@postgresql.org     3749         [ #  # ]:UBC           0 :         relkind != RELKIND_FOREIGN_TABLE &&
                               3750                 :                :         relkind != RELKIND_PARTITIONED_TABLE)
 5139                          3751         [ #  # ]:              0 :         ereport(ERROR,
                               3752                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               3753                 :                :                  errmsg("cannot rename columns of relation \"%s\"",
                               3754                 :                :                         NameStr(classform->relname)),
                               3755                 :                :                  errdetail_relkind_not_supported(relkind)));
                               3756                 :                : 
                               3757                 :                :     /*
                               3758                 :                :      * permissions checking.  only the owner of a class can change its schema.
                               3759                 :                :      */
  518 peter@eisentraut.org     3760         [ -  + ]:CBC         486 :     if (!object_ownercheck(RelationRelationId, myrelid, GetUserId()))
 2325 peter_e@gmx.net          3761                 :UBC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(myrelid)),
 4504 rhaas@postgresql.org     3762                 :              0 :                        NameStr(classform->relname));
 3790 rhaas@postgresql.org     3763   [ +  +  +  + ]:CBC         486 :     if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
 7574 tgl@sss.pgh.pa.us        3764         [ +  - ]:              1 :         ereport(ERROR,
                               3765                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                               3766                 :                :                  errmsg("permission denied: \"%s\" is a system catalog",
                               3767                 :                :                         NameStr(classform->relname))));
 4504 rhaas@postgresql.org     3768                 :            485 : }
                               3769                 :                : 
                               3770                 :                : /*
                               3771                 :                :  *      renameatt_internal      - workhorse for renameatt
                               3772                 :                :  *
                               3773                 :                :  * Return value is the attribute number in the 'myrelid' relation.
                               3774                 :                :  */
                               3775                 :                : static AttrNumber
                               3776                 :            270 : renameatt_internal(Oid myrelid,
                               3777                 :                :                    const char *oldattname,
                               3778                 :                :                    const char *newattname,
                               3779                 :                :                    bool recurse,
                               3780                 :                :                    bool recursing,
                               3781                 :                :                    int expected_parents,
                               3782                 :                :                    DropBehavior behavior)
                               3783                 :                : {
                               3784                 :                :     Relation    targetrelation;
                               3785                 :                :     Relation    attrelation;
                               3786                 :                :     HeapTuple   atttup;
                               3787                 :                :     Form_pg_attribute attform;
                               3788                 :                :     AttrNumber  attnum;
                               3789                 :                : 
                               3790                 :                :     /*
                               3791                 :                :      * Grab an exclusive lock on the target table, which we will NOT release
                               3792                 :                :      * until end of transaction.
                               3793                 :                :      */
                               3794                 :            270 :     targetrelation = relation_open(myrelid, AccessExclusiveLock);
                               3795                 :            270 :     renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
                               3796                 :                : 
                               3797                 :                :     /*
                               3798                 :                :      * if the 'recurse' flag is set then we are supposed to rename this
                               3799                 :                :      * attribute in all classes that inherit from 'relname' (as well as in
                               3800                 :                :      * 'relname').
                               3801                 :                :      *
                               3802                 :                :      * any permissions or problems with duplicate attributes will cause the
                               3803                 :                :      * whole transaction to abort, which is what we want -- all or nothing.
                               3804                 :                :      */
 8024 tgl@sss.pgh.pa.us        3805         [ +  + ]:            270 :     if (recurse)
                               3806                 :                :     {
                               3807                 :                :         List       *child_oids,
                               3808                 :                :                    *child_numparents;
                               3809                 :                :         ListCell   *lo,
                               3810                 :                :                    *li;
                               3811                 :                : 
                               3812                 :                :         /*
                               3813                 :                :          * we need the number of parents for each child so that the recursive
                               3814                 :                :          * calls to renameatt() can determine whether there are any parents
                               3815                 :                :          * outside the inheritance hierarchy being processed.
                               3816                 :                :          */
 5186 rhaas@postgresql.org     3817                 :            118 :         child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
                               3818                 :                :                                          &child_numparents);
                               3819                 :                : 
                               3820                 :                :         /*
                               3821                 :                :          * find_all_inheritors does the recursive search of the inheritance
                               3822                 :                :          * hierarchy, so all we have to do is process all of the relids in the
                               3823                 :                :          * list that it returns.
                               3824                 :                :          */
                               3825   [ +  -  +  +  :            355 :         forboth(lo, child_oids, li, child_numparents)
                                     +  -  +  +  +  
                                        +  +  -  +  
                                                 + ]
                               3826                 :                :         {
                               3827                 :            252 :             Oid         childrelid = lfirst_oid(lo);
                               3828                 :            252 :             int         numparents = lfirst_int(li);
                               3829                 :                : 
 7898 tgl@sss.pgh.pa.us        3830         [ +  + ]:            252 :             if (childrelid == myrelid)
 8220                          3831                 :            118 :                 continue;
                               3832                 :                :             /* note we need not recurse again */
 4891 peter_e@gmx.net          3833                 :            134 :             renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
                               3834                 :                :         }
                               3835                 :                :     }
                               3836                 :                :     else
                               3837                 :                :     {
                               3838                 :                :         /*
                               3839                 :                :          * If we are told not to recurse, there had better not be any child
                               3840                 :                :          * tables; else the rename would put them out of step.
                               3841                 :                :          *
                               3842                 :                :          * expected_parents will only be 0 if we are not already recursing.
                               3843                 :                :          */
 5186 rhaas@postgresql.org     3844   [ +  +  +  + ]:            170 :         if (expected_parents == 0 &&
 1082 alvherre@alvh.no-ip.     3845                 :             18 :             find_inheritance_children(myrelid, NoLock) != NIL)
 7574 tgl@sss.pgh.pa.us        3846         [ +  - ]:              6 :             ereport(ERROR,
                               3847                 :                :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               3848                 :                :                      errmsg("inherited column \"%s\" must be renamed in child tables too",
                               3849                 :                :                             oldattname)));
                               3850                 :                :     }
                               3851                 :                : 
                               3852                 :                :     /* rename attributes in typed tables of composite type */
 4891 peter_e@gmx.net          3853         [ +  + ]:            249 :     if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
                               3854                 :                :     {
                               3855                 :                :         List       *child_oids;
                               3856                 :                :         ListCell   *lo;
                               3857                 :                : 
                               3858                 :             12 :         child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
 2489 tgl@sss.pgh.pa.us        3859                 :             12 :                                                    RelationGetRelationName(targetrelation),
                               3860                 :                :                                                    behavior);
                               3861                 :                : 
 4891 peter_e@gmx.net          3862   [ +  +  +  +  :             12 :         foreach(lo, child_oids)
                                              +  + ]
                               3863                 :              3 :             renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
                               3864                 :                :     }
                               3865                 :                : 
 1910 andres@anarazel.de       3866                 :            246 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               3867                 :                : 
 7898 tgl@sss.pgh.pa.us        3868                 :            246 :     atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
 8024                          3869         [ +  + ]:            246 :     if (!HeapTupleIsValid(atttup))
 7574                          3870         [ +  - ]:             12 :         ereport(ERROR,
                               3871                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               3872                 :                :                  errmsg("column \"%s\" does not exist",
                               3873                 :                :                         oldattname)));
 7898                          3874                 :            234 :     attform = (Form_pg_attribute) GETSTRUCT(atttup);
                               3875                 :                : 
 7627                          3876                 :            234 :     attnum = attform->attnum;
 7284                          3877         [ -  + ]:            234 :     if (attnum <= 0)
 7574 tgl@sss.pgh.pa.us        3878         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3879                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               3880                 :                :                  errmsg("cannot rename system column \"%s\"",
                               3881                 :                :                         oldattname)));
                               3882                 :                : 
                               3883                 :                :     /*
                               3884                 :                :      * if the attribute is inherited, forbid the renaming.  if this is a
                               3885                 :                :      * top-level call to renameatt(), then expected_parents will be 0, so the
                               3886                 :                :      * effect of this code will be to prohibit the renaming if the attribute
                               3887                 :                :      * is inherited at all.  if this is a recursive call to renameatt(),
                               3888                 :                :      * expected_parents will be the number of parents the current relation has
                               3889                 :                :      * within the inheritance hierarchy being processed, so we'll prohibit the
                               3890                 :                :      * renaming only if there are additional parents from elsewhere.
                               3891                 :                :      */
 5186 rhaas@postgresql.org     3892         [ +  + ]:CBC         234 :     if (attform->attinhcount > expected_parents)
 7574 tgl@sss.pgh.pa.us        3893         [ +  - ]:             15 :         ereport(ERROR,
                               3894                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               3895                 :                :                  errmsg("cannot rename inherited column \"%s\"",
                               3896                 :                :                         oldattname)));
                               3897                 :                : 
                               3898                 :                :     /* new name should not already exist */
 3182 andrew@dunslane.net      3899                 :            219 :     (void) check_for_column_name_collision(targetrelation, newattname, false);
                               3900                 :                : 
                               3901                 :                :     /* apply the update */
 7898 tgl@sss.pgh.pa.us        3902                 :            213 :     namestrcpy(&(attform->attname), newattname);
                               3903                 :                : 
 2630 alvherre@alvh.no-ip.     3904                 :            213 :     CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
                               3905                 :                : 
 4046 rhaas@postgresql.org     3906         [ -  + ]:            213 :     InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
                               3907                 :                : 
 8024 tgl@sss.pgh.pa.us        3908                 :            213 :     heap_freetuple(atttup);
                               3909                 :                : 
 1910 andres@anarazel.de       3910                 :            213 :     table_close(attrelation, RowExclusiveLock);
                               3911                 :                : 
 2489 tgl@sss.pgh.pa.us        3912                 :            213 :     relation_close(targetrelation, NoLock); /* close rel but keep lock */
                               3913                 :                : 
 3330 alvherre@alvh.no-ip.     3914                 :            213 :     return attnum;
                               3915                 :                : }
                               3916                 :                : 
                               3917                 :                : /*
                               3918                 :                :  * Perform permissions and integrity checks before acquiring a relation lock.
                               3919                 :                :  */
                               3920                 :                : static void
 4504 rhaas@postgresql.org     3921                 :            198 : RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
                               3922                 :                :                                    void *arg)
                               3923                 :                : {
                               3924                 :                :     HeapTuple   tuple;
                               3925                 :                :     Form_pg_class form;
                               3926                 :                : 
                               3927                 :            198 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
                               3928         [ +  + ]:            198 :     if (!HeapTupleIsValid(tuple))
 4326 bruce@momjian.us         3929                 :             18 :         return;                 /* concurrently dropped */
 4504 rhaas@postgresql.org     3930                 :            180 :     form = (Form_pg_class) GETSTRUCT(tuple);
                               3931                 :            180 :     renameatt_check(relid, form, false);
                               3932                 :            176 :     ReleaseSysCache(tuple);
                               3933                 :                : }
                               3934                 :                : 
                               3935                 :                : /*
                               3936                 :                :  *      renameatt       - changes the name of an attribute in a relation
                               3937                 :                :  *
                               3938                 :                :  * The returned ObjectAddress is that of the renamed column.
                               3939                 :                :  */
                               3940                 :                : ObjectAddress
                               3941                 :            152 : renameatt(RenameStmt *stmt)
                               3942                 :                : {
                               3943                 :                :     Oid         relid;
                               3944                 :                :     AttrNumber  attnum;
                               3945                 :                :     ObjectAddress address;
                               3946                 :                : 
                               3947                 :                :     /* lock level taken here should match renameatt_internal */
                               3948                 :            152 :     relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
 2207 andres@anarazel.de       3949                 :            152 :                                      stmt->missing_ok ? RVR_MISSING_OK : 0,
                               3950                 :                :                                      RangeVarCallbackForRenameAttribute,
                               3951                 :                :                                      NULL);
                               3952                 :                : 
 4465 simon@2ndQuadrant.co     3953         [ +  + ]:            145 :     if (!OidIsValid(relid))
                               3954                 :                :     {
                               3955         [ +  - ]:             12 :         ereport(NOTICE,
                               3956                 :                :                 (errmsg("relation \"%s\" does not exist, skipping",
                               3957                 :                :                         stmt->relation->relname)));
 3330 alvherre@alvh.no-ip.     3958                 :             12 :         return InvalidObjectAddress;
                               3959                 :                :     }
                               3960                 :                : 
                               3961                 :                :     attnum =
                               3962                 :            133 :         renameatt_internal(relid,
 2489 tgl@sss.pgh.pa.us        3963                 :            133 :                            stmt->subname,    /* old att name */
                               3964                 :            133 :                            stmt->newname,    /* new att name */
 2669                          3965                 :            133 :                            stmt->relation->inh, /* recursive? */
                               3966                 :                :                            false,   /* recursing? */
                               3967                 :                :                            0,   /* expected inhcount */
                               3968                 :                :                            stmt->behavior);
                               3969                 :                : 
 3330 alvherre@alvh.no-ip.     3970                 :             91 :     ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
                               3971                 :                : 
                               3972                 :             91 :     return address;
                               3973                 :                : }
                               3974                 :                : 
                               3975                 :                : /*
                               3976                 :                :  * same logic as renameatt_internal
                               3977                 :                :  */
                               3978                 :                : static ObjectAddress
 4418 peter_e@gmx.net          3979                 :             42 : rename_constraint_internal(Oid myrelid,
                               3980                 :                :                            Oid mytypid,
                               3981                 :                :                            const char *oldconname,
                               3982                 :                :                            const char *newconname,
                               3983                 :                :                            bool recurse,
                               3984                 :                :                            bool recursing,
                               3985                 :                :                            int expected_parents)
                               3986                 :                : {
 4394                          3987                 :             42 :     Relation    targetrelation = NULL;
                               3988                 :                :     Oid         constraintOid;
                               3989                 :                :     HeapTuple   tuple;
                               3990                 :                :     Form_pg_constraint con;
                               3991                 :                :     ObjectAddress address;
                               3992                 :                : 
  534 peter@eisentraut.org     3993   [ +  +  -  + ]:             42 :     Assert(!myrelid || !mytypid);
                               3994                 :                : 
 4394 peter_e@gmx.net          3995         [ +  + ]:             42 :     if (mytypid)
                               3996                 :                :     {
                               3997                 :              3 :         constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
                               3998                 :                :     }
                               3999                 :                :     else
                               4000                 :                :     {
                               4001                 :             39 :         targetrelation = relation_open(myrelid, AccessExclusiveLock);
                               4002                 :                : 
                               4003                 :                :         /*
                               4004                 :                :          * don't tell it whether we're recursing; we allow changing typed
                               4005                 :                :          * tables here
                               4006                 :                :          */
                               4007                 :             39 :         renameatt_check(myrelid, RelationGetForm(targetrelation), false);
                               4008                 :                : 
                               4009                 :             39 :         constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
                               4010                 :                :     }
                               4011                 :                : 
 4418                          4012                 :             42 :     tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
                               4013         [ -  + ]:             42 :     if (!HeapTupleIsValid(tuple))
 4418 peter_e@gmx.net          4014         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for constraint %u",
                               4015                 :                :              constraintOid);
 4418 peter_e@gmx.net          4016                 :CBC          42 :     con = (Form_pg_constraint) GETSTRUCT(tuple);
                               4017                 :                : 
  233 alvherre@alvh.no-ip.     4018         [ +  + ]:GNC          42 :     if (myrelid &&
                               4019         [ +  + ]:             39 :         (con->contype == CONSTRAINT_CHECK ||
                               4020         [ -  + ]:              9 :          con->contype == CONSTRAINT_NOTNULL) &&
                               4021         [ +  + ]:             30 :         !con->connoinherit)
                               4022                 :                :     {
 4418 peter_e@gmx.net          4023         [ +  + ]:CBC          24 :         if (recurse)
                               4024                 :                :         {
                               4025                 :                :             List       *child_oids,
                               4026                 :                :                        *child_numparents;
                               4027                 :                :             ListCell   *lo,
                               4028                 :                :                        *li;
                               4029                 :                : 
                               4030                 :             15 :             child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
                               4031                 :                :                                              &child_numparents);
                               4032                 :                : 
                               4033   [ +  -  +  +  :             36 :             forboth(lo, child_oids, li, child_numparents)
                                     +  -  +  +  +  
                                        +  +  -  +  
                                                 + ]
                               4034                 :                :             {
                               4035                 :             21 :                 Oid         childrelid = lfirst_oid(lo);
                               4036                 :             21 :                 int         numparents = lfirst_int(li);
                               4037                 :                : 
                               4038         [ +  + ]:             21 :                 if (childrelid == myrelid)
                               4039                 :             15 :                     continue;
                               4040                 :                : 
 4394                          4041                 :              6 :                 rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
                               4042                 :                :             }
                               4043                 :                :         }
                               4044                 :                :         else
                               4045                 :                :         {
 4418                          4046   [ +  +  +  - ]:             12 :             if (expected_parents == 0 &&
 1082 alvherre@alvh.no-ip.     4047                 :              3 :                 find_inheritance_children(myrelid, NoLock) != NIL)
 4418 peter_e@gmx.net          4048         [ +  - ]:              3 :                 ereport(ERROR,
                               4049                 :                :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               4050                 :                :                          errmsg("inherited constraint \"%s\" must be renamed in child tables too",
                               4051                 :                :                                 oldconname)));
                               4052                 :                :         }
                               4053                 :                : 
                               4054         [ +  + ]:             21 :         if (con->coninhcount > expected_parents)
                               4055         [ +  - ]:              3 :             ereport(ERROR,
                               4056                 :                :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               4057                 :                :                      errmsg("cannot rename inherited constraint \"%s\"",
                               4058                 :                :                             oldconname)));
                               4059                 :                :     }
                               4060                 :                : 
                               4061         [ +  + ]:             36 :     if (con->conindid
                               4062         [ +  + ]:              9 :         && (con->contype == CONSTRAINT_PRIMARY
                               4063         [ -  + ]:              3 :             || con->contype == CONSTRAINT_UNIQUE
 4418 peter_e@gmx.net          4064         [ #  # ]:UBC           0 :             || con->contype == CONSTRAINT_EXCLUSION))
                               4065                 :                :         /* rename the index; this renames the constraint as well */
 1998 peter_e@gmx.net          4066                 :CBC           9 :         RenameRelationInternal(con->conindid, newconname, false, true);
                               4067                 :                :     else
 4418                          4068                 :             27 :         RenameConstraintById(constraintOid, newconname);
                               4069                 :                : 
 3330 alvherre@alvh.no-ip.     4070                 :             36 :     ObjectAddressSet(address, ConstraintRelationId, constraintOid);
                               4071                 :                : 
 4418 peter_e@gmx.net          4072                 :             36 :     ReleaseSysCache(tuple);
                               4073                 :                : 
 4394                          4074         [ +  + ]:             36 :     if (targetrelation)
                               4075                 :                :     {
                               4076                 :                :         /*
                               4077                 :                :          * Invalidate relcache so as others can see the new constraint name.
                               4078                 :                :          */
 1945 michael@paquier.xyz      4079                 :             33 :         CacheInvalidateRelcache(targetrelation);
                               4080                 :                : 
                               4081                 :             33 :         relation_close(targetrelation, NoLock); /* close rel but keep lock */
                               4082                 :                :     }
                               4083                 :                : 
 3330 alvherre@alvh.no-ip.     4084                 :             36 :     return address;
                               4085                 :                : }
                               4086                 :                : 
                               4087                 :                : ObjectAddress
 4418 peter_e@gmx.net          4088                 :             39 : RenameConstraint(RenameStmt *stmt)
                               4089                 :                : {
 4394                          4090                 :             39 :     Oid         relid = InvalidOid;
                               4091                 :             39 :     Oid         typid = InvalidOid;
                               4092                 :                : 
 3400 alvherre@alvh.no-ip.     4093         [ +  + ]:             39 :     if (stmt->renameType == OBJECT_DOMCONSTRAINT)
                               4094                 :                :     {
                               4095                 :                :         Relation    rel;
                               4096                 :                :         HeapTuple   tup;
                               4097                 :                : 
 2710 peter_e@gmx.net          4098                 :              3 :         typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
 1910 andres@anarazel.de       4099                 :              3 :         rel = table_open(TypeRelationId, RowExclusiveLock);
 4394 peter_e@gmx.net          4100                 :              3 :         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
                               4101         [ -  + ]:              3 :         if (!HeapTupleIsValid(tup))
 4394 peter_e@gmx.net          4102         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for type %u", typid);
 4394 peter_e@gmx.net          4103                 :CBC           3 :         checkDomainOwner(tup);
                               4104                 :              3 :         ReleaseSysCache(tup);
 1910 andres@anarazel.de       4105                 :              3 :         table_close(rel, NoLock);
                               4106                 :                :     }
                               4107                 :                :     else
                               4108                 :                :     {
                               4109                 :                :         /* lock level taken here should match rename_constraint_internal */
 4394 peter_e@gmx.net          4110                 :             36 :         relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
 2207 andres@anarazel.de       4111                 :             36 :                                          stmt->missing_ok ? RVR_MISSING_OK : 0,
                               4112                 :                :                                          RangeVarCallbackForRenameAttribute,
                               4113                 :                :                                          NULL);
 3309 bruce@momjian.us         4114         [ +  + ]:             36 :         if (!OidIsValid(relid))
                               4115                 :                :         {
                               4116         [ +  - ]:              3 :             ereport(NOTICE,
                               4117                 :                :                     (errmsg("relation \"%s\" does not exist, skipping",
                               4118                 :                :                             stmt->relation->relname)));
                               4119                 :              3 :             return InvalidObjectAddress;
                               4120                 :                :         }
                               4121                 :                :     }
                               4122                 :                : 
                               4123                 :                :     return
 4130 rhaas@postgresql.org     4124                 :             36 :         rename_constraint_internal(relid, typid,
                               4125                 :             36 :                                    stmt->subname,
                               4126                 :             36 :                                    stmt->newname,
 2669 tgl@sss.pgh.pa.us        4127         [ +  + ]:             69 :                                    (stmt->relation &&
 2489                          4128         [ +  + ]:             33 :                                     stmt->relation->inh), /* recursive? */
                               4129                 :                :                                    false,   /* recursing? */
 4130 rhaas@postgresql.org     4130                 :ECB        (36) :                                    0 /* expected inhcount */ );
                               4131                 :                : }
                               4132                 :                : 
                               4133                 :                : /*
                               4134                 :                :  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
                               4135                 :                :  * RENAME
                               4136                 :                :  */
                               4137                 :                : ObjectAddress
 4504 rhaas@postgresql.org     4138                 :CBC         255 : RenameRelation(RenameStmt *stmt)
                               4139                 :                : {
  908 alvherre@alvh.no-ip.     4140                 :            255 :     bool        is_index_stmt = stmt->renameType == OBJECT_INDEX;
                               4141                 :                :     Oid         relid;
                               4142                 :                :     ObjectAddress address;
                               4143                 :                : 
                               4144                 :                :     /*
                               4145                 :                :      * Grab an exclusive lock on the target table, index, sequence, view,
                               4146                 :                :      * materialized view, or foreign table, which we will NOT release until
                               4147                 :                :      * end of transaction.
                               4148                 :                :      *
                               4149                 :                :      * Lock level used here should match RenameRelationInternal, to avoid lock
                               4150                 :                :      * escalation.  However, because ALTER INDEX can be used with any relation
                               4151                 :                :      * type, we mustn't believe without verification.
                               4152                 :                :      */
                               4153                 :                :     for (;;)
 4465 simon@2ndQuadrant.co     4154                 :              6 :     {
                               4155                 :                :         LOCKMODE    lockmode;
                               4156                 :                :         char        relkind;
                               4157                 :                :         bool        obj_is_index;
                               4158                 :                : 
  908 alvherre@alvh.no-ip.     4159         [ +  + ]:            261 :         lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
                               4160                 :                : 
                               4161                 :            261 :         relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
                               4162                 :            261 :                                          stmt->missing_ok ? RVR_MISSING_OK : 0,
                               4163                 :                :                                          RangeVarCallbackForAlterRelation,
                               4164                 :                :                                          (void *) stmt);
                               4165                 :                : 
                               4166         [ +  + ]:            236 :         if (!OidIsValid(relid))
                               4167                 :                :         {
                               4168         [ +  - ]:              9 :             ereport(NOTICE,
                               4169                 :                :                     (errmsg("relation \"%s\" does not exist, skipping",
                               4170                 :                :                             stmt->relation->relname)));
                               4171                 :              9 :             return InvalidObjectAddress;
                               4172                 :                :         }
                               4173                 :                : 
                               4174                 :                :         /*
                               4175                 :                :          * We allow mismatched statement and object types (e.g., ALTER INDEX
                               4176                 :                :          * to rename a table), but we might've used the wrong lock level.  If
                               4177                 :                :          * that happens, retry with the correct lock level.  We don't bother
                               4178                 :                :          * if we already acquired AccessExclusiveLock with an index, however.
                               4179                 :                :          */
                               4180                 :            227 :         relkind = get_rel_relkind(relid);
                               4181   [ +  +  +  + ]:            227 :         obj_is_index = (relkind == RELKIND_INDEX ||
                               4182                 :                :                         relkind == RELKIND_PARTITIONED_INDEX);
                               4183   [ +  +  +  + ]:            227 :         if (obj_is_index || is_index_stmt == obj_is_index)
                               4184                 :                :             break;
                               4185                 :                : 
                               4186                 :              6 :         UnlockRelationOid(relid, lockmode);
                               4187                 :              6 :         is_index_stmt = obj_is_index;
                               4188                 :                :     }
                               4189                 :                : 
                               4190                 :                :     /* Do the work */
                               4191                 :            221 :     RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
                               4192                 :                : 
 3330                          4193                 :            215 :     ObjectAddressSet(address, RelationRelationId, relid);
                               4194                 :                : 
                               4195                 :            215 :     return address;
                               4196                 :                : }
                               4197                 :                : 
                               4198                 :                : /*
                               4199                 :                :  *      RenameRelationInternal - change the name of a relation
                               4200                 :                :  */
                               4201                 :                : void
 1998 peter_e@gmx.net          4202                 :            665 : RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
                               4203                 :                : {
                               4204                 :                :     Relation    targetrelation;
                               4205                 :                :     Relation    relrelation;    /* for RELATION relation */
                               4206                 :                :     HeapTuple   reltup;
                               4207                 :                :     Form_pg_class relform;
                               4208                 :                :     Oid         namespaceId;
                               4209                 :                : 
                               4210                 :                :     /*
                               4211                 :                :      * Grab a lock on the target relation, which we will NOT release until end
                               4212                 :                :      * of transaction.  We need at least a self-exclusive lock so that
                               4213                 :                :      * concurrent DDL doesn't overwrite the rename if they start updating
                               4214                 :                :      * while still seeing the old version.  The lock also guards against
                               4215                 :                :      * triggering relcache reloads in concurrent sessions, which might not
                               4216                 :                :      * handle this information changing under them.  For indexes, we can use a
                               4217                 :                :      * reduced lock level because RelationReloadIndexInfo() handles indexes
                               4218                 :                :      * specially.
                               4219                 :                :      */
                               4220         [ +  + ]:            665 :     targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
 4504 rhaas@postgresql.org     4221                 :            665 :     namespaceId = RelationGetNamespace(targetrelation);
                               4222                 :                : 
                               4223                 :                :     /*
                               4224                 :                :      * Find relation's pg_class tuple, and make sure newrelname isn't in use.
                               4225                 :                :      */
 1910 andres@anarazel.de       4226                 :            665 :     relrelation = table_open(RelationRelationId, RowExclusiveLock);
                               4227                 :                : 
 5173 rhaas@postgresql.org     4228                 :            665 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
 2489 tgl@sss.pgh.pa.us        4229         [ -  + ]:            665 :     if (!HeapTupleIsValid(reltup))  /* shouldn't happen */
 7574 tgl@sss.pgh.pa.us        4230         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
 6182 tgl@sss.pgh.pa.us        4231                 :CBC         665 :     relform = (Form_pg_class) GETSTRUCT(reltup);
                               4232                 :                : 
 8024                          4233         [ +  + ]:            665 :     if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
 7574                          4234         [ +  - ]:              6 :         ereport(ERROR,
                               4235                 :                :                 (errcode(ERRCODE_DUPLICATE_TABLE),
                               4236                 :                :                  errmsg("relation \"%s\" already exists",
                               4237                 :                :                         newrelname)));
                               4238                 :                : 
                               4239                 :                :     /*
                               4240                 :                :      * RenameRelation is careful not to believe the caller's idea of the
                               4241                 :                :      * relation kind being handled.  We don't have to worry about this, but
                               4242                 :                :      * let's not be totally oblivious to it.  We can process an index as
                               4243                 :                :      * not-an-index, but not the other way around.
                               4244                 :                :      */
  908 alvherre@alvh.no-ip.     4245   [ +  +  +  +  :            659 :     Assert(!is_index ||
                                        +  -  -  + ]
                               4246                 :                :            is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
                               4247                 :                :                         targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
                               4248                 :                : 
                               4249                 :                :     /*
                               4250                 :                :      * Update pg_class tuple with new relname.  (Scribbling on reltup is OK
                               4251                 :                :      * because it's a copy...)
                               4252                 :                :      */
 6182 tgl@sss.pgh.pa.us        4253                 :            659 :     namestrcpy(&(relform->relname), newrelname);
                               4254                 :                : 
 2630 alvherre@alvh.no-ip.     4255                 :            659 :     CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
                               4256                 :                : 
 4046 rhaas@postgresql.org     4257         [ -  + ]:            659 :     InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
                               4258                 :                :                                  InvalidOid, is_internal);
                               4259                 :                : 
 8024 tgl@sss.pgh.pa.us        4260                 :            659 :     heap_freetuple(reltup);
 1910 andres@anarazel.de       4261                 :            659 :     table_close(relrelation, RowExclusiveLock);
                               4262                 :                : 
                               4263                 :                :     /*
                               4264                 :                :      * Also rename the associated type, if any.
                               4265                 :                :      */
 6182 tgl@sss.pgh.pa.us        4266         [ +  + ]:            659 :     if (OidIsValid(targetrelation->rd_rel->reltype))
 5870                          4267                 :             77 :         RenameTypeInternal(targetrelation->rd_rel->reltype,
                               4268                 :                :                            newrelname, namespaceId);
                               4269                 :                : 
                               4270                 :                :     /*
                               4271                 :                :      * Also rename the associated constraint, if any.
                               4272                 :                :      */
 2277 alvherre@alvh.no-ip.     4273         [ +  + ]:            659 :     if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
                               4274         [ +  + ]:            359 :         targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
                               4275                 :                :     {
 5932 tgl@sss.pgh.pa.us        4276                 :            309 :         Oid         constraintId = get_index_constraint(myrelid);
                               4277                 :                : 
                               4278         [ +  + ]:            309 :         if (OidIsValid(constraintId))
                               4279                 :             18 :             RenameConstraintById(constraintId, newrelname);
                               4280                 :                :     }
                               4281                 :                : 
                               4282                 :                :     /*
                               4283                 :                :      * Close rel, but keep lock!
                               4284                 :                :      */
 8024                          4285                 :            659 :     relation_close(targetrelation, NoLock);
  963 akapila@postgresql.o     4286                 :            659 : }
                               4287                 :                : 
                               4288                 :                : /*
                               4289                 :                :  *      ResetRelRewrite - reset relrewrite
                               4290                 :                :  */
                               4291                 :                : void
                               4292                 :            206 : ResetRelRewrite(Oid myrelid)
                               4293                 :                : {
                               4294                 :                :     Relation    relrelation;    /* for RELATION relation */
                               4295                 :                :     HeapTuple   reltup;
                               4296                 :                :     Form_pg_class relform;
                               4297                 :                : 
                               4298                 :                :     /*
                               4299                 :                :      * Find relation's pg_class tuple.
                               4300                 :                :      */
                               4301                 :            206 :     relrelation = table_open(RelationRelationId, RowExclusiveLock);
                               4302                 :                : 
                               4303                 :            206 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
                               4304         [ -  + ]:            206 :     if (!HeapTupleIsValid(reltup))  /* shouldn't happen */
  963 akapila@postgresql.o     4305         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
  963 akapila@postgresql.o     4306                 :CBC         206 :     relform = (Form_pg_class) GETSTRUCT(reltup);
                               4307                 :                : 
                               4308                 :                :     /*
                               4309                 :                :      * Update pg_class tuple.
                               4310                 :                :      */
                               4311                 :            206 :     relform->relrewrite = InvalidOid;
                               4312                 :                : 
                               4313                 :            206 :     CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
                               4314                 :                : 
                               4315                 :            206 :     heap_freetuple(reltup);
                               4316                 :            206 :     table_close(relrelation, RowExclusiveLock);
 8024 tgl@sss.pgh.pa.us        4317                 :            206 : }
                               4318                 :                : 
                               4319                 :                : /*
                               4320                 :                :  * Disallow ALTER TABLE (and similar commands) when the current backend has
                               4321                 :                :  * any open reference to the target table besides the one just acquired by
                               4322                 :                :  * the calling command; this implies there's an open cursor or active plan.
                               4323                 :                :  * We need this check because our lock doesn't protect us against stomping
                               4324                 :                :  * on our own foot, only other people's feet!
                               4325                 :                :  *
                               4326                 :                :  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
                               4327                 :                :  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
                               4328                 :                :  * possibly be relaxed to only error out for certain types of alterations.
                               4329                 :                :  * But the use-case for allowing any of these things is not obvious, so we
                               4330                 :                :  * won't work hard at it for now.
                               4331                 :                :  *
                               4332                 :                :  * We also reject these commands if there are any pending AFTER trigger events
                               4333                 :                :  * for the rel.  This is certainly necessary for the rewriting variants of
                               4334                 :                :  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
                               4335                 :                :  * events would try to fetch the wrong tuples.  It might be overly cautious
                               4336                 :                :  * in other cases, but again it seems better to err on the side of paranoia.
                               4337                 :                :  *
                               4338                 :                :  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
                               4339                 :                :  * we are worried about active indexscans on the index.  The trigger-event
                               4340                 :                :  * check can be skipped, since we are doing no damage to the parent table.
                               4341                 :                :  *
                               4342                 :                :  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
                               4343                 :                :  */
                               4344                 :                : void
 5919                          4345                 :          68070 : CheckTableNotInUse(Relation rel, const char *stmt)
                               4346                 :                : {
                               4347                 :                :     int         expected_refcnt;
                               4348                 :                : 
                               4349         [ +  + ]:          68070 :     expected_refcnt = rel->rd_isnailed ? 2 : 1;
                               4350         [ +  + ]:          68070 :     if (rel->rd_refcnt != expected_refcnt)
                               4351         [ +  - ]:             12 :         ereport(ERROR,
                               4352                 :                :                 (errcode(ERRCODE_OBJECT_IN_USE),
                               4353                 :                :         /* translator: first %s is a SQL command, eg ALTER TABLE */
                               4354                 :                :                  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
                               4355                 :                :                         stmt, RelationGetRelationName(rel))));
                               4356                 :                : 
                               4357         [ +  + ]:          68058 :     if (rel->rd_rel->relkind != RELKIND_INDEX &&
 2277 alvherre@alvh.no-ip.     4358   [ +  +  +  + ]:         106631 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
 5919 tgl@sss.pgh.pa.us        4359                 :          52803 :         AfterTriggerPendingOnRel(RelationGetRelid(rel)))
                               4360         [ +  - ]:              9 :         ereport(ERROR,
                               4361                 :                :                 (errcode(ERRCODE_OBJECT_IN_USE),
                               4362                 :                :         /* translator: first %s is a SQL command, eg ALTER TABLE */
                               4363                 :                :                  errmsg("cannot %s \"%s\" because it has pending trigger events",
                               4364                 :                :                         stmt, RelationGetRelationName(rel))));
                               4365                 :          68049 : }
                               4366                 :                : 
                               4367                 :                : /*
                               4368                 :                :  * AlterTableLookupRelation
                               4369                 :                :  *      Look up, and lock, the OID for the relation named by an alter table
                               4370                 :                :  *      statement.
                               4371                 :                :  */
                               4372                 :                : Oid
 4482 rhaas@postgresql.org     4373                 :          17109 : AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
                               4374                 :                : {
 2207 andres@anarazel.de       4375                 :          34176 :     return RangeVarGetRelidExtended(stmt->relation, lockmode,
                               4376                 :          17109 :                                     stmt->missing_ok ? RVR_MISSING_OK : 0,
                               4377                 :                :                                     RangeVarCallbackForAlterRelation,
                               4378                 :                :                                     (void *) stmt);
                               4379                 :                : }
                               4380                 :                : 
                               4381                 :                : /*
                               4382                 :                :  * AlterTable
                               4383                 :                :  *      Execute ALTER TABLE, which can be a list of subcommands
                               4384                 :                :  *
                               4385                 :                :  * ALTER TABLE is performed in three phases:
                               4386                 :                :  *      1. Examine subcommands and perform pre-transformation checking.
                               4387                 :                :  *      2. Validate and transform subcommands, and update system catalogs.
                               4388                 :                :  *      3. Scan table(s) to check new constraints, and optionally recopy
                               4389                 :                :  *         the data into new table(s).
                               4390                 :                :  * Phase 3 is not performed unless one or more of the subcommands requires
                               4391                 :                :  * it.  The intention of this design is to allow multiple independent
                               4392                 :                :  * updates of the table schema to be performed with only one pass over the
                               4393                 :                :  * data.
                               4394                 :                :  *
                               4395                 :                :  * ATPrepCmd performs phase 1.  A "work queue" entry is created for
                               4396                 :                :  * each table to be affected (there may be multiple affected tables if the
                               4397                 :                :  * commands traverse a table inheritance hierarchy).  Also we do preliminary
                               4398                 :                :  * validation of the subcommands.  Because earlier subcommands may change
                               4399                 :                :  * the catalog state seen by later commands, there are limits to what can
                               4400                 :                :  * be done in this phase.  Generally, this phase acquires table locks,
                               4401                 :                :  * checks permissions and relkind, and recurses to find child tables.
                               4402                 :                :  *
                               4403                 :                :  * ATRewriteCatalogs performs phase 2 for each affected table.
                               4404                 :                :  * Certain subcommands need to be performed before others to avoid
                               4405                 :                :  * unnecessary conflicts; for example, DROP COLUMN should come before
                               4406                 :                :  * ADD COLUMN.  Therefore phase 1 divides the subcommands into multiple
                               4407                 :                :  * lists, one for each logical "pass" of phase 2.
                               4408                 :                :  *
                               4409                 :                :  * ATRewriteTables performs phase 3 for those tables that need it.
                               4410                 :                :  *
                               4411                 :                :  * For most subcommand types, phases 2 and 3 do no explicit recursion,
                               4412                 :                :  * since phase 1 already does it.  However, for certain subcommand types
                               4413                 :                :  * it is only possible to determine how to recurse at phase 2 time; for
                               4414                 :                :  * those cases, phase 1 sets the cmd->recurse flag.
                               4415                 :                :  *
                               4416                 :                :  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
                               4417                 :                :  * the whole operation; we don't have to do anything special to clean up.
                               4418                 :                :  *
                               4419                 :                :  * The caller must lock the relation, with an appropriate lock level
                               4420                 :                :  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
                               4421                 :                :  * or higher. We pass the lock level down
                               4422                 :                :  * so that we can apply it recursively to inherited tables. Note that the
                               4423                 :                :  * lock level we want as we recurse might well be higher than required for
                               4424                 :                :  * that specific subcommand. So we pass down the overall lock requirement,
                               4425                 :                :  * rather than reassess it at lower levels.
                               4426                 :                :  *
                               4427                 :                :  * The caller also provides a "context" which is to be passed back to
                               4428                 :                :  * utility.c when we need to execute a subcommand such as CREATE INDEX.
                               4429                 :                :  * Some of the fields therein, such as the relid, are used here as well.
                               4430                 :                :  */
                               4431                 :                : void
 1551 tgl@sss.pgh.pa.us        4432                 :          16998 : AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
                               4433                 :                :            AlterTableUtilityContext *context)
                               4434                 :                : {
                               4435                 :                :     Relation    rel;
                               4436                 :                : 
                               4437                 :                :     /* Caller is required to provide an adequate lock. */
                               4438                 :          16998 :     rel = relation_open(context->relid, NoLock);
                               4439                 :                : 
 5919                          4440                 :          16998 :     CheckTableNotInUse(rel, "ALTER TABLE");
                               4441                 :                : 
 1551                          4442                 :          16989 :     ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
 5947                          4443                 :          15376 : }
                               4444                 :                : 
                               4445                 :                : /*
                               4446                 :                :  * AlterTableInternal
                               4447                 :                :  *
                               4448                 :                :  * ALTER TABLE with target specified by OID
                               4449                 :                :  *
                               4450                 :                :  * We do not reject if the relation is already open, because it's quite
                               4451                 :                :  * likely that one or more layers of caller have it open.  That means it
                               4452                 :                :  * is unsafe to use this entry point for alterations that could break
                               4453                 :                :  * existing query plans.  On the assumption it's not used for such, we
                               4454                 :                :  * don't have to reject pending AFTER triggers, either.
                               4455                 :                :  *
                               4456                 :                :  * Also, since we don't have an AlterTableUtilityContext, this cannot be
                               4457                 :                :  * used for any subcommand types that require parse transformation or
                               4458                 :                :  * could generate subcommands that have to be passed to ProcessUtility.
                               4459                 :                :  */
                               4460                 :                : void
 7284                          4461                 :            139 : AlterTableInternal(Oid relid, List *cmds, bool recurse)
                               4462                 :                : {
                               4463                 :                :     Relation    rel;
 4753 bruce@momjian.us         4464                 :            139 :     LOCKMODE    lockmode = AlterTableGetLockLevel(cmds);
                               4465                 :                : 
 5009 simon@2ndQuadrant.co     4466                 :            139 :     rel = relation_open(relid, lockmode);
                               4467                 :                : 
 3261 alvherre@alvh.no-ip.     4468                 :            139 :     EventTriggerAlterTableRelid(relid);
                               4469                 :                : 
 1551 tgl@sss.pgh.pa.us        4470                 :            139 :     ATController(NULL, rel, cmds, recurse, lockmode, NULL);
 5009 simon@2ndQuadrant.co     4471                 :            139 : }
                               4472                 :                : 
                               4473                 :                : /*
                               4474                 :                :  * AlterTableGetLockLevel
                               4475                 :                :  *
                               4476                 :                :  * Sets the overall lock level required for the supplied list of subcommands.
                               4477                 :                :  * Policy for doing this set according to needs of AlterTable(), see
                               4478                 :                :  * comments there for overall explanation.
                               4479                 :                :  *
                               4480                 :                :  * Function is called before and after parsing, so it must give same
                               4481                 :                :  * answer each time it is called. Some subcommands are transformed
                               4482                 :                :  * into other subcommand types, so the transform must never be made to a
                               4483                 :                :  * lower lock level than previously assigned. All transforms are noted below.
                               4484                 :                :  *
                               4485                 :                :  * Since this is called before we lock the table we cannot use table metadata
                               4486                 :                :  * to influence the type of lock we acquire.
                               4487                 :                :  *
                               4488                 :                :  * There should be no lockmodes hardcoded into the subcommand functions. All
                               4489                 :                :  * lockmode decisions for ALTER TABLE are made here only. The one exception is
                               4490                 :                :  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
                               4491                 :                :  * and does not travel through this section of code and cannot be combined with
                               4492                 :                :  * any of the subcommands given here.
                               4493                 :                :  *
                               4494                 :                :  * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
                               4495                 :                :  * so any changes that might affect SELECTs running on standbys need to use
                               4496                 :                :  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
                               4497                 :                :  * have a solution for that also.
                               4498                 :                :  *
                               4499                 :                :  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
                               4500                 :                :  * that takes a lock less than AccessExclusiveLock can change object definitions
                               4501                 :                :  * while pg_dump is running. Be careful to check that the appropriate data is
                               4502                 :                :  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
                               4503                 :                :  * otherwise we might end up with an inconsistent dump that can't restore.
                               4504                 :                :  */
                               4505                 :                : LOCKMODE
                               4506                 :          17248 : AlterTableGetLockLevel(List *cmds)
                               4507                 :                : {
                               4508                 :                :     /*
                               4509                 :                :      * This only works if we read catalog tables using MVCC snapshots.
                               4510                 :                :      */
                               4511                 :                :     ListCell   *lcmd;
 4753 bruce@momjian.us         4512                 :          17248 :     LOCKMODE    lockmode = ShareUpdateExclusiveLock;
                               4513                 :                : 
 5009 simon@2ndQuadrant.co     4514   [ +  -  +  +  :          35472 :     foreach(lcmd, cmds)
                                              +  + ]
                               4515                 :                :     {
                               4516                 :          18224 :         AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
 4753 bruce@momjian.us         4517                 :          18224 :         LOCKMODE    cmd_lockmode = AccessExclusiveLock; /* default for compiler */
                               4518                 :                : 
 5009 simon@2ndQuadrant.co     4519   [ +  +  +  +  :          18224 :         switch (cmd->subtype)
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                           +  +  - ]
                               4520                 :                :         {
                               4521                 :                :                 /*
                               4522                 :                :                  * These subcommands rewrite the heap, so require full locks.
                               4523                 :                :                  */
 4753 bruce@momjian.us         4524                 :           1606 :             case AT_AddColumn:  /* may rewrite heap, in some cases and visible
                               4525                 :                :                                  * to SELECT */
                               4526                 :                :             case AT_SetAccessMethod:    /* must rewrite heap */
                               4527                 :                :             case AT_SetTableSpace:  /* must rewrite heap */
                               4528                 :                :             case AT_AlterColumnType:    /* must rewrite heap */
 3661 simon@2ndQuadrant.co     4529                 :           1606 :                 cmd_lockmode = AccessExclusiveLock;
                               4530                 :           1606 :                 break;
                               4531                 :                : 
                               4532                 :                :                 /*
                               4533                 :                :                  * These subcommands may require addition of toast tables. If
                               4534                 :                :                  * we add a toast table to a table currently being scanned, we
                               4535                 :                :                  * might miss data added to the new toast table by concurrent
                               4536                 :                :                  * insert transactions.
                               4537                 :                :                  */
 2489 tgl@sss.pgh.pa.us        4538                 :            106 :             case AT_SetStorage: /* may add toast tables, see
                               4539                 :                :                                  * ATRewriteCatalogs() */
 3661 simon@2ndQuadrant.co     4540                 :            106 :                 cmd_lockmode = AccessExclusiveLock;
                               4541                 :            106 :                 break;
                               4542                 :                : 
                               4543                 :                :                 /*
                               4544                 :                :                  * Removing constraints can affect SELECTs that have been
                               4545                 :                :                  * optimized assuming the constraint holds true. See also
                               4546                 :                :                  * CloneFkReferenced.
                               4547                 :                :                  */
 2489 tgl@sss.pgh.pa.us        4548                 :            614 :             case AT_DropConstraint: /* as DROP INDEX */
                               4549                 :                :             case AT_DropNotNull:    /* may change some SQL plans */
 3661 simon@2ndQuadrant.co     4550                 :            614 :                 cmd_lockmode = AccessExclusiveLock;
                               4551                 :            614 :                 break;
                               4552                 :                : 
                               4553                 :                :                 /*
                               4554                 :                :                  * Subcommands that may be visible to concurrent SELECTs
                               4555                 :                :                  */
 2489 tgl@sss.pgh.pa.us        4556                 :            855 :             case AT_DropColumn: /* change visible to SELECT */
                               4557                 :                :             case AT_AddColumnToView:    /* CREATE VIEW */
                               4558                 :                :             case AT_DropOids:   /* used to equiv to DropColumn */
                               4559                 :                :             case AT_EnableAlwaysRule:   /* may change SELECT rules */
                               4560                 :                :             case AT_EnableReplicaRule:  /* may change SELECT rules */
                               4561                 :                :             case AT_EnableRule: /* may change SELECT rules */
                               4562                 :                :             case AT_DisableRule:    /* may change SELECT rules */
 3661 simon@2ndQuadrant.co     4563                 :            855 :                 cmd_lockmode = AccessExclusiveLock;
                               4564                 :            855 :                 break;
                               4565                 :                : 
                               4566                 :                :                 /*
                               4567                 :                :                  * Changing owner may remove implicit SELECT privileges
                               4568                 :                :                  */
 2489 tgl@sss.pgh.pa.us        4569                 :            910 :             case AT_ChangeOwner:    /* change visible to SELECT */
 3661 simon@2ndQuadrant.co     4570                 :            910 :                 cmd_lockmode = AccessExclusiveLock;
                               4571                 :            910 :                 break;
                               4572                 :                : 
                               4573                 :                :                 /*
                               4574                 :                :                  * Changing foreign table options may affect optimization.
                               4575                 :                :                  */
 4852 rhaas@postgresql.org     4576                 :            119 :             case AT_GenericOptions:
                               4577                 :                :             case AT_AlterColumnGenericOptions:
 5009 simon@2ndQuadrant.co     4578                 :            119 :                 cmd_lockmode = AccessExclusiveLock;
                               4579                 :            119 :                 break;
                               4580                 :                : 
                               4581                 :                :                 /*
                               4582                 :                :                  * These subcommands affect write operations only.
                               4583                 :                :                  */
                               4584                 :            170 :             case AT_EnableTrig:
                               4585                 :                :             case AT_EnableAlwaysTrig:
                               4586                 :                :             case AT_EnableReplicaTrig:
                               4587                 :                :             case AT_EnableTrigAll:
                               4588                 :                :             case AT_EnableTrigUser:
                               4589                 :                :             case AT_DisableTrig:
                               4590                 :                :             case AT_DisableTrigAll:
                               4591                 :                :             case AT_DisableTrigUser:
 3297                          4592                 :            170 :                 cmd_lockmode = ShareRowExclusiveLock;
                               4593                 :            170 :                 break;
                               4594                 :                : 
                               4595                 :                :                 /*
                               4596                 :                :                  * These subcommands affect write operations only. XXX
                               4597                 :                :                  * Theoretically, these could be ShareRowExclusiveLock.
                               4598                 :                :                  */
                               4599                 :           4766 :             case AT_ColumnDefault:
                               4600                 :                :             case AT_CookedColumnDefault:
                               4601                 :                :             case AT_AlterConstraint:
                               4602                 :                :             case AT_AddIndex:   /* from ADD CONSTRAINT */
                               4603                 :                :             case AT_AddIndexConstraint:
                               4604                 :                :             case AT_ReplicaIdentity:
                               4605                 :                :             case AT_SetNotNull:
                               4606                 :                :             case AT_SetAttNotNull:
                               4607                 :                :             case AT_EnableRowSecurity:
                               4608                 :                :             case AT_DisableRowSecurity:
                               4609                 :                :             case AT_ForceRowSecurity:
                               4610                 :                :             case AT_NoForceRowSecurity:
                               4611                 :                :             case AT_AddIdentity:
                               4612                 :                :             case AT_DropIdentity:
                               4613                 :                :             case AT_SetIdentity:
                               4614                 :                :             case AT_SetExpression:
                               4615                 :                :             case AT_DropExpression:
                               4616                 :                :             case AT_SetCompression:
 3661                          4617                 :           4766 :                 cmd_lockmode = AccessExclusiveLock;
 5009                          4618                 :           4766 :                 break;
                               4619                 :                : 
                               4620                 :           6283 :             case AT_AddConstraint:
                               4621                 :                :             case AT_ReAddConstraint:    /* becomes AT_AddConstraint */
                               4622                 :                :             case AT_ReAddDomainConstraint:  /* becomes AT_AddConstraint */
                               4623         [ +  - ]:           6283 :                 if (IsA(cmd->def, Constraint))
                               4624                 :                :                 {
                               4625                 :           6283 :                     Constraint *con = (Constraint *) cmd->def;
                               4626                 :                : 
                               4627      [ +  +  + ]:           6283 :                     switch (con->contype)
                               4628                 :                :                     {
                               4629                 :           4629 :                         case CONSTR_EXCLUSION:
                               4630                 :                :                         case CONSTR_PRIMARY:
                               4631                 :                :                         case CONSTR_UNIQUE:
                               4632                 :                : 
                               4633                 :                :                             /*
                               4634                 :                :                              * Cases essentially the same as CREATE INDEX. We
                               4635                 :                :                              * could reduce the lock strength to ShareLock if
                               4636                 :                :                              * we can work out how to allow concurrent catalog
                               4637                 :                :                              * updates. XXX Might be set down to
                               4638                 :                :                              * ShareRowExclusiveLock but requires further
                               4639                 :                :                              * analysis.
                               4640                 :                :                              */
 3661                          4641                 :           4629 :                             cmd_lockmode = AccessExclusiveLock;
 5009                          4642                 :           4629 :                             break;
                               4643                 :           1193 :                         case CONSTR_FOREIGN:
                               4644                 :                : 
                               4645                 :                :                             /*
                               4646                 :                :                              * We add triggers to both tables when we add a
                               4647                 :                :                              * Foreign Key, so the lock level must be at least
                               4648                 :                :                              * as strong as CREATE TRIGGER.
                               4649                 :                :                              */
 3297                          4650                 :           1193 :                             cmd_lockmode = ShareRowExclusiveLock;
 5009                          4651                 :           1193 :                             break;
                               4652                 :                : 
                               4653                 :            461 :                         default:
 3661                          4654                 :            461 :                             cmd_lockmode = AccessExclusiveLock;
                               4655                 :                :                     }
                               4656                 :                :                 }
 5009                          4657                 :           6283 :                 break;
                               4658                 :                : 
                               4659                 :                :                 /*
                               4660                 :                :                  * These subcommands affect inheritance behaviour. Queries
                               4661                 :                :                  * started before us will continue to see the old inheritance
                               4662                 :                :                  * behaviour, while queries started after we commit will see
                               4663                 :                :                  * new behaviour. No need to prevent reads or writes to the
                               4664                 :                :                  * subtable while we hook it up though. Changing the TupDesc
                               4665                 :                :                  * may be a problem, so keep highest lock.
                               4666                 :                :                  */
                               4667                 :            185 :             case AT_AddInherit:
                               4668                 :                :             case AT_DropInherit:
 3661                          4669                 :            185 :                 cmd_lockmode = AccessExclusiveLock;
 5009                          4670                 :            185 :                 break;
                               4671                 :                : 
                               4672                 :                :                 /*
                               4673                 :                :                  * These subcommands affect implicit row type conversion. They
                               4674                 :                :                  * have affects similar to CREATE/DROP CAST on queries. don't
                               4675                 :                :                  * provide for invalidating parse trees as a result of such
                               4676                 :                :                  * changes, so we keep these at AccessExclusiveLock.
                               4677                 :                :                  */
 4743 rhaas@postgresql.org     4678                 :             36 :             case AT_AddOf:
                               4679                 :                :             case AT_DropOf:
 3661 simon@2ndQuadrant.co     4680                 :             36 :                 cmd_lockmode = AccessExclusiveLock;
                               4681                 :             36 :                 break;
                               4682                 :                : 
                               4683                 :                :                 /*
                               4684                 :                :                  * Only used by CREATE OR REPLACE VIEW which must conflict
                               4685                 :                :                  * with an SELECTs currently using the view.
                               4686                 :                :                  */
                               4687                 :             97 :             case AT_ReplaceRelOptions:
                               4688                 :             97 :                 cmd_lockmode = AccessExclusiveLock;
                               4689                 :             97 :                 break;
                               4690                 :                : 
                               4691                 :                :                 /*
                               4692                 :                :                  * These subcommands affect general strategies for performance
                               4693                 :                :                  * and maintenance, though don't change the semantic results
                               4694                 :                :                  * from normal data reads and writes. Delaying an ALTER TABLE
                               4695                 :                :                  * behind currently active writes only delays the point where
                               4696                 :                :                  * the new strategy begins to take effect, so there is no
                               4697                 :                :                  * benefit in waiting. In this case the minimum restriction
                               4698                 :                :                  * applies: we don't currently allow concurrent catalog
                               4699                 :                :                  * updates.
                               4700                 :                :                  */
 2489 tgl@sss.pgh.pa.us        4701                 :            117 :             case AT_SetStatistics:  /* Uses MVCC in getTableAttrs() */
                               4702                 :                :             case AT_ClusterOn:  /* Uses MVCC in getIndexes() */
                               4703                 :                :             case AT_DropCluster:    /* Uses MVCC in getIndexes() */
                               4704                 :                :             case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
                               4705                 :                :             case AT_ResetOptions:   /* Uses MVCC in getTableAttrs() */
 5009 simon@2ndQuadrant.co     4706                 :            117 :                 cmd_lockmode = ShareUpdateExclusiveLock;
                               4707                 :            117 :                 break;
                               4708                 :                : 
 3523 alvherre@alvh.no-ip.     4709                 :             44 :             case AT_SetLogged:
                               4710                 :                :             case AT_SetUnLogged:
                               4711                 :             44 :                 cmd_lockmode = AccessExclusiveLock;
                               4712                 :             44 :                 break;
                               4713                 :                : 
 2489 tgl@sss.pgh.pa.us        4714                 :            194 :             case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
 3661 simon@2ndQuadrant.co     4715                 :            194 :                 cmd_lockmode = ShareUpdateExclusiveLock;
                               4716                 :            194 :                 break;
                               4717                 :                : 
                               4718                 :                :                 /*
                               4719                 :                :                  * Rel options are more complex than first appears. Options
                               4720                 :                :                  * are set here for tables, views and indexes; for historical
                               4721                 :                :                  * reasons these can all be used with ALTER TABLE, so we can't
                               4722                 :                :                  * decide between them using the basic grammar.
                               4723                 :                :                  */
 2489 tgl@sss.pgh.pa.us        4724                 :            370 :             case AT_SetRelOptions:  /* Uses MVCC in getIndexes() and
                               4725                 :                :                                      * getTables() */
                               4726                 :                :             case AT_ResetRelOptions:    /* Uses MVCC in getIndexes() and
                               4727                 :                :                                          * getTables() */
 3166 simon@2ndQuadrant.co     4728                 :            370 :                 cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
 3661                          4729                 :            370 :                 break;
                               4730                 :                : 
 2685 rhaas@postgresql.org     4731                 :           1295 :             case AT_AttachPartition:
 1865                          4732                 :           1295 :                 cmd_lockmode = ShareUpdateExclusiveLock;
                               4733                 :           1295 :                 break;
                               4734                 :                : 
 2685                          4735                 :            264 :             case AT_DetachPartition:
 1116 alvherre@alvh.no-ip.     4736         [ +  + ]:            264 :                 if (((PartitionCmd *) cmd->def)->concurrent)
                               4737                 :             79 :                     cmd_lockmode = ShareUpdateExclusiveLock;
                               4738                 :                :                 else
                               4739                 :            185 :                     cmd_lockmode = AccessExclusiveLock;
                               4740                 :            264 :                 break;
                               4741                 :                : 
                               4742                 :              7 :             case AT_DetachPartitionFinalize:
                               4743                 :              7 :                 cmd_lockmode = ShareUpdateExclusiveLock;
 2685 rhaas@postgresql.org     4744                 :              7 :                 break;
                               4745                 :                : 
    7 akorotkov@postgresql     4746                 :GNC         126 :             case AT_SplitPartition:
                               4747                 :            126 :                 cmd_lockmode = AccessExclusiveLock;
                               4748                 :            126 :                 break;
                               4749                 :                : 
                               4750                 :             60 :             case AT_MergePartitions:
                               4751                 :             60 :                 cmd_lockmode = AccessExclusiveLock;
    7 akorotkov@postgresql     4752                 :GBC          60 :                 break;
                               4753                 :                : 
 4753 bruce@momjian.us         4754                 :UBC           0 :             default:            /* oops */
 5009 simon@2ndQuadrant.co     4755         [ #  # ]:              0 :                 elog(ERROR, "unrecognized alter table type: %d",
                               4756                 :                :                      (int) cmd->subtype);
                               4757                 :                :                 break;
                               4758                 :                :         }
                               4759                 :                : 
                               4760                 :                :         /*
                               4761                 :                :          * Take the greatest lockmode from any subcommand
                               4762                 :                :          */
 5009 simon@2ndQuadrant.co     4763         [ +  + ]:CBC       18224 :         if (cmd_lockmode > lockmode)
                               4764                 :          15279 :             lockmode = cmd_lockmode;
                               4765                 :                :     }
                               4766                 :                : 
                               4767                 :          17248 :     return lockmode;
                               4768                 :                : }
                               4769                 :                : 
                               4770                 :                : /*
                               4771                 :                :  * ATController provides top level control over the phases.
                               4772                 :                :  *
                               4773                 :                :  * parsetree is passed in to allow it to be passed to event triggers
                               4774                 :                :  * when requested.
                               4775                 :                :  */
                               4776                 :                : static void
 3415                          4777                 :          17128 : ATController(AlterTableStmt *parsetree,
                               4778                 :                :              Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
                               4779                 :                :              AlterTableUtilityContext *context)
                               4780                 :                : {
 7284 tgl@sss.pgh.pa.us        4781                 :          17128 :     List       *wqueue = NIL;
                               4782                 :                :     ListCell   *lcmd;
                               4783                 :                : 
                               4784                 :                :     /* Phase 1: preliminary examination of commands, create work queue */
                               4785   [ +  -  +  +  :          35093 :     foreach(lcmd, cmds)
                                              +  + ]
                               4786                 :                :     {
                               4787                 :          18101 :         AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
                               4788                 :                : 
 1551                          4789                 :          18101 :         ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
                               4790                 :                :     }
                               4791                 :                : 
                               4792                 :                :     /* Close the relation, but keep lock until commit */
 7284                          4793                 :          16992 :     relation_close(rel, NoLock);
                               4794                 :                : 
                               4795                 :                :     /* Phase 2: update system catalogs */
 1551                          4796                 :          16992 :     ATRewriteCatalogs(&wqueue, lockmode, context);
                               4797                 :                : 
                               4798                 :                :     /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
                               4799                 :          15677 :     ATRewriteTables(parsetree, &wqueue, lockmode, context);
 7284                          4800                 :          15515 : }
                               4801                 :                : 
                               4802                 :                : /*
                               4803                 :                :  * ATPrepCmd
                               4804                 :                :  *
                               4805                 :                :  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
                               4806                 :                :  * recursion and permission checks.
                               4807                 :                :  *
                               4808                 :                :  * Caller must have acquired appropriate lock type on relation already.
                               4809                 :                :  * This lock should be held until commit.
                               4810                 :                :  */
                               4811                 :                : static void
                               4812                 :          18412 : ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
                               4813                 :                :           bool recurse, bool recursing, LOCKMODE lockmode,
                               4814                 :                :           AlterTableUtilityContext *context)
                               4815                 :                : {
                               4816                 :                :     AlteredTableInfo *tab;
  104 peter@eisentraut.org     4817                 :GNC       18412 :     AlterTablePass pass = AT_PASS_UNSET;
                               4818                 :                : 
                               4819                 :                :     /* Find or create work queue entry for this table */
 7284 tgl@sss.pgh.pa.us        4820                 :CBC       18412 :     tab = ATGetQueueEntry(wqueue, rel);
                               4821                 :                : 
                               4822                 :                :     /*
                               4823                 :                :      * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
                               4824                 :                :      * partitions that are pending detach.
                               4825                 :                :      */
 1116 alvherre@alvh.no-ip.     4826         [ +  + ]:          18412 :     if (rel->rd_rel->relispartition &&
                               4827   [ +  -  +  + ]:           1284 :         cmd->subtype != AT_DetachPartitionFinalize &&
                               4828                 :            642 :         PartitionHasPendingDetach(RelationGetRelid(rel)))
                               4829         [ +  - ]:              1 :         ereport(ERROR,
                               4830                 :                :                 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               4831                 :                :                 errmsg("cannot alter partition \"%s\" with an incomplete detach",
                               4832                 :                :                        RelationGetRelationName(rel)),
                               4833                 :                :                 errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
                               4834                 :                : 
                               4835                 :                :     /*
                               4836                 :                :      * Copy the original subcommand for each table, so we can scribble on it.
                               4837                 :                :      * This avoids conflicts when different child tables need to make
                               4838                 :                :      * different parse transformations (for example, the same column may have
                               4839                 :                :      * different column numbers in different children).
                               4840                 :                :      */
 7284 tgl@sss.pgh.pa.us        4841                 :          18411 :     cmd = copyObject(cmd);
                               4842                 :                : 
                               4843                 :                :     /*
                               4844                 :                :      * Do permissions and relkind checking, recursion to child tables if
                               4845                 :                :      * needed, and any additional phase-1 processing needed.  (But beware of
                               4846                 :                :      * adding any processing that looks at table details that another
                               4847                 :                :      * subcommand could change.  In some cases we reject multiple subcommands
                               4848                 :                :      * that could try to change the same state in contrary ways.)
                               4849                 :                :      */
                               4850   [ +  +  +  +  :          18411 :     switch (cmd->subtype)
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  -  +  
                                     -  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                                 - ]
                               4851                 :                :     {
                               4852                 :            978 :         case AT_AddColumn:      /* ADD COLUMN */
 1011 peter@eisentraut.org     4853                 :            978 :             ATSimplePermissions(cmd->subtype, rel,
                               4854                 :                :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
 3334 alvherre@alvh.no-ip.     4855                 :            978 :             ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
                               4856                 :                :                             lockmode, context);
                               4857                 :                :             /* Recursion occurs during execution phase */
 7284 tgl@sss.pgh.pa.us        4858                 :            972 :             pass = AT_PASS_ADD_COL;
                               4859                 :            972 :             break;
 2489                          4860                 :             12 :         case AT_AddColumnToView:    /* add column via CREATE OR REPLACE VIEW */
 1011 peter@eisentraut.org     4861                 :             12 :             ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
 3334 alvherre@alvh.no-ip.     4862                 :             12 :             ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
                               4863                 :                :                             lockmode, context);
                               4864                 :                :             /* Recursion occurs during execution phase */
 5608 bruce@momjian.us         4865                 :             12 :             pass = AT_PASS_ADD_COL;
                               4866                 :             12 :             break;
 7284 tgl@sss.pgh.pa.us        4867                 :            295 :         case AT_ColumnDefault:  /* ALTER COLUMN DEFAULT */
                               4868                 :                : 
                               4869                 :                :             /*
                               4870                 :                :              * We allow defaults on views so that INSERT into a view can have
                               4871                 :                :              * default-ish behavior.  This works because the rewriter
                               4872                 :                :              * substitutes default values into INSERTs before it expands
                               4873                 :                :              * rules.
                               4874                 :                :              */
 1011 peter@eisentraut.org     4875                 :            295 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
 1551 tgl@sss.pgh.pa.us        4876                 :            295 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
                               4877                 :                :             /* No command-specific prep needed */
                               4878         [ +  + ]:            295 :             pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
 7284                          4879                 :            295 :             break;
 1332                          4880                 :             55 :         case AT_CookedColumnDefault:    /* add a pre-cooked default */
                               4881                 :                :             /* This is currently used only in CREATE TABLE */
                               4882                 :                :             /* (so the permission check really isn't necessary) */
 1011 peter@eisentraut.org     4883                 :             55 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4884                 :                :             /* This command never recurses */
 1332 tgl@sss.pgh.pa.us        4885                 :             55 :             pass = AT_PASS_ADD_OTHERCONSTR;
                               4886                 :             55 :             break;
 2565 peter_e@gmx.net          4887                 :             77 :         case AT_AddIdentity:
 1011 peter@eisentraut.org     4888                 :             77 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
                               4889                 :                :             /* Set up recursion for phase 2; no other prep needed */
   89 peter@eisentraut.org     4890         [ +  + ]:GNC          77 :             if (recurse)
                               4891                 :             74 :                 cmd->recurse = true;
 1551 tgl@sss.pgh.pa.us        4892                 :CBC          77 :             pass = AT_PASS_ADD_OTHERCONSTR;
 2565 peter_e@gmx.net          4893                 :             77 :             break;
                               4894                 :             31 :         case AT_SetIdentity:
 1011 peter@eisentraut.org     4895                 :             31 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
                               4896                 :                :             /* Set up recursion for phase 2; no other prep needed */
   89 peter@eisentraut.org     4897         [ +  + ]:GNC          31 :             if (recurse)
                               4898                 :             28 :                 cmd->recurse = true;
                               4899                 :                :             /* This should run after AddIdentity, so do it in MISC pass */
 1551 tgl@sss.pgh.pa.us        4900                 :CBC          31 :             pass = AT_PASS_MISC;
 2565 peter_e@gmx.net          4901                 :             31 :             break;
 1727 alvherre@alvh.no-ip.     4902                 :             28 :         case AT_DropIdentity:
 1011 peter@eisentraut.org     4903                 :             28 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
                               4904                 :                :             /* Set up recursion for phase 2; no other prep needed */
   89 peter@eisentraut.org     4905         [ +  + ]:GNC          28 :             if (recurse)
                               4906                 :             25 :                 cmd->recurse = true;
 1727 alvherre@alvh.no-ip.     4907                 :CBC          28 :             pass = AT_PASS_DROP;
                               4908                 :             28 :             break;
 7284 tgl@sss.pgh.pa.us        4909                 :            122 :         case AT_DropNotNull:    /* ALTER COLUMN DROP NOT NULL */
 1011 peter@eisentraut.org     4910                 :            122 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4911                 :                :             /* Set up recursion for phase 2; no other prep needed */
  233 alvherre@alvh.no-ip.     4912         [ +  + ]:GNC         119 :             if (recurse)
                               4913                 :            113 :                 cmd->recurse = true;
 7284 tgl@sss.pgh.pa.us        4914                 :CBC         119 :             pass = AT_PASS_DROP;
                               4915                 :            119 :             break;
                               4916                 :            183 :         case AT_SetNotNull:     /* ALTER COLUMN SET NOT NULL */
 1011 peter@eisentraut.org     4917                 :            183 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4918                 :                :             /* Set up recursion for phase 2; no other prep needed */
  233 alvherre@alvh.no-ip.     4919         [ +  + ]:GNC         180 :             if (recurse)
                               4920                 :            165 :                 cmd->recurse = true;
 1818 tgl@sss.pgh.pa.us        4921                 :CBC         180 :             pass = AT_PASS_COL_ATTRS;
                               4922                 :            180 :             break;
  233 alvherre@alvh.no-ip.     4923                 :GNC        3629 :         case AT_SetAttNotNull:  /* set pg_attribute.attnotnull without adding
                               4924                 :                :                                  * a constraint */
 1011 peter@eisentraut.org     4925                 :           3629 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4926                 :                :             /* Need command-specific recursion decision */
 1551 tgl@sss.pgh.pa.us        4927                 :           3629 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
 1818                          4928                 :           3629 :             pass = AT_PASS_COL_ATTRS;
 7284                          4929                 :           3629 :             break;
  101 peter@eisentraut.org     4930                 :             42 :         case AT_SetExpression:  /* ALTER COLUMN SET EXPRESSION */
  101 peter@eisentraut.org     4931                 :CBC          42 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4932                 :             42 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
  101 peter@eisentraut.org     4933                 :GNC          42 :             pass = AT_PASS_SET_EXPRESSION;
  101 peter@eisentraut.org     4934                 :CBC          42 :             break;
 1551 tgl@sss.pgh.pa.us        4935                 :             22 :         case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
 1011 peter@eisentraut.org     4936                 :             22 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 1551 tgl@sss.pgh.pa.us        4937                 :             22 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
 1258 peter@eisentraut.org     4938                 :             22 :             ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
 1552                          4939                 :             16 :             pass = AT_PASS_DROP;
                               4940                 :             16 :             break;
 5369 tgl@sss.pgh.pa.us        4941                 :             82 :         case AT_SetStatistics:  /* ALTER COLUMN SET STATISTICS */
 1011 peter@eisentraut.org     4942                 :             82 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE);
 1551 tgl@sss.pgh.pa.us        4943                 :             82 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
                               4944                 :                :             /* No command-specific prep needed */
 5008 simon@2ndQuadrant.co     4945                 :             82 :             pass = AT_PASS_MISC;
 7284 tgl@sss.pgh.pa.us        4946                 :             82 :             break;
 5196 rhaas@postgresql.org     4947                 :             22 :         case AT_SetOptions:     /* ALTER COLUMN SET ( options ) */
                               4948                 :                :         case AT_ResetOptions:   /* ALTER COLUMN RESET ( options ) */
  908 michael@paquier.xyz      4949                 :             22 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
                               4950                 :                :             /* This command never recurses */
 5008 simon@2ndQuadrant.co     4951                 :             16 :             pass = AT_PASS_MISC;
 5369 tgl@sss.pgh.pa.us        4952                 :             16 :             break;
                               4953                 :            117 :         case AT_SetStorage:     /* ALTER COLUMN SET STORAGE */
 1011 peter@eisentraut.org     4954                 :            117 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
 1551 tgl@sss.pgh.pa.us        4955                 :            117 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
                               4956                 :                :             /* No command-specific prep needed */
 5008 simon@2ndQuadrant.co     4957                 :            117 :             pass = AT_PASS_MISC;
 7284 tgl@sss.pgh.pa.us        4958                 :            117 :             break;
 1068                          4959                 :             33 :         case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
 1011 peter@eisentraut.org     4960                 :             33 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
                               4961                 :                :             /* This command never recurses */
                               4962                 :                :             /* No command-specific prep needed */
 1122 rhaas@postgresql.org     4963                 :             33 :             pass = AT_PASS_MISC;
                               4964                 :             33 :             break;
 7284 tgl@sss.pgh.pa.us        4965                 :            808 :         case AT_DropColumn:     /* DROP COLUMN */
 1011 peter@eisentraut.org     4966                 :            808 :             ATSimplePermissions(cmd->subtype, rel,
                               4967                 :                :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
 1551 tgl@sss.pgh.pa.us        4968                 :            805 :             ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
                               4969                 :                :                              lockmode, context);
                               4970                 :                :             /* Recursion occurs during execution phase */
 7284                          4971                 :            799 :             pass = AT_PASS_DROP;
                               4972                 :            799 :             break;
 7284 tgl@sss.pgh.pa.us        4973                 :UBC           0 :         case AT_AddIndex:       /* ADD INDEX */
 1011 peter@eisentraut.org     4974                 :              0 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               4975                 :                :             /* This command never recurses */
                               4976                 :                :             /* No command-specific prep needed */
 7284 tgl@sss.pgh.pa.us        4977                 :              0 :             pass = AT_PASS_ADD_INDEX;
                               4978                 :              0 :             break;
 7284 tgl@sss.pgh.pa.us        4979                 :CBC        6310 :         case AT_AddConstraint:  /* ADD CONSTRAINT */
 1011 peter@eisentraut.org     4980                 :           6310 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               4981                 :                :             /* Recursion occurs during execution phase */
                               4982                 :                :             /* No command-specific prep needed except saving recurse flag */
 5819 tgl@sss.pgh.pa.us        4983         [ +  + ]:           6310 :             if (recurse)
  489 alvherre@alvh.no-ip.     4984                 :           6144 :                 cmd->recurse = true;
 7284 tgl@sss.pgh.pa.us        4985                 :           6310 :             pass = AT_PASS_ADD_CONSTR;
                               4986                 :           6310 :             break;
 2489 tgl@sss.pgh.pa.us        4987                 :UBC           0 :         case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
 1011 peter@eisentraut.org     4988                 :              0 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               4989                 :                :             /* This command never recurses */
                               4990                 :                :             /* No command-specific prep needed */
 1551 tgl@sss.pgh.pa.us        4991                 :              0 :             pass = AT_PASS_ADD_INDEXCONSTR;
 4828                          4992                 :              0 :             break;
 2489 tgl@sss.pgh.pa.us        4993                 :CBC         473 :         case AT_DropConstraint: /* DROP CONSTRAINT */
 1011 peter@eisentraut.org     4994                 :            473 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 1727 alvherre@alvh.no-ip.     4995                 :            473 :             ATCheckPartitionsNotInUse(rel, lockmode);
                               4996                 :                :             /* Other recursion occurs during execution phase */
                               4997                 :                :             /* No command-specific prep needed except saving recurse flag */
 5819 tgl@sss.pgh.pa.us        4998         [ +  + ]:            470 :             if (recurse)
  489 alvherre@alvh.no-ip.     4999                 :            354 :                 cmd->recurse = true;
 7284 tgl@sss.pgh.pa.us        5000                 :            470 :             pass = AT_PASS_DROP;
                               5001                 :            470 :             break;
 2489                          5002                 :            562 :         case AT_AlterColumnType:    /* ALTER COLUMN TYPE */
 1011 peter@eisentraut.org     5003                 :            562 :             ATSimplePermissions(cmd->subtype, rel,
                               5004                 :                :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
                               5005                 :                :             /* See comments for ATPrepAlterColumnType */
 1551 tgl@sss.pgh.pa.us        5006                 :            562 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
                               5007                 :                :                                       AT_PASS_UNSET, context);
                               5008         [ -  + ]:            559 :             Assert(cmd != NULL);
                               5009                 :                :             /* Performs own recursion */
                               5010                 :            559 :             ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
                               5011                 :                :                                   lockmode, context);
 7284                          5012                 :            487 :             pass = AT_PASS_ALTER_TYPE;
                               5013                 :            487 :             break;
 4636 rhaas@postgresql.org     5014                 :             82 :         case AT_AlterColumnGenericOptions:
 1011 peter@eisentraut.org     5015                 :             82 :             ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
                               5016                 :                :             /* This command never recurses */
                               5017                 :                :             /* No command-specific prep needed */
 4636 rhaas@postgresql.org     5018                 :             82 :             pass = AT_PASS_MISC;
                               5019                 :             82 :             break;
 7284 tgl@sss.pgh.pa.us        5020                 :            898 :         case AT_ChangeOwner:    /* ALTER OWNER */
                               5021                 :                :             /* This command never recurses */
                               5022                 :                :             /* No command-specific prep needed */
                               5023                 :            898 :             pass = AT_PASS_MISC;
                               5024                 :            898 :             break;
 7168 bruce@momjian.us         5025                 :             32 :         case AT_ClusterOn:      /* CLUSTER ON */
                               5026                 :                :         case AT_DropCluster:    /* SET WITHOUT CLUSTER */
 1011 peter@eisentraut.org     5027                 :             32 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
                               5028                 :                :             /* These commands never recurse */
                               5029                 :                :             /* No command-specific prep needed */
 7284 tgl@sss.pgh.pa.us        5030                 :             32 :             pass = AT_PASS_MISC;
                               5031                 :             32 :             break;
 3523 alvherre@alvh.no-ip.     5032                 :             19 :         case AT_SetLogged:      /* SET LOGGED */
  738 peter@eisentraut.org     5033                 :             19 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE);
 1551 tgl@sss.pgh.pa.us        5034         [ -  + ]:             19 :             if (tab->chgPersistence)
 1551 tgl@sss.pgh.pa.us        5035         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               5036                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               5037                 :                :                          errmsg("cannot change persistence setting twice")));
 3520 alvherre@alvh.no-ip.     5038                 :CBC          19 :             tab->chgPersistence = ATPrepChangePersistence(rel, true);
                               5039                 :                :             /* force rewrite if necessary; see comment in ATRewriteTables */
                               5040         [ +  + ]:             16 :             if (tab->chgPersistence)
                               5041                 :                :             {
 3415 simon@2ndQuadrant.co     5042                 :             13 :                 tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
 3520 alvherre@alvh.no-ip.     5043                 :             13 :                 tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
                               5044                 :                :             }
 3523                          5045                 :             16 :             pass = AT_PASS_MISC;
                               5046                 :             16 :             break;
                               5047                 :             25 :         case AT_SetUnLogged:    /* SET UNLOGGED */
  738 peter@eisentraut.org     5048                 :             25 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE);
 1551 tgl@sss.pgh.pa.us        5049         [ -  + ]:             25 :             if (tab->chgPersistence)
 1551 tgl@sss.pgh.pa.us        5050         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               5051                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               5052                 :                :                          errmsg("cannot change persistence setting twice")));
 3520 alvherre@alvh.no-ip.     5053                 :CBC          25 :             tab->chgPersistence = ATPrepChangePersistence(rel, false);
                               5054                 :                :             /* force rewrite if necessary; see comment in ATRewriteTables */
                               5055         [ +  + ]:             22 :             if (tab->chgPersistence)
                               5056                 :                :             {
 3415 simon@2ndQuadrant.co     5057                 :             19 :                 tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
 3520 alvherre@alvh.no-ip.     5058                 :             19 :                 tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
                               5059                 :                :             }
 3523                          5060                 :             22 :             pass = AT_PASS_MISC;
                               5061                 :             22 :             break;
 7168 bruce@momjian.us         5062                 :              3 :         case AT_DropOids:       /* SET WITHOUT OIDS */
 1011 peter@eisentraut.org     5063                 :              3 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
 7284 tgl@sss.pgh.pa.us        5064                 :              3 :             pass = AT_PASS_DROP;
                               5065                 :              3 :             break;
  991 michael@paquier.xyz      5066                 :             64 :         case AT_SetAccessMethod:    /* SET ACCESS METHOD */
                               5067                 :             64 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
                               5068                 :                : 
                               5069                 :                :             /* check if another access method change was already requested */
   20 alvherre@alvh.no-ip.     5070         [ +  + ]:GNC          64 :             if (tab->chgAccessMethod)
  991 michael@paquier.xyz      5071         [ +  - ]:CBC           9 :                 ereport(ERROR,
                               5072                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               5073                 :                :                          errmsg("cannot have multiple SET ACCESS METHOD subcommands")));
                               5074                 :                : 
                               5075                 :             55 :             ATPrepSetAccessMethod(tab, rel, cmd->name);
                               5076                 :             55 :             pass = AT_PASS_MISC;    /* does not matter; no work in Phase 2 */
                               5077                 :             55 :             break;
 7217 tgl@sss.pgh.pa.us        5078                 :             79 :         case AT_SetTableSpace:  /* SET TABLESPACE */
 1011 peter@eisentraut.org     5079                 :             79 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
                               5080                 :                :                                 ATT_PARTITIONED_INDEX);
                               5081                 :                :             /* This command never recurses */
 5009 simon@2ndQuadrant.co     5082                 :             79 :             ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
 7168 bruce@momjian.us         5083                 :             79 :             pass = AT_PASS_MISC;    /* doesn't actually matter */
 7217 tgl@sss.pgh.pa.us        5084                 :             79 :             break;
 6402 bruce@momjian.us         5085                 :            467 :         case AT_SetRelOptions:  /* SET (...) */
                               5086                 :                :         case AT_ResetRelOptions:    /* RESET (...) */
                               5087                 :                :         case AT_ReplaceRelOptions:  /* reset them all, then set just these */
 1011 peter@eisentraut.org     5088                 :            467 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
                               5089                 :                :             /* This command never recurses */
                               5090                 :                :             /* No command-specific prep needed */
 6496 bruce@momjian.us         5091                 :            467 :             pass = AT_PASS_MISC;
                               5092                 :            467 :             break;
 5014 peter_e@gmx.net          5093                 :            163 :         case AT_AddInherit:     /* INHERIT */
 1011 peter@eisentraut.org     5094                 :            163 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               5095                 :                :             /* This command never recurses */
 5014 peter_e@gmx.net          5096                 :            163 :             ATPrepAddInherit(rel);
                               5097                 :            154 :             pass = AT_PASS_MISC;
                               5098                 :            154 :             break;
 3311 tgl@sss.pgh.pa.us        5099                 :             22 :         case AT_DropInherit:    /* NO INHERIT */
 1011 peter@eisentraut.org     5100                 :             22 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               5101                 :                :             /* This command never recurses */
                               5102                 :                :             /* No command-specific prep needed */
 3311 tgl@sss.pgh.pa.us        5103                 :             22 :             pass = AT_PASS_MISC;
                               5104                 :             22 :             break;
 2489                          5105                 :             66 :         case AT_AlterConstraint:    /* ALTER CONSTRAINT */
 1011 peter@eisentraut.org     5106                 :             66 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5107                 :                :             /* Recursion occurs during execution phase */
 3942 simon@2ndQuadrant.co     5108                 :             63 :             pass = AT_PASS_MISC;
                               5109                 :             63 :             break;
 2489 tgl@sss.pgh.pa.us        5110                 :            194 :         case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
 1011 peter@eisentraut.org     5111                 :            194 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               5112                 :                :             /* Recursion occurs during execution phase */
                               5113                 :                :             /* No command-specific prep needed except saving recurse flag */
 4701 alvherre@alvh.no-ip.     5114         [ +  - ]:            194 :             if (recurse)
  489                          5115                 :            194 :                 cmd->recurse = true;
 4701                          5116                 :            194 :             pass = AT_PASS_MISC;
                               5117                 :            194 :             break;
 2489 tgl@sss.pgh.pa.us        5118                 :            215 :         case AT_ReplicaIdentity:    /* REPLICA IDENTITY ... */
 1011 peter@eisentraut.org     5119                 :            215 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
 3810 rhaas@postgresql.org     5120                 :            215 :             pass = AT_PASS_MISC;
                               5121                 :                :             /* This command never recurses */
                               5122                 :                :             /* No command-specific prep needed */
                               5123                 :            215 :             break;
 6809 tgl@sss.pgh.pa.us        5124                 :            170 :         case AT_EnableTrig:     /* ENABLE TRIGGER variants */
                               5125                 :                :         case AT_EnableAlwaysTrig:
                               5126                 :                :         case AT_EnableReplicaTrig:
                               5127                 :                :         case AT_EnableTrigAll:
                               5128                 :                :         case AT_EnableTrigUser:
                               5129                 :                :         case AT_DisableTrig:    /* DISABLE TRIGGER variants */
                               5130                 :                :         case AT_DisableTrigAll:
                               5131                 :                :         case AT_DisableTrigUser:
 1011 peter@eisentraut.org     5132                 :            170 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               5133                 :                :             /* Set up recursion for phase 2; no other prep needed */
  619 alvherre@alvh.no-ip.     5134         [ +  + ]:            170 :             if (recurse)
                               5135                 :            156 :                 cmd->recurse = true;
 3675 noah@leadboat.com        5136                 :            170 :             pass = AT_PASS_MISC;
                               5137                 :            170 :             break;
 6236 JanWieck@Yahoo.com       5138                 :            260 :         case AT_EnableRule:     /* ENABLE/DISABLE RULE variants */
                               5139                 :                :         case AT_EnableAlwaysRule:
                               5140                 :                :         case AT_EnableReplicaRule:
                               5141                 :                :         case AT_DisableRule:
                               5142                 :                :         case AT_AddOf:          /* OF */
                               5143                 :                :         case AT_DropOf:         /* NOT OF */
                               5144                 :                :         case AT_EnableRowSecurity:
                               5145                 :                :         case AT_DisableRowSecurity:
                               5146                 :                :         case AT_ForceRowSecurity:
                               5147                 :                :         case AT_NoForceRowSecurity:
 1011 peter@eisentraut.org     5148                 :            260 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5149                 :                :             /* These commands never recurse */
                               5150                 :                :             /* No command-specific prep needed */
 4852 rhaas@postgresql.org     5151                 :            260 :             pass = AT_PASS_MISC;
                               5152                 :            260 :             break;
                               5153                 :             25 :         case AT_GenericOptions:
 1011 peter@eisentraut.org     5154                 :             25 :             ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
                               5155                 :                :             /* No command-specific prep needed */
 4852 rhaas@postgresql.org     5156                 :             25 :             pass = AT_PASS_MISC;
                               5157                 :             25 :             break;
 2685                          5158                 :           1289 :         case AT_AttachPartition:
 1011 peter@eisentraut.org     5159                 :           1289 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
                               5160                 :                :             /* No command-specific prep needed */
 2277 alvherre@alvh.no-ip.     5161                 :           1289 :             pass = AT_PASS_MISC;
                               5162                 :           1289 :             break;
 2685 rhaas@postgresql.org     5163                 :            264 :         case AT_DetachPartition:
 1011 peter@eisentraut.org     5164                 :            264 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5165                 :                :             /* No command-specific prep needed */
 2685 rhaas@postgresql.org     5166                 :            261 :             pass = AT_PASS_MISC;
                               5167                 :            261 :             break;
 1116 alvherre@alvh.no-ip.     5168                 :              7 :         case AT_DetachPartitionFinalize:
 1011 peter@eisentraut.org     5169                 :              7 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5170                 :                :             /* No command-specific prep needed */
 1116 alvherre@alvh.no-ip.     5171                 :              7 :             pass = AT_PASS_MISC;
                               5172                 :              7 :             break;
    7 akorotkov@postgresql     5173                 :GNC         126 :         case AT_SplitPartition:
                               5174                 :            126 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5175                 :                :             /* No command-specific prep needed */
                               5176                 :            126 :             pass = AT_PASS_MISC;
                               5177                 :            126 :             break;
                               5178                 :             60 :         case AT_MergePartitions:
                               5179                 :             60 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
                               5180                 :                :             /* No command-specific prep needed */
                               5181                 :             60 :             pass = AT_PASS_MISC;
                               5182                 :             60 :             break;
 7168 bruce@momjian.us         5183                 :UBC           0 :         default:                /* oops */
 7284 tgl@sss.pgh.pa.us        5184         [ #  # ]:              0 :             elog(ERROR, "unrecognized alter table type: %d",
                               5185                 :                :                  (int) cmd->subtype);
                               5186                 :                :             pass = AT_PASS_UNSET;   /* keep compiler quiet */
                               5187                 :                :             break;
                               5188                 :                :     }
 3942 simon@2ndQuadrant.co     5189         [ -  + ]:CBC       18270 :     Assert(pass > AT_PASS_UNSET);
                               5190                 :                : 
                               5191                 :                :     /* Add the subcommand to the appropriate list for phase 2 */
 7284 tgl@sss.pgh.pa.us        5192                 :          18270 :     tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
                               5193                 :          18270 : }
                               5194                 :                : 
                               5195                 :                : /*
                               5196                 :                :  * ATRewriteCatalogs
                               5197                 :                :  *
                               5198                 :                :  * Traffic cop for ALTER TABLE Phase 2 operations.  Subcommands are
                               5199                 :                :  * dispatched in a "safe" execution order (designed to avoid unnecessary
                               5200                 :                :  * conflicts).
                               5201                 :                :  */
                               5202                 :                : static void
 1551                          5203                 :          16992 : ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
                               5204                 :                :                   AlterTableUtilityContext *context)
                               5205                 :                : {
                               5206                 :                :     ListCell   *ltab;
                               5207                 :                : 
                               5208                 :                :     /*
                               5209                 :                :      * We process all the tables "in parallel", one pass at a time.  This is
                               5210                 :                :      * needed because we may have to propagate work from one table to another
                               5211                 :                :      * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
                               5212                 :                :      * re-adding of the foreign key constraint to the other table).  Work can
                               5213                 :                :      * only be propagated into later passes, however.
                               5214                 :                :      */
  104 peter@eisentraut.org     5215         [ +  + ]:GNC      215300 :     for (AlterTablePass pass = 0; pass < AT_NUM_PASSES; pass++)
                               5216                 :                :     {
                               5217                 :                :         /* Go through each table that needs to be processed */
 7284 tgl@sss.pgh.pa.us        5218   [ +  -  +  +  :CBC      404813 :         foreach(ltab, *wqueue)
                                              +  + ]
                               5219                 :                :         {
                               5220                 :         206505 :             AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
                               5221                 :         206505 :             List       *subcmds = tab->subcmds[pass];
                               5222                 :                :             ListCell   *lcmd;
                               5223                 :                : 
                               5224         [ +  + ]:         206505 :             if (subcmds == NIL)
 8024                          5225                 :         179758 :                 continue;
                               5226                 :                : 
                               5227                 :                :             /*
                               5228                 :                :              * Open the relation and store it in tab.  This allows subroutines
                               5229                 :                :              * close and reopen, if necessary.  Appropriate lock was obtained
                               5230                 :                :              * by phase 1, needn't get it again.
                               5231                 :                :              */
 1116 alvherre@alvh.no-ip.     5232                 :          26747 :             tab->rel = relation_open(tab->relid, NoLock);
                               5233                 :                : 
 7284 tgl@sss.pgh.pa.us        5234   [ +  -  +  +  :          53954 :             foreach(lcmd, subcmds)
                                              +  + ]
 1116 alvherre@alvh.no-ip.     5235                 :          28522 :                 ATExecCmd(wqueue, tab,
 1000 peter@eisentraut.org     5236                 :          28522 :                           lfirst_node(AlterTableCmd, lcmd),
                               5237                 :                :                           lockmode, pass, context);
                               5238                 :                : 
                               5239                 :                :             /*
                               5240                 :                :              * After the ALTER TYPE or SET EXPRESSION pass, do cleanup work
                               5241                 :                :              * (this is not done in ATExecAlterColumnType since it should be
                               5242                 :                :              * done only once if multiple columns of a table are altered).
                               5243                 :                :              */
  101 peter@eisentraut.org     5244   [ +  +  +  + ]:GNC       25432 :             if (pass == AT_PASS_ALTER_TYPE || pass == AT_PASS_SET_EXPRESSION)
 5009 simon@2ndQuadrant.co     5245                 :CBC         478 :                 ATPostAlterTypeCleanup(wqueue, tab, lockmode);
                               5246                 :                : 
 1116 alvherre@alvh.no-ip.     5247         [ +  - ]:          25432 :             if (tab->rel)
                               5248                 :                :             {
                               5249                 :          25432 :                 relation_close(tab->rel, NoLock);
                               5250                 :          25432 :                 tab->rel = NULL;
                               5251                 :                :             }
                               5252                 :                :         }
                               5253                 :                :     }
                               5254                 :                : 
                               5255                 :                :     /* Check to see if a toast table must be added. */
 7284 tgl@sss.pgh.pa.us        5256   [ +  -  +  +  :          33206 :     foreach(ltab, *wqueue)
                                              +  + ]
                               5257                 :                :     {
                               5258                 :          17529 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
                               5259                 :                : 
                               5260                 :                :         /*
                               5261                 :                :          * If the table is source table of ATTACH PARTITION command, we did
                               5262                 :                :          * not modify anything about it that will change its toasting
                               5263                 :                :          * requirement, so no need to check.
                               5264                 :                :          */
 2685 rhaas@postgresql.org     5265         [ +  + ]:          17529 :         if (((tab->relkind == RELKIND_RELATION ||
                               5266         [ +  + ]:           3200 :               tab->relkind == RELKIND_PARTITIONED_TABLE) &&
 2576 tgl@sss.pgh.pa.us        5267         [ +  + ]:          16616 :              tab->partition_constraint == NULL) ||
 4060 kgrittn@postgresql.o     5268         [ +  + ]:           1873 :             tab->relkind == RELKIND_MATVIEW)
 3661 simon@2ndQuadrant.co     5269                 :          15681 :             AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
                               5270                 :                :     }
 7284 tgl@sss.pgh.pa.us        5271                 :          15677 : }
                               5272                 :                : 
                               5273                 :                : /*
                               5274                 :                :  * ATExecCmd: dispatch a subcommand to appropriate execution routine
                               5275                 :                :  */
                               5276                 :                : static void
 1116 alvherre@alvh.no-ip.     5277                 :          28522 : ATExecCmd(List **wqueue, AlteredTableInfo *tab,
                               5278                 :                :           AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
                               5279                 :                :           AlterTableUtilityContext *context)
                               5280                 :                : {
 3308                          5281                 :          28522 :     ObjectAddress address = InvalidObjectAddress;
 1116                          5282                 :          28522 :     Relation    rel = tab->rel;
                               5283                 :                : 
 7284 tgl@sss.pgh.pa.us        5284   [ +  +  +  +  :          28522 :     switch (cmd->subtype)
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  -  +  
                                     -  +  +  -  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                              +  - ]
                               5285                 :                :     {
                               5286                 :            981 :         case AT_AddColumn:      /* ADD COLUMN */
                               5287                 :                :         case AT_AddColumnToView:    /* add column via CREATE OR REPLACE VIEW */
 1551                          5288                 :            981 :             address = ATExecAddColumn(wqueue, tab, rel, &cmd,
  489 alvherre@alvh.no-ip.     5289                 :            981 :                                       cmd->recurse, false,
                               5290                 :                :                                       lockmode, cur_pass, context);
 7284 tgl@sss.pgh.pa.us        5291                 :            924 :             break;
                               5292                 :            283 :         case AT_ColumnDefault:  /* ALTER COLUMN DEFAULT */
 3308 alvherre@alvh.no-ip.     5293                 :            283 :             address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
 7284 tgl@sss.pgh.pa.us        5294                 :            253 :             break;
 1332                          5295                 :             55 :         case AT_CookedColumnDefault:    /* add a pre-cooked default */
                               5296                 :             55 :             address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
                               5297                 :             55 :             break;
 2565 peter_e@gmx.net          5298                 :             74 :         case AT_AddIdentity:
 1551 tgl@sss.pgh.pa.us        5299                 :             74 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
                               5300                 :                :                                       cur_pass, context);
                               5301         [ -  + ]:             71 :             Assert(cmd != NULL);
   89 peter@eisentraut.org     5302                 :GNC          71 :             address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
 2565 peter_e@gmx.net          5303                 :CBC          50 :             break;
                               5304                 :             31 :         case AT_SetIdentity:
 1551 tgl@sss.pgh.pa.us        5305                 :             31 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
                               5306                 :                :                                       cur_pass, context);
                               5307         [ -  + ]:             31 :             Assert(cmd != NULL);
   89 peter@eisentraut.org     5308                 :GNC          31 :             address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
 2565 peter_e@gmx.net          5309                 :CBC          19 :             break;
                               5310                 :             28 :         case AT_DropIdentity:
   89 peter@eisentraut.org     5311                 :GNC          28 :             address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode, cmd->recurse, false);
 2565 peter_e@gmx.net          5312                 :CBC          19 :             break;
 7284 tgl@sss.pgh.pa.us        5313                 :            119 :         case AT_DropNotNull:    /* ALTER COLUMN DROP NOT NULL */
  233 alvherre@alvh.no-ip.     5314                 :GNC         119 :             address = ATExecDropNotNull(rel, cmd->name, cmd->recurse, lockmode);
 7284 tgl@sss.pgh.pa.us        5315                 :CBC          65 :             break;
                               5316                 :            180 :         case AT_SetNotNull:     /* ALTER COLUMN SET NOT NULL */
  233 alvherre@alvh.no-ip.     5317                 :GNC         180 :             address = ATExecSetNotNull(wqueue, rel, NULL, cmd->name,
                               5318                 :            180 :                                        cmd->recurse, false, NULL, lockmode);
 7284 tgl@sss.pgh.pa.us        5319                 :CBC         165 :             break;
  233 alvherre@alvh.no-ip.     5320                 :GNC        7120 :         case AT_SetAttNotNull:  /* set pg_attribute.attnotnull */
                               5321                 :           7120 :             address = ATExecSetAttNotNull(wqueue, rel, cmd->name, lockmode);
 1818 tgl@sss.pgh.pa.us        5322                 :           7111 :             break;
  101 peter@eisentraut.org     5323                 :             42 :         case AT_SetExpression:
                               5324                 :             42 :             address = ATExecSetExpression(tab, rel, cmd->name, cmd->def, lockmode);
  101 peter@eisentraut.org     5325                 :CBC          39 :             break;
 1552                          5326                 :             16 :         case AT_DropExpression:
                               5327                 :             16 :             address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
                               5328                 :             13 :             break;
 5369 tgl@sss.pgh.pa.us        5329                 :             82 :         case AT_SetStatistics:  /* ALTER COLUMN SET STATISTICS */
 2412 simon@2ndQuadrant.co     5330                 :             82 :             address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
 7284 tgl@sss.pgh.pa.us        5331                 :             58 :             break;
 5196 rhaas@postgresql.org     5332                 :             13 :         case AT_SetOptions:     /* ALTER COLUMN SET ( options ) */
 3308 alvherre@alvh.no-ip.     5333                 :             13 :             address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
 5196 rhaas@postgresql.org     5334                 :             13 :             break;
                               5335                 :              3 :         case AT_ResetOptions:   /* ALTER COLUMN RESET ( options ) */
 3308 alvherre@alvh.no-ip.     5336                 :              3 :             address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
 5369 tgl@sss.pgh.pa.us        5337                 :              3 :             break;
                               5338                 :            117 :         case AT_SetStorage:     /* ALTER COLUMN SET STORAGE */
 3308 alvherre@alvh.no-ip.     5339                 :            117 :             address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
 7284 tgl@sss.pgh.pa.us        5340                 :            111 :             break;
  641 peter@eisentraut.org     5341                 :             33 :         case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
                               5342                 :             33 :             address = ATExecSetCompression(rel, cmd->name, cmd->def,
                               5343                 :                :                                            lockmode);
 1122 rhaas@postgresql.org     5344                 :             30 :             break;
 7284 tgl@sss.pgh.pa.us        5345                 :            799 :         case AT_DropColumn:     /* DROP COLUMN */
 3308 alvherre@alvh.no-ip.     5346                 :            799 :             address = ATExecDropColumn(wqueue, rel, cmd->name,
  489                          5347                 :            799 :                                        cmd->behavior, cmd->recurse, false,
 1645 michael@paquier.xyz      5348                 :            799 :                                        cmd->missing_ok, lockmode,
                               5349                 :                :                                        NULL);
 7284 tgl@sss.pgh.pa.us        5350                 :            712 :             break;
                               5351                 :            500 :         case AT_AddIndex:       /* ADD INDEX */
 3308 alvherre@alvh.no-ip.     5352                 :            500 :             address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
                               5353                 :                :                                      lockmode);
 7284 tgl@sss.pgh.pa.us        5354                 :            436 :             break;
                               5355                 :            217 :         case AT_ReAddIndex:     /* ADD INDEX */
 3308 alvherre@alvh.no-ip.     5356                 :            217 :             address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
                               5357                 :                :                                      lockmode);
 7284 tgl@sss.pgh.pa.us        5358                 :            217 :             break;
 1115 tomas.vondra@postgre     5359                 :              7 :         case AT_ReAddStatistics:    /* ADD STATISTICS */
                               5360                 :              7 :             address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
                               5361                 :                :                                           true, lockmode);
                               5362                 :              7 :             break;
 7284 tgl@sss.pgh.pa.us        5363                 :           8136 :         case AT_AddConstraint:  /* ADD CONSTRAINT */
                               5364                 :                :             /* Transform the command only during initial examination */
 1331                          5365         [ +  + ]:           8136 :             if (cur_pass == AT_PASS_ADD_CONSTR)
                               5366                 :           6295 :                 cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
  489 alvherre@alvh.no-ip.     5367                 :           6310 :                                           cmd->recurse, lockmode,
                               5368                 :                :                                           cur_pass, context);
                               5369                 :                :             /* Depending on constraint type, might be no more work to do now */
 1551 tgl@sss.pgh.pa.us        5370         [ +  + ]:           8121 :             if (cmd != NULL)
                               5371                 :                :                 address =
                               5372                 :           1826 :                     ATExecAddConstraint(wqueue, tab, rel,
                               5373                 :           1826 :                                         (Constraint *) cmd->def,
  489 alvherre@alvh.no-ip.     5374                 :           1826 :                                         cmd->recurse, false, lockmode);
 4178 tgl@sss.pgh.pa.us        5375                 :           7844 :             break;
 2489                          5376                 :             94 :         case AT_ReAddConstraint:    /* Re-add pre-existing check constraint */
                               5377                 :                :             address =
 3308 alvherre@alvh.no-ip.     5378                 :             94 :                 ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
                               5379                 :                :                                     true, true, lockmode);
 7284 tgl@sss.pgh.pa.us        5380                 :             88 :             break;
 2356                          5381                 :              7 :         case AT_ReAddDomainConstraint:  /* Re-add pre-existing domain check
                               5382                 :                :                                          * constraint */
                               5383                 :                :             address =
                               5384                 :              7 :                 AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
                               5385                 :              7 :                                          ((AlterDomainStmt *) cmd->def)->def,
                               5386                 :                :                                          NULL);
                               5387                 :              4 :             break;
 3197 heikki.linnakangas@i     5388                 :             27 :         case AT_ReAddComment:   /* Re-add existing comment */
                               5389                 :             27 :             address = CommentObject((CommentStmt *) cmd->def);
                               5390                 :             27 :             break;
 2489 tgl@sss.pgh.pa.us        5391                 :           4107 :         case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
 3308 alvherre@alvh.no-ip.     5392                 :           4107 :             address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
                               5393                 :                :                                                lockmode);
 4828 tgl@sss.pgh.pa.us        5394                 :           4101 :             break;
 2489                          5395                 :             63 :         case AT_AlterConstraint:    /* ALTER CONSTRAINT */
 3308 alvherre@alvh.no-ip.     5396                 :             63 :             address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
 3942 simon@2ndQuadrant.co     5397                 :             57 :             break;
 2489 tgl@sss.pgh.pa.us        5398                 :            194 :         case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
  489 alvherre@alvh.no-ip.     5399                 :            194 :             address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
                               5400                 :                :                                                false, lockmode);
 4814 simon@2ndQuadrant.co     5401                 :            194 :             break;
 2489 tgl@sss.pgh.pa.us        5402                 :            470 :         case AT_DropConstraint: /* DROP CONSTRAINT */
 5382 andrew@dunslane.net      5403                 :            470 :             ATExecDropConstraint(rel, cmd->name, cmd->behavior,
  220 alvherre@alvh.no-ip.     5404                 :GNC         470 :                                  cmd->recurse,
 5009 simon@2ndQuadrant.co     5405                 :CBC         470 :                                  cmd->missing_ok, lockmode);
 7284 tgl@sss.pgh.pa.us        5406                 :            371 :             break;
 2489                          5407                 :            472 :         case AT_AlterColumnType:    /* ALTER COLUMN TYPE */
                               5408                 :                :             /* parse transformation was done earlier */
 3308 alvherre@alvh.no-ip.     5409                 :            472 :             address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
 7284 tgl@sss.pgh.pa.us        5410                 :            454 :             break;
 2489                          5411                 :             82 :         case AT_AlterColumnGenericOptions:  /* ALTER COLUMN OPTIONS */
                               5412                 :                :             address =
 3308 alvherre@alvh.no-ip.     5413                 :             82 :                 ATExecAlterColumnGenericOptions(rel, cmd->name,
                               5414                 :             82 :                                                 (List *) cmd->def, lockmode);
 4636 rhaas@postgresql.org     5415                 :             79 :             break;
 7284 tgl@sss.pgh.pa.us        5416                 :            898 :         case AT_ChangeOwner:    /* ALTER OWNER */
 6865                          5417                 :            895 :             ATExecChangeOwner(RelationGetRelid(rel),
 3324 alvherre@alvh.no-ip.     5418                 :            898 :                               get_rolespec_oid(cmd->newowner, false),
                               5419                 :                :                               false, lockmode);
 7284 tgl@sss.pgh.pa.us        5420                 :            889 :             break;
                               5421                 :             32 :         case AT_ClusterOn:      /* CLUSTER ON */
 3308 alvherre@alvh.no-ip.     5422                 :             32 :             address = ATExecClusterOn(rel, cmd->name, lockmode);
 7284 tgl@sss.pgh.pa.us        5423                 :             29 :             break;
 7168 bruce@momjian.us         5424                 :              9 :         case AT_DropCluster:    /* SET WITHOUT CLUSTER */
 5009 simon@2ndQuadrant.co     5425                 :              9 :             ATExecDropCluster(rel, lockmode);
 7256 bruce@momjian.us         5426                 :              6 :             break;
 3523 alvherre@alvh.no-ip.     5427                 :             38 :         case AT_SetLogged:      /* SET LOGGED */
                               5428                 :                :         case AT_SetUnLogged:    /* SET UNLOGGED */
                               5429                 :             38 :             break;
 7284 tgl@sss.pgh.pa.us        5430                 :              3 :         case AT_DropOids:       /* SET WITHOUT OIDS */
                               5431                 :                :             /* nothing to do here, oid columns don't exist anymore */
                               5432                 :              3 :             break;
  991 michael@paquier.xyz      5433                 :             46 :         case AT_SetAccessMethod:    /* SET ACCESS METHOD */
                               5434                 :                : 
                               5435                 :                :             /*
                               5436                 :                :              * Only do this for partitioned tables, for which this is just a
                               5437                 :                :              * catalog change.  Tables with storage are handled by Phase 3.
                               5438                 :                :              */
   20 alvherre@alvh.no-ip.     5439         [ +  + ]:GNC          46 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
                               5440         [ +  + ]:             25 :                 tab->chgAccessMethod)
                               5441                 :             22 :                 ATExecSetAccessMethodNoStorage(rel, tab->newAccessMethod);
  991 michael@paquier.xyz      5442                 :CBC          46 :             break;
 7168 bruce@momjian.us         5443                 :             79 :         case AT_SetTableSpace:  /* SET TABLESPACE */
                               5444                 :                : 
                               5445                 :                :             /*
                               5446                 :                :              * Only do this for partitioned tables and indexes, for which this
                               5447                 :                :              * is just a catalog change.  Other relation types which have
                               5448                 :                :              * storage are handled by Phase 3.
                               5449                 :                :              */
 1945 alvherre@alvh.no-ip.     5450         [ +  + ]:             79 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
                               5451         [ +  + ]:             73 :                 rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
                               5452                 :             18 :                 ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
                               5453                 :                : 
 7217 tgl@sss.pgh.pa.us        5454                 :             76 :             break;
 6402 bruce@momjian.us         5455                 :            467 :         case AT_SetRelOptions:  /* SET (...) */
                               5456                 :                :         case AT_ResetRelOptions:    /* RESET (...) */
                               5457                 :                :         case AT_ReplaceRelOptions:  /* replace entire option list */
 4497 rhaas@postgresql.org     5458                 :            467 :             ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
 6496 bruce@momjian.us         5459                 :            441 :             break;
 5995                          5460                 :             61 :         case AT_EnableTrig:     /* ENABLE TRIGGER name */
                               5461                 :             61 :             ATExecEnableDisableTrigger(rel, cmd->name,
                               5462                 :                :                                        TRIGGER_FIRES_ON_ORIGIN, false,
  619 alvherre@alvh.no-ip.     5463                 :             61 :                                        cmd->recurse,
                               5464                 :                :                                        lockmode);
 6236 JanWieck@Yahoo.com       5465                 :             61 :             break;
 2489 tgl@sss.pgh.pa.us        5466                 :             20 :         case AT_EnableAlwaysTrig:   /* ENABLE ALWAYS TRIGGER name */
 5995 bruce@momjian.us         5467                 :             20 :             ATExecEnableDisableTrigger(rel, cmd->name,
                               5468                 :                :                                        TRIGGER_FIRES_ALWAYS, false,
  619 alvherre@alvh.no-ip.     5469                 :             20 :                                        cmd->recurse,
                               5470                 :                :                                        lockmode);
 6236 JanWieck@Yahoo.com       5471                 :             20 :             break;
 2489 tgl@sss.pgh.pa.us        5472                 :              8 :         case AT_EnableReplicaTrig:  /* ENABLE REPLICA TRIGGER name */
 5995 bruce@momjian.us         5473                 :              8 :             ATExecEnableDisableTrigger(rel, cmd->name,
                               5474                 :                :                                        TRIGGER_FIRES_ON_REPLICA, false,
  619 alvherre@alvh.no-ip.     5475                 :              8 :                                        cmd->recurse,
                               5476                 :                :                                        lockmode);
 6809 tgl@sss.pgh.pa.us        5477                 :              8 :             break;
                               5478                 :             69 :         case AT_DisableTrig:    /* DISABLE TRIGGER name */
 5995 bruce@momjian.us         5479                 :             69 :             ATExecEnableDisableTrigger(rel, cmd->name,
                               5480                 :                :                                        TRIGGER_DISABLED, false,
  619 alvherre@alvh.no-ip.     5481                 :             69 :                                        cmd->recurse,
                               5482                 :                :                                        lockmode);
 6809 tgl@sss.pgh.pa.us        5483                 :             69 :             break;
 6809 tgl@sss.pgh.pa.us        5484                 :UBC           0 :         case AT_EnableTrigAll:  /* ENABLE TRIGGER ALL */
 5995 bruce@momjian.us         5485                 :              0 :             ATExecEnableDisableTrigger(rel, NULL,
                               5486                 :                :                                        TRIGGER_FIRES_ON_ORIGIN, false,
  619 alvherre@alvh.no-ip.     5487                 :              0 :                                        cmd->recurse,
                               5488                 :                :                                        lockmode);
 6809 tgl@sss.pgh.pa.us        5489                 :              0 :             break;
 2489 tgl@sss.pgh.pa.us        5490                 :CBC           6 :         case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
 5995 bruce@momjian.us         5491                 :              6 :             ATExecEnableDisableTrigger(rel, NULL,
                               5492                 :                :                                        TRIGGER_DISABLED, false,
  619 alvherre@alvh.no-ip.     5493                 :              6 :                                        cmd->recurse,
                               5494                 :                :                                        lockmode);
 6809 tgl@sss.pgh.pa.us        5495                 :              6 :             break;
 2489 tgl@sss.pgh.pa.us        5496                 :UBC           0 :         case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
 5995 bruce@momjian.us         5497                 :              0 :             ATExecEnableDisableTrigger(rel, NULL,
                               5498                 :                :                                        TRIGGER_FIRES_ON_ORIGIN, true,
  619 alvherre@alvh.no-ip.     5499                 :              0 :                                        cmd->recurse,
                               5500                 :                :                                        lockmode);
 6809 tgl@sss.pgh.pa.us        5501                 :              0 :             break;
 2489 tgl@sss.pgh.pa.us        5502                 :CBC           6 :         case AT_DisableTrigUser:    /* DISABLE TRIGGER USER */
 5995 bruce@momjian.us         5503                 :              6 :             ATExecEnableDisableTrigger(rel, NULL,
                               5504                 :                :                                        TRIGGER_DISABLED, true,
  619 alvherre@alvh.no-ip.     5505                 :              6 :                                        cmd->recurse,
                               5506                 :                :                                        lockmode);
 6236 JanWieck@Yahoo.com       5507                 :              6 :             break;
                               5508                 :                : 
 5995 bruce@momjian.us         5509                 :              4 :         case AT_EnableRule:     /* ENABLE RULE name */
                               5510                 :              4 :             ATExecEnableDisableRule(rel, cmd->name,
                               5511                 :                :                                     RULE_FIRES_ON_ORIGIN, lockmode);
 6236 JanWieck@Yahoo.com       5512                 :              4 :             break;
 2489 tgl@sss.pgh.pa.us        5513                 :UBC           0 :         case AT_EnableAlwaysRule:   /* ENABLE ALWAYS RULE name */
 5995 bruce@momjian.us         5514                 :              0 :             ATExecEnableDisableRule(rel, cmd->name,
                               5515                 :                :                                     RULE_FIRES_ALWAYS, lockmode);
 6236 JanWieck@Yahoo.com       5516                 :              0 :             break;
 2489 tgl@sss.pgh.pa.us        5517                 :CBC           3 :         case AT_EnableReplicaRule:  /* ENABLE REPLICA RULE name */
 5995 bruce@momjian.us         5518                 :              3 :             ATExecEnableDisableRule(rel, cmd->name,
                               5519                 :                :                                     RULE_FIRES_ON_REPLICA, lockmode);
 6236 JanWieck@Yahoo.com       5520                 :              3 :             break;
                               5521                 :             16 :         case AT_DisableRule:    /* DISABLE RULE name */
 5995 bruce@momjian.us         5522                 :             16 :             ATExecEnableDisableRule(rel, cmd->name,
                               5523                 :                :                                     RULE_DISABLED, lockmode);
 6809 tgl@sss.pgh.pa.us        5524                 :             16 :             break;
                               5525                 :                : 
 6393                          5526                 :            154 :         case AT_AddInherit:
 3308 alvherre@alvh.no-ip.     5527                 :            154 :             address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
 6496 bruce@momjian.us         5528                 :            112 :             break;
 6393 tgl@sss.pgh.pa.us        5529                 :             22 :         case AT_DropInherit:
 3308 alvherre@alvh.no-ip.     5530                 :             22 :             address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
 6496 bruce@momjian.us         5531                 :             19 :             break;
 4743 rhaas@postgresql.org     5532                 :             33 :         case AT_AddOf:
 3308 alvherre@alvh.no-ip.     5533                 :             33 :             address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
 4743 rhaas@postgresql.org     5534                 :             15 :             break;
                               5535                 :              3 :         case AT_DropOf:
                               5536                 :              3 :             ATExecDropOf(rel, lockmode);
                               5537                 :              3 :             break;
 3810                          5538                 :            224 :         case AT_ReplicaIdentity:
                               5539                 :            224 :             ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
                               5540                 :            200 :             break;
 3495 sfrost@snowman.net       5541                 :            139 :         case AT_EnableRowSecurity:
 1139 michael@paquier.xyz      5542                 :            139 :             ATExecSetRowSecurity(rel, true);
 3495 sfrost@snowman.net       5543                 :            139 :             break;
                               5544                 :              5 :         case AT_DisableRowSecurity:
 1139 michael@paquier.xyz      5545                 :              5 :             ATExecSetRowSecurity(rel, false);
 3495 sfrost@snowman.net       5546                 :              5 :             break;
 3115                          5547                 :             41 :         case AT_ForceRowSecurity:
                               5548                 :             41 :             ATExecForceNoForceRowSecurity(rel, true);
                               5549                 :             41 :             break;
                               5550                 :             16 :         case AT_NoForceRowSecurity:
                               5551                 :             16 :             ATExecForceNoForceRowSecurity(rel, false);
                               5552                 :             16 :             break;
 4852 rhaas@postgresql.org     5553                 :             25 :         case AT_GenericOptions:
                               5554                 :             25 :             ATExecGenericOptions(rel, (List *) cmd->def);
                               5555                 :             24 :             break;
 2685                          5556                 :           1289 :         case AT_AttachPartition:
 1551 tgl@sss.pgh.pa.us        5557                 :           1289 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
                               5558                 :                :                                       cur_pass, context);
                               5559         [ -  + ]:           1274 :             Assert(cmd != NULL);
 2277 alvherre@alvh.no-ip.     5560         [ +  + ]:           1274 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
  623 michael@paquier.xyz      5561                 :           1088 :                 address = ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
                               5562                 :                :                                                 context);
                               5563                 :                :             else
                               5564                 :            186 :                 address = ATExecAttachPartitionIdx(wqueue, rel,
                               5565                 :            186 :                                                    ((PartitionCmd *) cmd->def)->name);
 2685 rhaas@postgresql.org     5566                 :           1103 :             break;
                               5567                 :            261 :         case AT_DetachPartition:
 1551 tgl@sss.pgh.pa.us        5568                 :            261 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
                               5569                 :                :                                       cur_pass, context);
                               5570         [ -  + ]:            258 :             Assert(cmd != NULL);
                               5571                 :                :             /* ATPrepCmd ensures it must be a table */
 2277 alvherre@alvh.no-ip.     5572         [ -  + ]:            258 :             Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
  623 michael@paquier.xyz      5573                 :            258 :             address = ATExecDetachPartition(wqueue, tab, rel,
                               5574                 :            258 :                                             ((PartitionCmd *) cmd->def)->name,
                               5575                 :            258 :                                             ((PartitionCmd *) cmd->def)->concurrent);
 1116 alvherre@alvh.no-ip.     5576                 :            193 :             break;
                               5577                 :              7 :         case AT_DetachPartitionFinalize:
  623 michael@paquier.xyz      5578                 :              7 :             address = ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
 2685 rhaas@postgresql.org     5579                 :              7 :             break;
    7 akorotkov@postgresql     5580                 :GNC         126 :         case AT_SplitPartition:
                               5581                 :            126 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
                               5582                 :                :                                       cur_pass, context);
                               5583         [ -  + ]:             60 :             Assert(cmd != NULL);
                               5584         [ -  + ]:             60 :             Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                               5585                 :             60 :             ATExecSplitPartition(wqueue, tab, rel, (PartitionCmd *) cmd->def,
                               5586                 :                :                                  context);
                               5587                 :             57 :             break;
                               5588                 :             60 :         case AT_MergePartitions:
                               5589                 :             60 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
                               5590                 :                :                                       cur_pass, context);
                               5591         [ -  + ]:             33 :             Assert(cmd != NULL);
                               5592         [ -  + ]:             33 :             Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                               5593                 :             33 :             ATExecMergePartitions(wqueue, tab, rel, (PartitionCmd *) cmd->def,
                               5594                 :                :                                   context);
                               5595                 :             33 :             break;
 7168 bruce@momjian.us         5596                 :UBC           0 :         default:                /* oops */
 7284 tgl@sss.pgh.pa.us        5597         [ #  # ]:              0 :             elog(ERROR, "unrecognized alter table type: %d",
                               5598                 :                :                  (int) cmd->subtype);
                               5599                 :                :             break;
                               5600                 :                :     }
                               5601                 :                : 
                               5602                 :                :     /*
                               5603                 :                :      * Report the subcommand to interested event triggers.
                               5604                 :                :      */
 1551 tgl@sss.pgh.pa.us        5605         [ +  + ]:CBC       27207 :     if (cmd)
                               5606                 :          20912 :         EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
                               5607                 :                : 
                               5608                 :                :     /*
                               5609                 :                :      * Bump the command counter to ensure the next subcommand in the sequence
                               5610                 :                :      * can see the changes so far
                               5611                 :                :      */
 7284                          5612                 :          27207 :     CommandCounterIncrement();
                               5613                 :          27207 : }
                               5614                 :                : 
                               5615                 :                : /*
                               5616                 :                :  * ATParseTransformCmd: perform parse transformation for one subcommand
                               5617                 :                :  *
                               5618                 :                :  * Returns the transformed subcommand tree, if there is one, else NULL.
                               5619                 :                :  *
                               5620                 :                :  * The parser may hand back additional AlterTableCmd(s) and/or other
                               5621                 :                :  * utility statements, either before or after the original subcommand.
                               5622                 :                :  * Other AlterTableCmds are scheduled into the appropriate slot of the
                               5623                 :                :  * AlteredTableInfo (they had better be for later passes than the current one).
                               5624                 :                :  * Utility statements that are supposed to happen before the AlterTableCmd
                               5625                 :                :  * are executed immediately.  Those that are supposed to happen afterwards
                               5626                 :                :  * are added to the tab->afterStmts list to be done at the very end.
                               5627                 :                :  */
                               5628                 :                : static AlterTableCmd *
 1551                          5629                 :           9634 : ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
                               5630                 :                :                     AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
                               5631                 :                :                     AlterTablePass cur_pass, AlterTableUtilityContext *context)
                               5632                 :                : {
                               5633                 :           9634 :     AlterTableCmd *newcmd = NULL;
                               5634                 :           9634 :     AlterTableStmt *atstmt = makeNode(AlterTableStmt);
                               5635                 :                :     List       *beforeStmts;
                               5636                 :                :     List       *afterStmts;
                               5637                 :                :     ListCell   *lc;
                               5638                 :                : 
                               5639                 :                :     /* Gin up an AlterTableStmt with just this subcommand and this table */
                               5640                 :           9634 :     atstmt->relation =
                               5641                 :           9634 :         makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
                               5642                 :           9634 :                      pstrdup(RelationGetRelationName(rel)),
                               5643                 :                :                      -1);
                               5644                 :           9634 :     atstmt->relation->inh = recurse;
                               5645                 :           9634 :     atstmt->cmds = list_make1(cmd);
 1373 michael@paquier.xyz      5646                 :           9634 :     atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
 1551 tgl@sss.pgh.pa.us        5647                 :           9634 :     atstmt->missing_ok = false;
                               5648                 :                : 
                               5649                 :                :     /* Transform the AlterTableStmt */
                               5650                 :           9634 :     atstmt = transformAlterTableStmt(RelationGetRelid(rel),
                               5651                 :                :                                      atstmt,
                               5652                 :                :                                      context->queryString,
                               5653                 :                :                                      &beforeStmts,
                               5654                 :                :                                      &afterStmts);
                               5655                 :                : 
                               5656                 :                :     /* Execute any statements that should happen before these subcommand(s) */
                               5657   [ +  +  +  +  :           9724 :     foreach(lc, beforeStmts)
                                              +  + ]
                               5658                 :                :     {
                               5659                 :            222 :         Node       *stmt = (Node *) lfirst(lc);
                               5660                 :                : 
                               5661                 :            222 :         ProcessUtilityForAlterTable(stmt, context);
                               5662                 :            216 :         CommandCounterIncrement();
                               5663                 :                :     }
                               5664                 :                : 
                               5665                 :                :     /* Examine the transformed subcommands and schedule them appropriately */
                               5666   [ +  -  +  +  :          22651 :     foreach(lc, atstmt->cmds)
                                              +  + ]
                               5667                 :                :     {
                               5668                 :          13149 :         AlterTableCmd *cmd2 = lfirst_node(AlterTableCmd, lc);
                               5669                 :                :         AlterTablePass pass;
                               5670                 :                : 
                               5671                 :                :         /*
                               5672                 :                :          * This switch need only cover the subcommand types that can be added
                               5673                 :                :          * by parse_utilcmd.c; otherwise, we'll use the default strategy of
                               5674                 :                :          * executing the subcommand immediately, as a substitute for the
                               5675                 :                :          * original subcommand.  (Note, however, that this does cause
                               5676                 :                :          * AT_AddConstraint subcommands to be rescheduled into later passes,
                               5677                 :                :          * which is important for index and foreign key constraints.)
                               5678                 :                :          *
                               5679                 :                :          * We assume we needn't do any phase-1 checks for added subcommands.
                               5680                 :                :          */
 1331                          5681   [ +  +  +  +  :          13149 :         switch (cmd2->subtype)
                                              -  + ]
                               5682                 :                :         {
  233 alvherre@alvh.no-ip.     5683                 :GNC        3491 :             case AT_SetAttNotNull:
                               5684                 :           3491 :                 ATSimpleRecursion(wqueue, rel, cmd2, recurse, lockmode, context);
 1331 tgl@sss.pgh.pa.us        5685                 :CBC        3491 :                 pass = AT_PASS_COL_ATTRS;
                               5686                 :           3491 :                 break;
                               5687                 :            509 :             case AT_AddIndex:
                               5688                 :                : 
                               5689                 :                :                 /*
                               5690                 :                :                  * A primary key on a inheritance parent needs supporting NOT
                               5691                 :                :                  * NULL constraint on its children; enqueue commands to create
                               5692                 :                :                  * those or mark them inherited if they already exist.
                               5693                 :                :                  */
  233 alvherre@alvh.no-ip.     5694                 :GNC         509 :                 ATPrepAddPrimaryKey(wqueue, rel, cmd2, lockmode, context);
 1331 tgl@sss.pgh.pa.us        5695                 :CBC         509 :                 pass = AT_PASS_ADD_INDEX;
                               5696                 :            509 :                 break;
                               5697                 :           4107 :             case AT_AddIndexConstraint:
                               5698                 :                :                 /* as above */
  233 alvherre@alvh.no-ip.     5699                 :GNC        4107 :                 ATPrepAddPrimaryKey(wqueue, rel, cmd2, lockmode, context);
 1331 tgl@sss.pgh.pa.us        5700                 :CBC        4107 :                 pass = AT_PASS_ADD_INDEXCONSTR;
                               5701                 :           4107 :                 break;
                               5702                 :           1835 :             case AT_AddConstraint:
                               5703                 :                :                 /* Recursion occurs during execution phase */
                               5704         [ +  + ]:           1835 :                 if (recurse)
  489 alvherre@alvh.no-ip.     5705                 :           1810 :                     cmd2->recurse = true;
 1331 tgl@sss.pgh.pa.us        5706         [ -  + ]:           1835 :                 switch (castNode(Constraint, cmd2->def)->contype)
                               5707                 :                :                 {
 1331 tgl@sss.pgh.pa.us        5708                 :UBC           0 :                     case CONSTR_PRIMARY:
                               5709                 :                :                     case CONSTR_UNIQUE:
                               5710                 :                :                     case CONSTR_EXCLUSION:
                               5711                 :              0 :                         pass = AT_PASS_ADD_INDEXCONSTR;
                               5712                 :              0 :                         break;
 1331 tgl@sss.pgh.pa.us        5713                 :CBC        1835 :                     default:
                               5714                 :           1835 :                         pass = AT_PASS_ADD_OTHERCONSTR;
                               5715                 :           1835 :                         break;
                               5716                 :                :                 }
                               5717                 :           1835 :                 break;
 1331 tgl@sss.pgh.pa.us        5718                 :UBC           0 :             case AT_AlterColumnGenericOptions:
                               5719                 :                :                 /* This command never recurses */
                               5720                 :                :                 /* No command-specific prep needed */
                               5721                 :              0 :                 pass = AT_PASS_MISC;
                               5722                 :              0 :                 break;
 1331 tgl@sss.pgh.pa.us        5723                 :CBC        3207 :             default:
                               5724                 :           3207 :                 pass = cur_pass;
                               5725                 :           3207 :                 break;
                               5726                 :                :         }
                               5727                 :                : 
                               5728         [ -  + ]:          13149 :         if (pass < cur_pass)
                               5729                 :                :         {
                               5730                 :                :             /* Cannot schedule into a pass we already finished */
 1331 tgl@sss.pgh.pa.us        5731         [ #  # ]:UBC           0 :             elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
                               5732                 :                :                  pass);
                               5733                 :                :         }
 1331 tgl@sss.pgh.pa.us        5734         [ +  + ]:CBC       13149 :         else if (pass > cur_pass)
                               5735                 :                :         {
                               5736                 :                :             /* OK, queue it up for later */
                               5737                 :           9942 :             tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
                               5738                 :                :         }
                               5739                 :                :         else
                               5740                 :                :         {
                               5741                 :                :             /*
                               5742                 :                :              * We should see at most one subcommand for the current pass,
                               5743                 :                :              * which is the transformed version of the original subcommand.
                               5744                 :                :              */
                               5745   [ +  -  +  - ]:           3207 :             if (newcmd == NULL && cmd->subtype == cmd2->subtype)
                               5746                 :                :             {
                               5747                 :                :                 /* Found the transformed version of our subcommand */
                               5748                 :           3207 :                 newcmd = cmd2;
                               5749                 :                :             }
                               5750                 :                :             else
 1331 tgl@sss.pgh.pa.us        5751         [ #  # ]:UBC           0 :                 elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
                               5752                 :                :                      pass);
                               5753                 :                :         }
                               5754                 :                :     }
                               5755                 :                : 
                               5756                 :                :     /* Queue up any after-statements to happen at the end */
 1551 tgl@sss.pgh.pa.us        5757                 :CBC        9502 :     tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
                               5758                 :                : 
                               5759                 :           9502 :     return newcmd;
                               5760                 :                : }
                               5761                 :                : 
                               5762                 :                : /*
                               5763                 :                :  * ATRewriteTables: ALTER TABLE phase 3
                               5764                 :                :  */
                               5765                 :                : static void
                               5766                 :          15677 : ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
                               5767                 :                :                 AlterTableUtilityContext *context)
                               5768                 :                : {
                               5769                 :                :     ListCell   *ltab;
                               5770                 :                : 
                               5771                 :                :     /* Go through each table that needs to be checked or rewritten */
 7284                          5772   [ +  -  +  +  :          33078 :     foreach(ltab, *wqueue)
                                              +  + ]
                               5773                 :                :     {
                               5774                 :          17523 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
                               5775                 :                : 
                               5776                 :                :         /* Relations without storage may be ignored here */
 1835                          5777   [ +  +  +  +  :          17523 :         if (!RELKIND_HAS_STORAGE(tab->relkind))
                                     +  +  +  -  +  
                                                 + ]
 4852 rhaas@postgresql.org     5778                 :           3057 :             continue;
                               5779                 :                : 
                               5780                 :                :         /*
                               5781                 :                :          * If we change column data types, the operation has to be propagated
                               5782                 :                :          * to tables that use this table's rowtype as a column type.
                               5783                 :                :          * tab->newvals will also be non-NULL in the case where we're adding a
                               5784                 :                :          * column with a default.  We choose to forbid that case as well,
                               5785                 :                :          * since composite types might eventually support defaults.
                               5786                 :                :          *
                               5787                 :                :          * (Eventually we'll probably need to check for composite type
                               5788                 :                :          * dependencies even when we're just scanning the table without a
                               5789                 :                :          * rewrite, but at the moment a composite type does not enforce any
                               5790                 :                :          * constraints, so it's not necessary/appropriate to enforce them just
                               5791                 :                :          * during ALTER.)
                               5792                 :                :          */
 3415 simon@2ndQuadrant.co     5793   [ +  +  +  + ]:          14466 :         if (tab->newvals != NIL || tab->rewrite > 0)
                               5794                 :                :         {
                               5795                 :                :             Relation    rel;
                               5796                 :                : 
 1910 andres@anarazel.de       5797                 :            726 :             rel = table_open(tab->relid, NoLock);
 4810 rhaas@postgresql.org     5798                 :            726 :             find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
 1910 andres@anarazel.de       5799                 :            720 :             table_close(rel, NoLock);
                               5800                 :                :         }
                               5801                 :                : 
                               5802                 :                :         /*
                               5803                 :                :          * We only need to rewrite the table if at least one column needs to
                               5804                 :                :          * be recomputed, or we are changing its persistence or access method.
                               5805                 :                :          *
                               5806                 :                :          * There are two reasons for requiring a rewrite when changing
                               5807                 :                :          * persistence: on one hand, we need to ensure that the buffers
                               5808                 :                :          * belonging to each of the two relations are marked with or without
                               5809                 :                :          * BM_PERMANENT properly.  On the other hand, since rewriting creates
                               5810                 :                :          * and assigns a new relfilenumber, we automatically create or drop an
                               5811                 :                :          * init fork for the relation as appropriate.
                               5812                 :                :          */
  738 peter@eisentraut.org     5813   [ +  +  +  + ]:          14460 :         if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE)
 7284 tgl@sss.pgh.pa.us        5814                 :            422 :         {
                               5815                 :                :             /* Build a temporary relation and copy data */
                               5816                 :                :             Relation    OldHeap;
                               5817                 :                :             Oid         OIDNewHeap;
                               5818                 :                :             Oid         NewAccessMethod;
                               5819                 :                :             Oid         NewTableSpace;
                               5820                 :                :             char        persistence;
                               5821                 :                : 
 1910 andres@anarazel.de       5822                 :            441 :             OldHeap = table_open(tab->relid, NoLock);
                               5823                 :                : 
                               5824                 :                :             /*
                               5825                 :                :              * We don't support rewriting of system catalogs; there are too
                               5826                 :                :              * many corner cases and too little benefit.  In particular this
                               5827                 :                :              * is certainly not going to work for mapped catalogs.
                               5828                 :                :              */
 5180 tgl@sss.pgh.pa.us        5829         [ -  + ]:            441 :             if (IsSystemRelation(OldHeap))
 7281 tgl@sss.pgh.pa.us        5830         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               5831                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               5832                 :                :                          errmsg("cannot rewrite system relation \"%s\"",
                               5833                 :                :                                 RelationGetRelationName(OldHeap))));
                               5834                 :                : 
 3778 rhaas@postgresql.org     5835   [ +  +  -  +  :CBC         441 :             if (RelationIsUsedAsCatalogTable(OldHeap))
                                        -  -  +  + ]
                               5836         [ +  - ]:              1 :                 ereport(ERROR,
                               5837                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               5838                 :                :                          errmsg("cannot rewrite table \"%s\" used as a catalog table",
                               5839                 :                :                                 RelationGetRelationName(OldHeap))));
                               5840                 :                : 
                               5841                 :                :             /*
                               5842                 :                :              * Don't allow rewrite on temp tables of other backends ... their
                               5843                 :                :              * local buffer manager is not going to cope.
                               5844                 :                :              */
 5493 tgl@sss.pgh.pa.us        5845   [ +  +  -  + ]:            440 :             if (RELATION_IS_OTHER_TEMP(OldHeap))
 7281 tgl@sss.pgh.pa.us        5846         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               5847                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               5848                 :                :                          errmsg("cannot rewrite temporary tables of other sessions")));
                               5849                 :                : 
                               5850                 :                :             /*
                               5851                 :                :              * Select destination tablespace (same as original unless user
                               5852                 :                :              * requested a change)
                               5853                 :                :              */
 7217 tgl@sss.pgh.pa.us        5854         [ -  + ]:CBC         440 :             if (tab->newTableSpace)
 7217 tgl@sss.pgh.pa.us        5855                 :UBC           0 :                 NewTableSpace = tab->newTableSpace;
                               5856                 :                :             else
 7217 tgl@sss.pgh.pa.us        5857                 :CBC         440 :                 NewTableSpace = OldHeap->rd_rel->reltablespace;
                               5858                 :                : 
                               5859                 :                :             /*
                               5860                 :                :              * Select destination access method (same as original unless user
                               5861                 :                :              * requested a change)
                               5862                 :                :              */
   20 alvherre@alvh.no-ip.     5863         [ +  + ]:GNC         440 :             if (tab->chgAccessMethod)
  991 michael@paquier.xyz      5864                 :CBC          18 :                 NewAccessMethod = tab->newAccessMethod;
                               5865                 :                :             else
                               5866                 :            422 :                 NewAccessMethod = OldHeap->rd_rel->relam;
                               5867                 :                : 
                               5868                 :                :             /*
                               5869                 :                :              * Select persistence of transient table (same as original unless
                               5870                 :                :              * user requested a change)
                               5871                 :                :              */
 3520 alvherre@alvh.no-ip.     5872         [ +  + ]:            440 :             persistence = tab->chgPersistence ?
 3523                          5873                 :            414 :                 tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
                               5874                 :                : 
 1910 andres@anarazel.de       5875                 :            440 :             table_close(OldHeap, NoLock);
                               5876                 :                : 
                               5877                 :                :             /*
                               5878                 :                :              * Fire off an Event Trigger now, before actually rewriting the
                               5879                 :                :              * table.
                               5880                 :                :              *
                               5881                 :                :              * We don't support Event Trigger for nested commands anywhere,
                               5882                 :                :              * here included, and parsetree is given NULL when coming from
                               5883                 :                :              * AlterTableInternal.
                               5884                 :                :              *
                               5885                 :                :              * And fire it only once.
                               5886                 :                :              */
 3415 simon@2ndQuadrant.co     5887         [ +  - ]:            440 :             if (parsetree)
 3249 bruce@momjian.us         5888                 :            440 :                 EventTriggerTableRewrite((Node *) parsetree,
                               5889                 :                :                                          tab->relid,
                               5890                 :                :                                          tab->rewrite);
                               5891                 :                : 
                               5892                 :                :             /*
                               5893                 :                :              * Create transient table that will receive the modified data.
                               5894                 :                :              *
                               5895                 :                :              * Ensure it is marked correctly as logged or unlogged.  We have
                               5896                 :                :              * to do this here so that buffers for the new relfilenumber will
                               5897                 :                :              * have the right persistence set, and at the same time ensure
                               5898                 :                :              * that the original filenumbers's buffers will get read in with
                               5899                 :                :              * the correct setting (i.e. the original one).  Otherwise a
                               5900                 :                :              * rollback after the rewrite would possibly result with buffers
                               5901                 :                :              * for the original filenumbers having the wrong persistence
                               5902                 :                :              * setting.
                               5903                 :                :              *
                               5904                 :                :              * NB: This relies on swap_relation_files() also swapping the
                               5905                 :                :              * persistence. That wouldn't work for pg_class, but that can't be
                               5906                 :                :              * unlogged anyway.
                               5907                 :                :              */
  991 michael@paquier.xyz      5908                 :            437 :             OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod,
                               5909                 :                :                                        persistence, lockmode);
                               5910                 :                : 
                               5911                 :                :             /*
                               5912                 :                :              * Copy the heap data into the new table with the desired
                               5913                 :                :              * modifications, and test the current data within the table
                               5914                 :                :              * against new constraints generated by ALTER TABLE commands.
                               5915                 :                :              */
 5009 simon@2ndQuadrant.co     5916                 :            437 :             ATRewriteTable(tab, OIDNewHeap, lockmode);
                               5917                 :                : 
                               5918                 :                :             /*
                               5919                 :                :              * Swap the physical files of the old and new heaps, then rebuild
                               5920                 :                :              * indexes and discard the old heap.  We can use RecentXmin for
                               5921                 :                :              * the table's new relfrozenxid because we rewrote all the tuples
                               5922                 :                :              * in ATRewriteTable, so no older Xid remains in the table.  Also,
                               5923                 :                :              * we never try to swap toast tables by content, since we have no
                               5924                 :                :              * interest in letting this code work on system catalogs.
                               5925                 :                :              */
 4833 rhaas@postgresql.org     5926                 :            425 :             finish_heap_swap(tab->relid, OIDNewHeap,
                               5927                 :                :                              false, false, true,
 4046                          5928                 :            425 :                              !OidIsValid(tab->newTableSpace),
                               5929                 :                :                              RecentXmin,
                               5930                 :                :                              ReadNextMultiXactId(),
                               5931                 :                :                              persistence);
                               5932                 :                : 
  978 michael@paquier.xyz      5933         [ -  + ]:            422 :             InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0);
                               5934                 :                :         }
  738 peter@eisentraut.org     5935   [ +  +  +  - ]:          14019 :         else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE)
                               5936                 :                :         {
                               5937         [ +  - ]:              6 :             if (tab->chgPersistence)
                               5938                 :              6 :                 SequenceChangePersistence(tab->relid, tab->newrelpersistence);
                               5939                 :                :         }
                               5940                 :                :         else
                               5941                 :                :         {
                               5942                 :                :             /*
                               5943                 :                :              * If required, test the current data within the table against new
                               5944                 :                :              * constraints generated by ALTER TABLE commands, but don't
                               5945                 :                :              * rebuild data.
                               5946                 :                :              */
 1859 rhaas@postgresql.org     5947   [ +  +  +  + ]:          14013 :             if (tab->constraints != NIL || tab->verify_new_notnull ||
 2576 tgl@sss.pgh.pa.us        5948         [ +  + ]:          12680 :                 tab->partition_constraint != NULL)
 5009 simon@2ndQuadrant.co     5949                 :           2225 :                 ATRewriteTable(tab, InvalidOid, lockmode);
                               5950                 :                : 
                               5951                 :                :             /*
                               5952                 :                :              * If we had SET TABLESPACE but no reason to reconstruct tuples,
                               5953                 :                :              * just do a block-by-block copy.
                               5954                 :                :              */
 7217 tgl@sss.pgh.pa.us        5955         [ +  + ]:          13916 :             if (tab->newTableSpace)
 5009 simon@2ndQuadrant.co     5956                 :             61 :                 ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
                               5957                 :                :         }
                               5958                 :                : 
                               5959                 :                :         /*
                               5960                 :                :          * Also change persistence of owned sequences, so that it matches the
                               5961                 :                :          * table persistence.
                               5962                 :                :          */
  738 peter@eisentraut.org     5963         [ +  + ]:          14344 :         if (tab->chgPersistence)
                               5964                 :                :         {
                               5965                 :             32 :             List       *seqlist = getOwnedSequences(tab->relid);
                               5966                 :                :             ListCell   *lc;
                               5967                 :                : 
                               5968   [ +  +  +  +  :             56 :             foreach(lc, seqlist)
                                              +  + ]
                               5969                 :                :             {
  703 tgl@sss.pgh.pa.us        5970                 :             24 :                 Oid         seq_relid = lfirst_oid(lc);
                               5971                 :                : 
  738 peter@eisentraut.org     5972                 :             24 :                 SequenceChangePersistence(seq_relid, tab->newrelpersistence);
                               5973                 :                :             }
                               5974                 :                :         }
                               5975                 :                :     }
                               5976                 :                : 
                               5977                 :                :     /*
                               5978                 :                :      * Foreign key constraints are checked in a final pass, since (a) it's
                               5979                 :                :      * generally best to examine each one separately, and (b) it's at least
                               5980                 :                :      * theoretically possible that we have changed both relations of the
                               5981                 :                :      * foreign key, and we'd better have finished both rewrites before we try
                               5982                 :                :      * to read the tables.
                               5983                 :                :      */
 7284 tgl@sss.pgh.pa.us        5984   [ +  -  +  +  :          32854 :     foreach(ltab, *wqueue)
                                              +  + ]
                               5985                 :                :     {
 7168 bruce@momjian.us         5986                 :          17339 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
                               5987                 :          17339 :         Relation    rel = NULL;
                               5988                 :                :         ListCell   *lcon;
                               5989                 :                : 
                               5990                 :                :         /* Relations without storage may be ignored here too */
 1835 tgl@sss.pgh.pa.us        5991   [ +  +  +  +  :          17339 :         if (!RELKIND_HAS_STORAGE(tab->relkind))
                                     +  +  +  -  +  
                                                 + ]
                               5992                 :           3020 :             continue;
                               5993                 :                : 
 7284                          5994   [ +  +  +  +  :          15147 :         foreach(lcon, tab->constraints)
                                              +  + ]
                               5995                 :                :         {
                               5996                 :            868 :             NewConstraint *con = lfirst(lcon);
                               5997                 :                : 
                               5998         [ +  + ]:            868 :             if (con->contype == CONSTR_FOREIGN)
                               5999                 :                :             {
 5372                          6000                 :            542 :                 Constraint *fkconstraint = (Constraint *) con->qual;
                               6001                 :                :                 Relation    refrel;
                               6002                 :                : 
 7284                          6003         [ +  + ]:            542 :                 if (rel == NULL)
                               6004                 :                :                 {
                               6005                 :                :                     /* Long since locked, no need for another */
 1910 andres@anarazel.de       6006                 :            536 :                     rel = table_open(tab->relid, NoLock);
                               6007                 :                :                 }
                               6008                 :                : 
                               6009                 :            542 :                 refrel = table_open(con->refrelid, RowShareLock);
                               6010                 :                : 
 4814 simon@2ndQuadrant.co     6011                 :            542 :                 validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
                               6012                 :                :                                              con->refindid,
                               6013                 :                :                                              con->conid,
   21 peter@eisentraut.org     6014                 :GNC         542 :                                              con->conwithperiod);
                               6015                 :                : 
                               6016                 :                :                 /*
                               6017                 :                :                  * No need to mark the constraint row as validated, we did
                               6018                 :                :                  * that when we inserted the row earlier.
                               6019                 :                :                  */
                               6020                 :                : 
 1910 andres@anarazel.de       6021                 :CBC         502 :                 table_close(refrel, NoLock);
                               6022                 :                :             }
                               6023                 :                :         }
                               6024                 :                : 
 7284 tgl@sss.pgh.pa.us        6025         [ +  + ]:          14279 :         if (rel)
 1910 andres@anarazel.de       6026                 :            496 :             table_close(rel, NoLock);
                               6027                 :                :     }
                               6028                 :                : 
                               6029                 :                :     /* Finally, run any afterStmts that were queued up */
 1551 tgl@sss.pgh.pa.us        6030   [ +  -  +  +  :          32795 :     foreach(ltab, *wqueue)
                                              +  + ]
                               6031                 :                :     {
                               6032                 :          17280 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
                               6033                 :                :         ListCell   *lc;
                               6034                 :                : 
                               6035   [ +  +  +  +  :          17323 :         foreach(lc, tab->afterStmts)
                                              +  + ]
                               6036                 :                :         {
                               6037                 :             43 :             Node       *stmt = (Node *) lfirst(lc);
                               6038                 :                : 
                               6039                 :             43 :             ProcessUtilityForAlterTable(stmt, context);
                               6040                 :             43 :             CommandCounterIncrement();
                               6041                 :                :         }
                               6042                 :                :     }
 7284                          6043                 :          15515 : }
                               6044                 :                : 
                               6045                 :                : /*
                               6046                 :                :  * ATRewriteTable: scan or rewrite one table
                               6047                 :                :  *
                               6048                 :                :  * OIDNewHeap is InvalidOid if we don't need to rewrite
                               6049                 :                :  */
                               6050                 :                : static void
 5009 simon@2ndQuadrant.co     6051                 :           2662 : ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
                               6052                 :                : {
                               6053                 :                :     Relation    oldrel;
                               6054                 :                :     Relation    newrel;
                               6055                 :                :     TupleDesc   oldTupDesc;
                               6056                 :                :     TupleDesc   newTupDesc;
 7284 tgl@sss.pgh.pa.us        6057                 :           2662 :     bool        needscan = false;
                               6058                 :                :     List       *notnull_attrs;
                               6059                 :                :     int         i;
                               6060                 :                :     ListCell   *l;
                               6061                 :                :     EState     *estate;
                               6062                 :                :     CommandId   mycid;
                               6063                 :                :     BulkInsertState bistate;
                               6064                 :                :     int         ti_options;
 2588 andres@anarazel.de       6065                 :           2662 :     ExprState  *partqualstate = NULL;
                               6066                 :                : 
                               6067                 :                :     /*
                               6068                 :                :      * Open the relation(s).  We have surely already locked the existing
                               6069                 :                :      * table.
                               6070                 :                :      */
 1910                          6071                 :           2662 :     oldrel = table_open(tab->relid, NoLock);
 7284 tgl@sss.pgh.pa.us        6072                 :           2662 :     oldTupDesc = tab->oldDesc;
 2489                          6073                 :           2662 :     newTupDesc = RelationGetDescr(oldrel);  /* includes all mods */
                               6074                 :                : 
 7284                          6075         [ +  + ]:           2662 :     if (OidIsValid(OIDNewHeap))
 1910 andres@anarazel.de       6076                 :            437 :         newrel = table_open(OIDNewHeap, lockmode);
                               6077                 :                :     else
 7284 tgl@sss.pgh.pa.us        6078                 :           2225 :         newrel = NULL;
                               6079                 :                : 
                               6080                 :                :     /*
                               6081                 :                :      * Prepare a BulkInsertState and options for table_tuple_insert.  The FSM
                               6082                 :                :      * is empty, so don't bother using it.
                               6083                 :                :      */
 5275 heikki.linnakangas@i     6084         [ +  + ]:           2662 :     if (newrel)
                               6085                 :                :     {
                               6086                 :            437 :         mycid = GetCurrentCommandId(true);
                               6087                 :            437 :         bistate = GetBulkInsertState();
 1840 andres@anarazel.de       6088                 :            437 :         ti_options = TABLE_INSERT_SKIP_FSM;
                               6089                 :                :     }
                               6090                 :                :     else
                               6091                 :                :     {
                               6092                 :                :         /* keep compiler quiet about using these uninitialized */
 5275 heikki.linnakangas@i     6093                 :           2225 :         mycid = 0;
                               6094                 :           2225 :         bistate = NULL;
 1840 andres@anarazel.de       6095                 :           2225 :         ti_options = 0;
                               6096                 :                :     }
                               6097                 :                : 
                               6098                 :                :     /*
                               6099                 :                :      * Generate the constraint and default execution states
                               6100                 :                :      */
                               6101                 :                : 
 7284 tgl@sss.pgh.pa.us        6102                 :           2662 :     estate = CreateExecutorState();
                               6103                 :                : 
                               6104                 :                :     /* Build the needed expression execution states */
                               6105   [ +  +  +  +  :           3578 :     foreach(l, tab->constraints)
                                              +  + ]
                               6106                 :                :     {
                               6107                 :            916 :         NewConstraint *con = lfirst(l);
                               6108                 :                : 
                               6109      [ +  +  - ]:            916 :         switch (con->contype)
                               6110                 :                :         {
                               6111                 :            371 :             case CONSTR_CHECK:
                               6112                 :            371 :                 needscan = true;
 2588 andres@anarazel.de       6113                 :            371 :                 con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
 7284 tgl@sss.pgh.pa.us        6114                 :            371 :                 break;
                               6115                 :            545 :             case CONSTR_FOREIGN:
                               6116                 :                :                 /* Nothing to do here */
                               6117                 :            545 :                 break;
 7284 tgl@sss.pgh.pa.us        6118                 :UBC           0 :             default:
                               6119         [ #  # ]:              0 :                 elog(ERROR, "unrecognized constraint type: %d",
                               6120                 :                :                      (int) con->contype);
                               6121                 :                :         }
                               6122                 :                :     }
                               6123                 :                : 
                               6124                 :                :     /* Build expression execution states for partition check quals */
 2685 rhaas@postgresql.org     6125         [ +  + ]:CBC        2662 :     if (tab->partition_constraint)
                               6126                 :                :     {
                               6127                 :            957 :         needscan = true;
 2576 tgl@sss.pgh.pa.us        6128                 :            957 :         partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
                               6129                 :                :     }
                               6130                 :                : 
 7284                          6131   [ +  +  +  +  :           3097 :     foreach(l, tab->newvals)
                                              +  + ]
                               6132                 :                :     {
 7168 bruce@momjian.us         6133                 :            435 :         NewColumnValue *ex = lfirst(l);
                               6134                 :                : 
                               6135                 :                :         /* expr already planned */
 4681 rhaas@postgresql.org     6136                 :            435 :         ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
                               6137                 :                :     }
                               6138                 :                : 
 6488 tgl@sss.pgh.pa.us        6139                 :           2662 :     notnull_attrs = NIL;
 1859 rhaas@postgresql.org     6140   [ +  +  +  + ]:           2662 :     if (newrel || tab->verify_new_notnull)
                               6141                 :                :     {
                               6142                 :                :         /*
                               6143                 :                :          * If we are rebuilding the tuples OR if we added any new but not
                               6144                 :                :          * verified not-null constraints, check all not-null constraints. This
                               6145                 :                :          * is a bit of overkill but it minimizes risk of bugs, and
                               6146                 :                :          * heap_attisnull is a pretty cheap test anyway.
                               6147                 :                :          */
 6488 tgl@sss.pgh.pa.us        6148         [ +  + ]:           3479 :         for (i = 0; i < newTupDesc->natts; i++)
                               6149                 :                :         {
 2429 andres@anarazel.de       6150                 :           2552 :             Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
                               6151                 :                : 
                               6152   [ +  +  +  - ]:           2552 :             if (attr->attnotnull && !attr->attisdropped)
 6488 tgl@sss.pgh.pa.us        6153                 :           1005 :                 notnull_attrs = lappend_int(notnull_attrs, i);
                               6154                 :                :         }
                               6155         [ +  + ]:            927 :         if (notnull_attrs)
                               6156                 :            725 :             needscan = true;
                               6157                 :                :     }
                               6158                 :                : 
 5541                          6159   [ +  +  +  + ]:           2662 :     if (newrel || needscan)
                               6160                 :                :     {
                               6161                 :                :         ExprContext *econtext;
                               6162                 :                :         TupleTableSlot *oldslot;
                               6163                 :                :         TupleTableSlot *newslot;
                               6164                 :                :         TableScanDesc scan;
                               6165                 :                :         MemoryContext oldCxt;
 6756 bruce@momjian.us         6166                 :           2209 :         List       *dropped_attrs = NIL;
                               6167                 :                :         ListCell   *lc;
                               6168                 :                :         Snapshot    snapshot;
                               6169                 :                : 
 4810 rhaas@postgresql.org     6170         [ +  + ]:           2209 :         if (newrel)
                               6171         [ -  + ]:            437 :             ereport(DEBUG1,
                               6172                 :                :                     (errmsg_internal("rewriting table \"%s\"",
                               6173                 :                :                                      RelationGetRelationName(oldrel))));
                               6174                 :                :         else
                               6175         [ +  + ]:           1772 :             ereport(DEBUG1,
                               6176                 :                :                     (errmsg_internal("verifying table \"%s\"",
                               6177                 :                :                                      RelationGetRelationName(oldrel))));
                               6178                 :                : 
 4694 heikki.linnakangas@i     6179         [ +  + ]:           2209 :         if (newrel)
                               6180                 :                :         {
                               6181                 :                :             /*
                               6182                 :                :              * All predicate locks on the tuples or pages are about to be made
                               6183                 :                :              * invalid, because we move tuples around.  Promote them to
                               6184                 :                :              * relation locks.
                               6185                 :                :              */
                               6186                 :            437 :             TransferPredicateLocksToHeapRelation(oldrel);
                               6187                 :                :         }
                               6188                 :                : 
 7284 tgl@sss.pgh.pa.us        6189         [ -  + ]:           2209 :         econtext = GetPerTupleExprContext(estate);
                               6190                 :                : 
                               6191                 :                :         /*
                               6192                 :                :          * Create necessary tuple slots. When rewriting, two slots are needed,
                               6193                 :                :          * otherwise one suffices. In the case where one slot suffices, we
                               6194                 :                :          * need to use the new tuple descriptor, otherwise some constraints
                               6195                 :                :          * can't be evaluated.  Note that even when the tuple layout is the
                               6196                 :                :          * same and no rewrite is required, the tupDescs might not be
                               6197                 :                :          * (consider ADD COLUMN without a default).
                               6198                 :                :          */
 1861 andres@anarazel.de       6199         [ +  + ]:           2209 :         if (tab->rewrite)
                               6200                 :                :         {
                               6201         [ -  + ]:            437 :             Assert(newrel != NULL);
                               6202                 :            437 :             oldslot = MakeSingleTupleTableSlot(oldTupDesc,
                               6203                 :                :                                                table_slot_callbacks(oldrel));
                               6204                 :            437 :             newslot = MakeSingleTupleTableSlot(newTupDesc,
                               6205                 :                :                                                table_slot_callbacks(newrel));
                               6206                 :                : 
                               6207                 :                :             /*
                               6208                 :                :              * Set all columns in the new slot to NULL initially, to ensure
                               6209                 :                :              * columns added as part of the rewrite are initialized to NULL.
                               6210                 :                :              * That is necessary as tab->newvals will not contain an
                               6211                 :                :              * expression for columns with a NULL default, e.g. when adding a
                               6212                 :                :              * column without a default together with a column with a default
                               6213                 :                :              * requiring an actual rewrite.
                               6214                 :                :              */
 1649                          6215                 :            437 :             ExecStoreAllNullTuple(newslot);
                               6216                 :                :         }
                               6217                 :                :         else
                               6218                 :                :         {
 1861                          6219                 :           1772 :             oldslot = MakeSingleTupleTableSlot(newTupDesc,
                               6220                 :                :                                                table_slot_callbacks(oldrel));
                               6221                 :           1772 :             newslot = NULL;
                               6222                 :                :         }
                               6223                 :                : 
                               6224                 :                :         /*
                               6225                 :                :          * Any attributes that are dropped according to the new tuple
                               6226                 :                :          * descriptor can be set to NULL. We precompute the list of dropped
                               6227                 :                :          * attributes to avoid needing to do so in the per-tuple loop.
                               6228                 :                :          */
 7004 neilc@samurai.com        6229         [ +  + ]:           7896 :         for (i = 0; i < newTupDesc->natts; i++)
                               6230                 :                :         {
 2429 andres@anarazel.de       6231         [ +  + ]:           5687 :             if (TupleDescAttr(newTupDesc, i)->attisdropped)
 7004 neilc@samurai.com        6232                 :            395 :                 dropped_attrs = lappend_int(dropped_attrs, i);
                               6233                 :                :         }
                               6234                 :                : 
                               6235                 :                :         /*
                               6236                 :                :          * Scan through the rows, generating a new row if needed and then
                               6237                 :                :          * checking all the constraints.
                               6238                 :                :          */
 3939 rhaas@postgresql.org     6239                 :           2209 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
 1861 andres@anarazel.de       6240                 :           2209 :         scan = table_beginscan(oldrel, snapshot, 0, NULL);
                               6241                 :                : 
                               6242                 :                :         /*
                               6243                 :                :          * Switch to per-tuple memory context and reset it for each tuple
                               6244                 :                :          * produced, so we don't leak memory.
                               6245                 :                :          */
 7004 neilc@samurai.com        6246         [ +  - ]:           2209 :         oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
                               6247                 :                : 
 1861 andres@anarazel.de       6248         [ +  + ]:         385696 :         while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
                               6249                 :                :         {
                               6250                 :                :             TupleTableSlot *insertslot;
                               6251                 :                : 
 3415 simon@2ndQuadrant.co     6252         [ +  + ]:         381387 :             if (tab->rewrite > 0)
                               6253                 :                :             {
                               6254                 :                :                 /* Extract data from old tuple */
 1861 andres@anarazel.de       6255                 :          48776 :                 slot_getallattrs(oldslot);
                               6256                 :          48776 :                 ExecClearTuple(newslot);
                               6257                 :                : 
                               6258                 :                :                 /* copy attributes */
                               6259                 :          48776 :                 memcpy(newslot->tts_values, oldslot->tts_values,
                               6260                 :          48776 :                        sizeof(Datum) * oldslot->tts_nvalid);
                               6261                 :          48776 :                 memcpy(newslot->tts_isnull, oldslot->tts_isnull,
                               6262                 :          48776 :                        sizeof(bool) * oldslot->tts_nvalid);
                               6263                 :                : 
                               6264                 :                :                 /* Set dropped attributes to null in new tuple */
 6756 bruce@momjian.us         6265   [ +  +  +  +  :          48819 :                 foreach(lc, dropped_attrs)
                                              +  + ]
 1861 andres@anarazel.de       6266                 :             43 :                     newslot->tts_isnull[lfirst_int(lc)] = true;
                               6267                 :                : 
                               6268                 :                :                 /*
                               6269                 :                :                  * Constraints and GENERATED expressions might reference the
                               6270                 :                :                  * tableoid column, so fill tts_tableOid with the desired
                               6271                 :                :                  * value.  (We must do this each time, because it gets
                               6272                 :                :                  * overwritten with newrel's OID during storing.)
                               6273                 :                :                  */
 1059 tgl@sss.pgh.pa.us        6274                 :          48776 :                 newslot->tts_tableOid = RelationGetRelid(oldrel);
                               6275                 :                : 
                               6276                 :                :                 /*
                               6277                 :                :                  * Process supplied expressions to replace selected columns.
                               6278                 :                :                  *
                               6279                 :                :                  * First, evaluate expressions whose inputs come from the old
                               6280                 :                :                  * tuple.
                               6281                 :                :                  */
 7284                          6282                 :          48776 :                 econtext->ecxt_scantuple = oldslot;
                               6283                 :                : 
                               6284   [ +  +  +  +  :         100462 :                 foreach(l, tab->newvals)
                                              +  + ]
                               6285                 :                :                 {
 7168 bruce@momjian.us         6286                 :          51692 :                     NewColumnValue *ex = lfirst(l);
                               6287                 :                : 
 1558 tgl@sss.pgh.pa.us        6288         [ +  + ]:          51692 :                     if (ex->is_generated)
                               6289                 :             75 :                         continue;
                               6290                 :                : 
 1861 andres@anarazel.de       6291                 :          51617 :                     newslot->tts_values[ex->attnum - 1]
                               6292                 :          51611 :                         = ExecEvalExpr(ex->exprstate,
                               6293                 :                :                                        econtext,
                               6294                 :          51617 :                                        &newslot->tts_isnull[ex->attnum - 1]);
                               6295                 :                :                 }
                               6296                 :                : 
                               6297                 :          48770 :                 ExecStoreVirtualTuple(newslot);
                               6298                 :                : 
                               6299                 :                :                 /*
                               6300                 :                :                  * Now, evaluate any expressions whose inputs come from the
                               6301                 :                :                  * new tuple.  We assume these columns won't reference each
                               6302                 :                :                  * other, so that there's no ordering dependency.
                               6303                 :                :                  */
 1558 tgl@sss.pgh.pa.us        6304                 :          48770 :                 econtext->ecxt_scantuple = newslot;
                               6305                 :                : 
                               6306   [ +  +  +  +  :         100456 :                 foreach(l, tab->newvals)
                                              +  + ]
                               6307                 :                :                 {
                               6308                 :          51686 :                     NewColumnValue *ex = lfirst(l);
                               6309                 :                : 
                               6310         [ +  + ]:          51686 :                     if (!ex->is_generated)
                               6311                 :          51611 :                         continue;
                               6312                 :                : 
                               6313                 :             75 :                     newslot->tts_values[ex->attnum - 1]
                               6314                 :             75 :                         = ExecEvalExpr(ex->exprstate,
                               6315                 :                :                                        econtext,
                               6316                 :             75 :                                        &newslot->tts_isnull[ex->attnum - 1]);
                               6317                 :                :                 }
                               6318                 :                : 
 1861 andres@anarazel.de       6319                 :          48770 :                 insertslot = newslot;
                               6320                 :                :             }
                               6321                 :                :             else
                               6322                 :                :             {
                               6323                 :                :                 /*
                               6324                 :                :                  * If there's no rewrite, old and new table are guaranteed to
                               6325                 :                :                  * have the same AM, so we can just use the old slot to verify
                               6326                 :                :                  * new constraints etc.
                               6327                 :                :                  */
                               6328                 :         332611 :                 insertslot = oldslot;
                               6329                 :                :             }
                               6330                 :                : 
                               6331                 :                :             /* Now check any constraints on the possibly-changed tuple */
                               6332                 :         381381 :             econtext->ecxt_scantuple = insertslot;
                               6333                 :                : 
 6488 tgl@sss.pgh.pa.us        6334   [ +  +  +  +  :        1669532 :             foreach(l, notnull_attrs)
                                              +  + ]
                               6335                 :                :             {
 6402 bruce@momjian.us         6336                 :        1288181 :                 int         attn = lfirst_int(l);
                               6337                 :                : 
 1861 andres@anarazel.de       6338         [ +  + ]:        1288181 :                 if (slot_attisnull(insertslot, attn + 1))
                               6339                 :                :                 {
 2429                          6340                 :             30 :                     Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
                               6341                 :                : 
 6488 tgl@sss.pgh.pa.us        6342         [ +  - ]:             30 :                     ereport(ERROR,
                               6343                 :                :                             (errcode(ERRCODE_NOT_NULL_VIOLATION),
                               6344                 :                :                              errmsg("column \"%s\" of relation \"%s\" contains null values",
                               6345                 :                :                                     NameStr(attr->attname),
                               6346                 :                :                                     RelationGetRelationName(oldrel)),
                               6347                 :                :                              errtablecol(oldrel, attn + 1)));
                               6348                 :                :                 }
                               6349                 :                :             }
                               6350                 :                : 
 7284                          6351   [ +  +  +  +  :         385401 :             foreach(l, tab->constraints)
                                              +  + ]
                               6352                 :                :             {
                               6353                 :           4086 :                 NewConstraint *con = lfirst(l);
                               6354                 :                : 
                               6355      [ +  +  - ]:           4086 :                 switch (con->contype)
                               6356                 :                :                 {
                               6357                 :           4036 :                     case CONSTR_CHECK:
 2588 andres@anarazel.de       6358         [ +  + ]:           4036 :                         if (!ExecCheck(con->qualstate, econtext))
 7284 tgl@sss.pgh.pa.us        6359         [ +  - ]:             36 :                             ereport(ERROR,
                               6360                 :                :                                     (errcode(ERRCODE_CHECK_VIOLATION),
                               6361                 :                :                                      errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
                               6362                 :                :                                             con->name,
                               6363                 :                :                                             RelationGetRelationName(oldrel)),
                               6364                 :                :                                      errtableconstraint(oldrel, con->name)));
                               6365                 :           4000 :                         break;
  233 alvherre@alvh.no-ip.     6366                 :GNC          50 :                     case CONSTR_NOTNULL:
 7284 tgl@sss.pgh.pa.us        6367                 :ECB        (44) :                     case CONSTR_FOREIGN:
                               6368                 :                :                         /* Nothing to do here */
 7284 tgl@sss.pgh.pa.us        6369                 :CBC          50 :                         break;
 7284 tgl@sss.pgh.pa.us        6370                 :UBC           0 :                     default:
                               6371         [ #  # ]:              0 :                         elog(ERROR, "unrecognized constraint type: %d",
                               6372                 :                :                              (int) con->contype);
                               6373                 :                :                 }
                               6374                 :                :             }
                               6375                 :                : 
 2588 andres@anarazel.de       6376   [ +  +  +  + ]:CBC      381315 :             if (partqualstate && !ExecCheck(partqualstate, econtext))
                               6377                 :                :             {
 2410 rhaas@postgresql.org     6378         [ +  + ]:             37 :                 if (tab->validate_default)
                               6379         [ +  - ]:             13 :                     ereport(ERROR,
                               6380                 :                :                             (errcode(ERRCODE_CHECK_VIOLATION),
                               6381                 :                :                              errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
                               6382                 :                :                                     RelationGetRelationName(oldrel)),
                               6383                 :                :                              errtable(oldrel)));
                               6384                 :                :                 else
                               6385         [ +  - ]:             24 :                     ereport(ERROR,
                               6386                 :                :                             (errcode(ERRCODE_CHECK_VIOLATION),
                               6387                 :                :                              errmsg("partition constraint of relation \"%s\" is violated by some row",
                               6388                 :                :                                     RelationGetRelationName(oldrel)),
                               6389                 :                :                              errtable(oldrel)));
                               6390                 :                :             }
                               6391                 :                : 
                               6392                 :                :             /* Write the tuple out to the new relation */
 7284 tgl@sss.pgh.pa.us        6393         [ +  + ]:         381278 :             if (newrel)
 1788 andres@anarazel.de       6394                 :          48764 :                 table_tuple_insert(newrel, insertslot, mycid,
                               6395                 :                :                                    ti_options, bistate);
                               6396                 :                : 
 7284 tgl@sss.pgh.pa.us        6397                 :         381278 :             ResetExprContext(econtext);
                               6398                 :                : 
                               6399         [ -  + ]:         381278 :             CHECK_FOR_INTERRUPTS();
                               6400                 :                :         }
                               6401                 :                : 
 7004 neilc@samurai.com        6402                 :           2100 :         MemoryContextSwitchTo(oldCxt);
 1861 andres@anarazel.de       6403                 :           2100 :         table_endscan(scan);
 3939 rhaas@postgresql.org     6404                 :           2100 :         UnregisterSnapshot(snapshot);
                               6405                 :                : 
 6512 tgl@sss.pgh.pa.us        6406                 :           2100 :         ExecDropSingleTupleTableSlot(oldslot);
 1861 andres@anarazel.de       6407         [ +  + ]:           2100 :         if (newslot)
                               6408                 :            425 :             ExecDropSingleTupleTableSlot(newslot);
                               6409                 :                :     }
                               6410                 :                : 
 7284 tgl@sss.pgh.pa.us        6411                 :           2553 :     FreeExecutorState(estate);
                               6412                 :                : 
 1910 andres@anarazel.de       6413                 :           2553 :     table_close(oldrel, NoLock);
 7284 tgl@sss.pgh.pa.us        6414         [ +  + ]:           2553 :     if (newrel)
                               6415                 :                :     {
 5275 heikki.linnakangas@i     6416                 :            425 :         FreeBulkInsertState(bistate);
                               6417                 :                : 
 1840 andres@anarazel.de       6418                 :            425 :         table_finish_bulk_insert(newrel, ti_options);
                               6419                 :                : 
 1910                          6420                 :            425 :         table_close(newrel, NoLock);
                               6421                 :                :     }
 7284 tgl@sss.pgh.pa.us        6422                 :           2553 : }
                               6423                 :                : 
                               6424                 :                : /*
                               6425                 :                :  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
                               6426                 :                :  */
                               6427                 :                : static AlteredTableInfo *
                               6428                 :          21562 : ATGetQueueEntry(List **wqueue, Relation rel)
                               6429                 :                : {
                               6430                 :          21562 :     Oid         relid = RelationGetRelid(rel);
                               6431                 :                :     AlteredTableInfo *tab;
                               6432                 :                :     ListCell   *ltab;
                               6433                 :                : 
                               6434   [ +  +  +  +  :          26048 :     foreach(ltab, *wqueue)
                                              +  + ]
                               6435                 :                :     {
                               6436                 :           6979 :         tab = (AlteredTableInfo *) lfirst(ltab);
                               6437         [ +  + ]:           6979 :         if (tab->relid == relid)
                               6438                 :           2493 :             return tab;
                               6439                 :                :     }
                               6440                 :                : 
                               6441                 :                :     /*
                               6442                 :                :      * Not there, so add it.  Note that we make a copy of the relation's
                               6443                 :                :      * existing descriptor before anything interesting can happen to it.
                               6444                 :                :      */
                               6445                 :          19069 :     tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
                               6446                 :          19069 :     tab->relid = relid;
 1116 alvherre@alvh.no-ip.     6447                 :          19069 :     tab->rel = NULL;         /* set later */
 7281 tgl@sss.pgh.pa.us        6448                 :          19069 :     tab->relkind = rel->rd_rel->relkind;
 2209 andrew@dunslane.net      6449                 :          19069 :     tab->oldDesc = CreateTupleDescCopyConstr(RelationGetDescr(rel));
  991 michael@paquier.xyz      6450                 :          19069 :     tab->newAccessMethod = InvalidOid;
   20 alvherre@alvh.no-ip.     6451                 :GNC       19069 :     tab->chgAccessMethod = false;
  991 michael@paquier.xyz      6452                 :CBC       19069 :     tab->newTableSpace = InvalidOid;
 3523 alvherre@alvh.no-ip.     6453                 :          19069 :     tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
 3520                          6454                 :          19069 :     tab->chgPersistence = false;
                               6455                 :                : 
 7284 tgl@sss.pgh.pa.us        6456                 :          19069 :     *wqueue = lappend(*wqueue, tab);
                               6457                 :                : 
                               6458                 :          19069 :     return tab;
                               6459                 :                : }
                               6460                 :                : 
                               6461                 :                : static const char *
 1011 peter@eisentraut.org     6462                 :             21 : alter_table_type_to_string(AlterTableType cmdtype)
                               6463                 :                : {
                               6464   [ -  -  +  +  :             21 :     switch (cmdtype)
                                     -  -  -  -  +  
                                     -  -  -  +  -  
                                     -  +  -  -  -  
                                     -  -  -  -  -  
                                     -  -  -  -  -  
                                     -  -  -  -  -  
                                     -  -  -  -  -  
                                     -  -  -  -  -  
                                     -  -  -  -  -  
                                     -  -  -  -  -  
                                     -  +  -  -  -  
                                        -  -  -  -  
                                                 - ]
                               6465                 :                :     {
 1011 peter@eisentraut.org     6466                 :UBC           0 :         case AT_AddColumn:
                               6467                 :                :         case AT_AddColumnToView:
                               6468                 :              0 :             return "ADD COLUMN";
                               6469                 :              0 :         case AT_ColumnDefault:
                               6470                 :                :         case AT_CookedColumnDefault:
                               6471                 :              0 :             return "ALTER COLUMN ... SET DEFAULT";
 1011 peter@eisentraut.org     6472                 :CBC           3 :         case AT_DropNotNull:
                               6473                 :              3 :             return "ALTER COLUMN ... DROP NOT NULL";
                               6474                 :              3 :         case AT_SetNotNull:
                               6475                 :              3 :             return "ALTER COLUMN ... SET NOT NULL";
  233 alvherre@alvh.no-ip.     6476                 :UNC           0 :         case AT_SetAttNotNull:
                               6477                 :              0 :             return NULL;        /* not real grammar */
  101 peter@eisentraut.org     6478                 :              0 :         case AT_SetExpression:
                               6479                 :              0 :             return "ALTER COLUMN ... SET EXPRESSION";
 1011 peter@eisentraut.org     6480                 :UBC           0 :         case AT_DropExpression:
                               6481                 :              0 :             return "ALTER COLUMN ... DROP EXPRESSION";
                               6482                 :              0 :         case AT_SetStatistics:
                               6483                 :              0 :             return "ALTER COLUMN ... SET STATISTICS";
 1011 peter@eisentraut.org     6484                 :CBC           6 :         case AT_SetOptions:
                               6485                 :              6 :             return "ALTER COLUMN ... SET";
 1011 peter@eisentraut.org     6486                 :UBC           0 :         case AT_ResetOptions:
                               6487                 :              0 :             return "ALTER COLUMN ... RESET";
                               6488                 :              0 :         case AT_SetStorage:
                               6489                 :              0 :             return "ALTER COLUMN ... SET STORAGE";
                               6490                 :              0 :         case AT_SetCompression:
                               6491                 :              0 :             return "ALTER COLUMN ... SET COMPRESSION";
 1011 peter@eisentraut.org     6492                 :CBC           3 :         case AT_DropColumn:
                               6493                 :              3 :             return "DROP COLUMN";
 1011 peter@eisentraut.org     6494                 :UBC           0 :         case AT_AddIndex:
                               6495                 :                :         case AT_ReAddIndex:
 1004 tgl@sss.pgh.pa.us        6496                 :              0 :             return NULL;        /* not real grammar */
 1011 peter@eisentraut.org     6497                 :              0 :         case AT_AddConstraint:
                               6498                 :                :         case AT_ReAddConstraint:
                               6499                 :                :         case AT_ReAddDomainConstraint:
                               6500                 :                :         case AT_AddIndexConstraint:
                               6501                 :              0 :             return "ADD CONSTRAINT";
 1011 peter@eisentraut.org     6502                 :CBC           3 :         case AT_AlterConstraint:
                               6503                 :              3 :             return "ALTER CONSTRAINT";
 1011 peter@eisentraut.org     6504                 :UBC           0 :         case AT_ValidateConstraint:
                               6505                 :              0 :             return "VALIDATE CONSTRAINT";
                               6506                 :              0 :         case AT_DropConstraint:
                               6507                 :              0 :             return "DROP CONSTRAINT";
                               6508                 :              0 :         case AT_ReAddComment:
 1004 tgl@sss.pgh.pa.us        6509                 :              0 :             return NULL;        /* not real grammar */
 1011 peter@eisentraut.org     6510                 :              0 :         case AT_AlterColumnType:
                               6511                 :              0 :             return "ALTER COLUMN ... SET DATA TYPE";
                               6512                 :              0 :         case AT_AlterColumnGenericOptions:
                               6513                 :              0 :             return "ALTER COLUMN ... OPTIONS";
                               6514                 :              0 :         case AT_ChangeOwner:
                               6515                 :              0 :             return "OWNER TO";
                               6516                 :              0 :         case AT_ClusterOn:
                               6517                 :              0 :             return "CLUSTER ON";
                               6518                 :              0 :         case AT_DropCluster:
                               6519                 :              0 :             return "SET WITHOUT CLUSTER";
  991 michael@paquier.xyz      6520                 :              0 :         case AT_SetAccessMethod:
                               6521                 :              0 :             return "SET ACCESS METHOD";
 1011 peter@eisentraut.org     6522                 :              0 :         case AT_SetLogged:
                               6523                 :              0 :             return "SET LOGGED";
                               6524                 :              0 :         case AT_SetUnLogged:
                               6525                 :              0 :             return "SET UNLOGGED";
                               6526                 :              0 :         case AT_DropOids:
                               6527                 :              0 :             return "SET WITHOUT OIDS";
                               6528                 :              0 :         case AT_SetTableSpace:
                               6529                 :              0 :             return "SET TABLESPACE";
                               6530                 :              0 :         case AT_SetRelOptions:
                               6531                 :              0 :             return "SET";
                               6532                 :              0 :         case AT_ResetRelOptions:
                               6533                 :              0 :             return "RESET";
                               6534                 :              0 :         case AT_ReplaceRelOptions:
 1004 tgl@sss.pgh.pa.us        6535                 :              0 :             return NULL;        /* not real grammar */
 1011 peter@eisentraut.org     6536                 :              0 :         case AT_EnableTrig:
                               6537                 :              0 :             return "ENABLE TRIGGER";
                               6538                 :              0 :         case AT_EnableAlwaysTrig:
                               6539                 :              0 :             return "ENABLE ALWAYS TRIGGER";
                               6540                 :              0 :         case AT_EnableReplicaTrig:
                               6541                 :              0 :             return "ENABLE REPLICA TRIGGER";
                               6542                 :              0 :         case AT_DisableTrig:
                               6543                 :              0 :             return "DISABLE TRIGGER";
                               6544                 :              0 :         case AT_EnableTrigAll:
                               6545                 :              0 :             return "ENABLE TRIGGER ALL";
                               6546                 :              0 :         case AT_DisableTrigAll:
                               6547                 :              0 :             return "DISABLE TRIGGER ALL";
                               6548                 :              0 :         case AT_EnableTrigUser:
                               6549                 :              0 :             return "ENABLE TRIGGER USER";
                               6550                 :              0 :         case AT_DisableTrigUser:
                               6551                 :              0 :             return "DISABLE TRIGGER USER";
                               6552                 :              0 :         case AT_EnableRule:
                               6553                 :              0 :             return "ENABLE RULE";
                               6554                 :              0 :         case AT_EnableAlwaysRule:
                               6555                 :              0 :             return "ENABLE ALWAYS RULE";
                               6556                 :              0 :         case AT_EnableReplicaRule:
                               6557                 :              0 :             return "ENABLE REPLICA RULE";
                               6558                 :              0 :         case AT_DisableRule:
                               6559                 :              0 :             return "DISABLE RULE";
                               6560                 :              0 :         case AT_AddInherit:
                               6561                 :              0 :             return "INHERIT";
                               6562                 :              0 :         case AT_DropInherit:
                               6563                 :              0 :             return "NO INHERIT";
                               6564                 :              0 :         case AT_AddOf:
                               6565                 :              0 :             return "OF";
                               6566                 :              0 :         case AT_DropOf:
                               6567                 :              0 :             return "NOT OF";
                               6568                 :              0 :         case AT_ReplicaIdentity:
                               6569                 :              0 :             return "REPLICA IDENTITY";
                               6570                 :              0 :         case AT_EnableRowSecurity:
                               6571                 :              0 :             return "ENABLE ROW SECURITY";
                               6572                 :              0 :         case AT_DisableRowSecurity:
                               6573                 :              0 :             return "DISABLE ROW SECURITY";
                               6574                 :              0 :         case AT_ForceRowSecurity:
                               6575                 :              0 :             return "FORCE ROW SECURITY";
                               6576                 :              0 :         case AT_NoForceRowSecurity:
                               6577                 :              0 :             return "NO FORCE ROW SECURITY";
                               6578                 :              0 :         case AT_GenericOptions:
                               6579                 :              0 :             return "OPTIONS";
                               6580                 :              0 :         case AT_AttachPartition:
                               6581                 :              0 :             return "ATTACH PARTITION";
 1011 peter@eisentraut.org     6582                 :CBC           3 :         case AT_DetachPartition:
                               6583                 :              3 :             return "DETACH PARTITION";
 1011 peter@eisentraut.org     6584                 :UBC           0 :         case AT_DetachPartitionFinalize:
                               6585                 :              0 :             return "DETACH PARTITION ... FINALIZE";
    7 akorotkov@postgresql     6586                 :UNC           0 :         case AT_SplitPartition:
                               6587                 :              0 :             return "SPLIT PARTITION";
                               6588                 :              0 :         case AT_MergePartitions:
                               6589                 :              0 :             return "MERGE PARTITIONS";
 1011 peter@eisentraut.org     6590                 :UBC           0 :         case AT_AddIdentity:
                               6591                 :              0 :             return "ALTER COLUMN ... ADD IDENTITY";
                               6592                 :              0 :         case AT_SetIdentity:
                               6593                 :              0 :             return "ALTER COLUMN ... SET";
                               6594                 :              0 :         case AT_DropIdentity:
                               6595                 :              0 :             return "ALTER COLUMN ... DROP IDENTITY";
                               6596                 :              0 :         case AT_ReAddStatistics:
 1004 tgl@sss.pgh.pa.us        6597                 :              0 :             return NULL;        /* not real grammar */
                               6598                 :                :     }
                               6599                 :                : 
 1011 peter@eisentraut.org     6600                 :              0 :     return NULL;
                               6601                 :                : }
                               6602                 :                : 
                               6603                 :                : /*
                               6604                 :                :  * ATSimplePermissions
                               6605                 :                :  *
                               6606                 :                :  * - Ensure that it is a relation (or possibly a view)
                               6607                 :                :  * - Ensure this user is the owner
                               6608                 :                :  * - Ensure that it is not a system table
                               6609                 :                :  */
                               6610                 :                : static void
 1011 peter@eisentraut.org     6611                 :CBC       19752 : ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
                               6612                 :                : {
                               6613                 :                :     int         actual_target;
                               6614                 :                : 
 4852 rhaas@postgresql.org     6615   [ +  +  +  +  :          19752 :     switch (rel->rd_rel->relkind)
                                        +  +  +  +  
                                                 - ]
                               6616                 :                :     {
                               6617                 :          18655 :         case RELKIND_RELATION:
                               6618                 :                :         case RELKIND_PARTITIONED_TABLE:
                               6619                 :          18655 :             actual_target = ATT_TABLE;
                               6620                 :          18655 :             break;
                               6621                 :            198 :         case RELKIND_VIEW:
                               6622                 :            198 :             actual_target = ATT_VIEW;
                               6623                 :            198 :             break;
 4060 kgrittn@postgresql.o     6624                 :             23 :         case RELKIND_MATVIEW:
                               6625                 :             23 :             actual_target = ATT_MATVIEW;
                               6626                 :             23 :             break;
 4852 rhaas@postgresql.org     6627                 :            113 :         case RELKIND_INDEX:
                               6628                 :            113 :             actual_target = ATT_INDEX;
                               6629                 :            113 :             break;
 2277 alvherre@alvh.no-ip.     6630                 :            207 :         case RELKIND_PARTITIONED_INDEX:
                               6631                 :            207 :             actual_target = ATT_PARTITIONED_INDEX;
                               6632                 :            207 :             break;
 4852 rhaas@postgresql.org     6633                 :            107 :         case RELKIND_COMPOSITE_TYPE:
                               6634                 :            107 :             actual_target = ATT_COMPOSITE_TYPE;
                               6635                 :            107 :             break;
                               6636                 :            443 :         case RELKIND_FOREIGN_TABLE:
                               6637                 :            443 :             actual_target = ATT_FOREIGN_TABLE;
                               6638                 :            443 :             break;
  738 peter@eisentraut.org     6639                 :              6 :         case RELKIND_SEQUENCE:
                               6640                 :              6 :             actual_target = ATT_SEQUENCE;
                               6641                 :              6 :             break;
 4852 rhaas@postgresql.org     6642                 :UBC           0 :         default:
                               6643                 :              0 :             actual_target = 0;
                               6644                 :              0 :             break;
                               6645                 :                :     }
                               6646                 :                : 
                               6647                 :                :     /* Wrong target type? */
 4852 rhaas@postgresql.org     6648         [ +  + ]:CBC       19752 :     if ((actual_target & allowed_targets) == 0)
                               6649                 :                :     {
 1011 peter@eisentraut.org     6650                 :             21 :         const char *action_str = alter_table_type_to_string(cmdtype);
                               6651                 :                : 
                               6652         [ +  - ]:             21 :         if (action_str)
                               6653         [ +  - ]:             21 :             ereport(ERROR,
                               6654                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               6655                 :                :             /* translator: %s is a group of some SQL keywords */
                               6656                 :                :                      errmsg("ALTER action %s cannot be performed on relation \"%s\"",
                               6657                 :                :                             action_str, RelationGetRelationName(rel)),
                               6658                 :                :                      errdetail_relkind_not_supported(rel->rd_rel->relkind)));
                               6659                 :                :         else
                               6660                 :                :             /* internal error? */
 1011 peter@eisentraut.org     6661         [ #  # ]:UBC           0 :             elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
                               6662                 :                :                  RelationGetRelationName(rel));
                               6663                 :                :     }
                               6664                 :                : 
                               6665                 :                :     /* Permissions checks */
  518 peter@eisentraut.org     6666         [ +  + ]:CBC       19731 :     if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
 2325 peter_e@gmx.net          6667                 :              6 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
 7562 tgl@sss.pgh.pa.us        6668                 :              6 :                        RelationGetRelationName(rel));
                               6669                 :                : 
 7574                          6670   [ +  +  -  + ]:          19725 :     if (!allowSystemTableMods && IsSystemRelation(rel))
 7574 tgl@sss.pgh.pa.us        6671         [ #  # ]:UBC           0 :         ereport(ERROR,
                               6672                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                               6673                 :                :                  errmsg("permission denied: \"%s\" is a system catalog",
                               6674                 :                :                         RelationGetRelationName(rel))));
 7284 tgl@sss.pgh.pa.us        6675                 :CBC       19725 : }
                               6676                 :                : 
                               6677                 :                : /*
                               6678                 :                :  * ATSimpleRecursion
                               6679                 :                :  *
                               6680                 :                :  * Simple table recursion sufficient for most ALTER TABLE operations.
                               6681                 :                :  * All direct and indirect children are processed in an unspecified order.
                               6682                 :                :  * Note that if a child inherits from the original table via multiple
                               6683                 :                :  * inheritance paths, it will be visited just once.
                               6684                 :                :  */
                               6685                 :                : static void
                               6686                 :           7678 : ATSimpleRecursion(List **wqueue, Relation rel,
                               6687                 :                :                   AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
                               6688                 :                :                   AlterTableUtilityContext *context)
                               6689                 :                : {
                               6690                 :                :     /*
                               6691                 :                :      * Propagate to children, if desired and if there are (or might be) any
                               6692                 :                :      * children.
                               6693                 :                :      */
 1306                          6694   [ +  +  +  + ]:           7678 :     if (recurse && rel->rd_rel->relhassubclass)
                               6695                 :                :     {
 7284                          6696                 :             71 :         Oid         relid = RelationGetRelid(rel);
                               6697                 :                :         ListCell   *child;
                               6698                 :                :         List       *children;
                               6699                 :                : 
 5009 simon@2ndQuadrant.co     6700                 :             71 :         children = find_all_inheritors(relid, lockmode, NULL);
                               6701                 :                : 
                               6702                 :                :         /*
                               6703                 :                :          * find_all_inheritors does the recursive search of the inheritance
                               6704                 :                :          * hierarchy, so all we have to do is process all of the relids in the
                               6705                 :                :          * list that it returns.
                               6706                 :                :          */
 8024 tgl@sss.pgh.pa.us        6707   [ +  -  +  +  :            297 :         foreach(child, children)
                                              +  + ]
                               6708                 :                :         {
 7263 neilc@samurai.com        6709                 :            226 :             Oid         childrelid = lfirst_oid(child);
                               6710                 :                :             Relation    childrel;
                               6711                 :                : 
 7284 tgl@sss.pgh.pa.us        6712         [ +  + ]:            226 :             if (childrelid == relid)
 8024                          6713                 :             71 :                 continue;
                               6714                 :                :             /* find_all_inheritors already got lock */
 5451                          6715                 :            155 :             childrel = relation_open(childrelid, NoLock);
 5919                          6716                 :            155 :             CheckTableNotInUse(childrel, "ALTER TABLE");
 1551                          6717                 :            155 :             ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
 7284                          6718                 :            155 :             relation_close(childrel, NoLock);
                               6719                 :                :         }
                               6720                 :                :     }
                               6721                 :           7678 : }
                               6722                 :                : 
                               6723                 :                : /*
                               6724                 :                :  * Obtain list of partitions of the given table, locking them all at the given
                               6725                 :                :  * lockmode and ensuring that they all pass CheckTableNotInUse.
                               6726                 :                :  *
                               6727                 :                :  * This function is a no-op if the given relation is not a partitioned table;
                               6728                 :                :  * in particular, nothing is done if it's a legacy inheritance parent.
                               6729                 :                :  */
                               6730                 :                : static void
 1727 alvherre@alvh.no-ip.     6731                 :            473 : ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
                               6732                 :                : {
                               6733         [ +  + ]:            473 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               6734                 :                :     {
                               6735                 :                :         List       *inh;
                               6736                 :                :         ListCell   *cell;
                               6737                 :                : 
                               6738                 :             86 :         inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
                               6739                 :                :         /* first element is the parent rel; must ignore it */
 1294 tgl@sss.pgh.pa.us        6740   [ +  -  +  +  :            294 :         for_each_from(cell, inh, 1)
                                              +  + ]
                               6741                 :                :         {
                               6742                 :                :             Relation    childrel;
                               6743                 :                : 
                               6744                 :                :             /* find_all_inheritors already got lock */
 1727 alvherre@alvh.no-ip.     6745                 :            211 :             childrel = table_open(lfirst_oid(cell), NoLock);
                               6746                 :            211 :             CheckTableNotInUse(childrel, "ALTER TABLE");
                               6747                 :            208 :             table_close(childrel, NoLock);
                               6748                 :                :         }
                               6749                 :             83 :         list_free(inh);
                               6750                 :                :     }
                               6751                 :            470 : }
                               6752                 :                : 
                               6753                 :                : /*
                               6754                 :                :  * ATTypedTableRecursion
                               6755                 :                :  *
                               6756                 :                :  * Propagate ALTER TYPE operations to the typed tables of that type.
                               6757                 :                :  * Also check the RESTRICT/CASCADE behavior.  Given CASCADE, also permit
                               6758                 :                :  * recursion to inheritance children of the typed tables.
                               6759                 :                :  */
                               6760                 :                : static void
 4891 peter_e@gmx.net          6761                 :             95 : ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
                               6762                 :                :                       LOCKMODE lockmode, AlterTableUtilityContext *context)
                               6763                 :                : {
                               6764                 :                :     ListCell   *child;
                               6765                 :                :     List       *children;
                               6766                 :                : 
                               6767         [ -  + ]:             95 :     Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
                               6768                 :                : 
                               6769                 :             95 :     children = find_typed_table_dependencies(rel->rd_rel->reltype,
                               6770                 :             95 :                                              RelationGetRelationName(rel),
                               6771                 :                :                                              cmd->behavior);
                               6772                 :                : 
                               6773   [ +  +  +  +  :            101 :     foreach(child, children)
                                              +  + ]
                               6774                 :                :     {
                               6775                 :             15 :         Oid         childrelid = lfirst_oid(child);
                               6776                 :                :         Relation    childrel;
                               6777                 :                : 
                               6778                 :             15 :         childrel = relation_open(childrelid, lockmode);
                               6779                 :             15 :         CheckTableNotInUse(childrel, "ALTER TABLE");
 1551 tgl@sss.pgh.pa.us        6780                 :             15 :         ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
 4891 peter_e@gmx.net          6781                 :             15 :         relation_close(childrel, NoLock);
                               6782                 :                :     }
                               6783                 :             86 : }
                               6784                 :                : 
                               6785                 :                : 
                               6786                 :                : /*
                               6787                 :                :  * find_composite_type_dependencies
                               6788                 :                :  *
                               6789                 :                :  * Check to see if the type "typeOid" is being used as a column in some table
                               6790                 :                :  * (possibly nested several levels deep in composite types, arrays, etc!).
                               6791                 :                :  * Eventually, we'd like to propagate the check or rewrite operation
                               6792                 :                :  * into such tables, but for now, just error out if we find any.
                               6793                 :                :  *
                               6794                 :                :  * Caller should provide either the associated relation of a rowtype,
                               6795                 :                :  * or a type name (not both) for use in the error message, if any.
                               6796                 :                :  *
                               6797                 :                :  * Note that "typeOid" is not necessarily a composite type; it could also be
                               6798                 :                :  * another container type such as an array or range, or a domain over one of
                               6799                 :                :  * these things.  The name of this function is therefore somewhat historical,
                               6800                 :                :  * but it's not worth changing.
                               6801                 :                :  *
                               6802                 :                :  * We assume that functions and views depending on the type are not reasons
                               6803                 :                :  * to reject the ALTER.  (How safe is this really?)
                               6804                 :                :  */
                               6805                 :                : void
 4811 rhaas@postgresql.org     6806                 :           1928 : find_composite_type_dependencies(Oid typeOid, Relation origRelation,
                               6807                 :                :                                  const char *origTypeName)
                               6808                 :                : {
                               6809                 :                :     Relation    depRel;
                               6810                 :                :     ScanKeyData key[2];
                               6811                 :                :     SysScanDesc depScan;
                               6812                 :                :     HeapTuple   depTup;
                               6813                 :                : 
                               6814                 :                :     /* since this function recurses, it could be driven to stack overflow */
 2440 tgl@sss.pgh.pa.us        6815                 :           1928 :     check_stack_depth();
                               6816                 :                : 
                               6817                 :                :     /*
                               6818                 :                :      * We scan pg_depend to find those things that depend on the given type.
                               6819                 :                :      * (We assume we can ignore refobjsubid for a type.)
                               6820                 :                :      */
 1910 andres@anarazel.de       6821                 :           1928 :     depRel = table_open(DependRelationId, AccessShareLock);
                               6822                 :                : 
 7252 tgl@sss.pgh.pa.us        6823                 :           1928 :     ScanKeyInit(&key[0],
                               6824                 :                :                 Anum_pg_depend_refclassid,
                               6825                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                               6826                 :                :                 ObjectIdGetDatum(TypeRelationId));
                               6827                 :           1928 :     ScanKeyInit(&key[1],
                               6828                 :                :                 Anum_pg_depend_refobjid,
                               6829                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                               6830                 :                :                 ObjectIdGetDatum(typeOid));
                               6831                 :                : 
 6940                          6832                 :           1928 :     depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
                               6833                 :                :                                  NULL, 2, key);
                               6834                 :                : 
 7252                          6835         [ +  + ]:           2980 :     while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
                               6836                 :                :     {
                               6837                 :           1100 :         Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
                               6838                 :                :         Relation    rel;
                               6839                 :                :         TupleDesc   tupleDesc;
                               6840                 :                :         Form_pg_attribute att;
                               6841                 :                : 
                               6842                 :                :         /* Check for directly dependent types */
 2440                          6843         [ +  + ]:           1100 :         if (pg_depend->classid == TypeRelationId)
                               6844                 :                :         {
                               6845                 :                :             /*
                               6846                 :                :              * This must be an array, domain, or range containing the given
                               6847                 :                :              * type, so recursively check for uses of this type.  Note that
                               6848                 :                :              * any error message will mention the original type not the
                               6849                 :                :              * container; this is intentional.
                               6850                 :                :              */
                               6851                 :            927 :             find_composite_type_dependencies(pg_depend->objid,
                               6852                 :                :                                              origRelation, origTypeName);
                               6853                 :            915 :             continue;
                               6854                 :                :         }
                               6855                 :                : 
                               6856                 :                :         /* Else, ignore dependees that aren't relations */
  384                          6857         [ +  + ]:            173 :         if (pg_depend->classid != RelationRelationId)
 7252                          6858                 :             61 :             continue;
                               6859                 :                : 
                               6860                 :            112 :         rel = relation_open(pg_depend->objid, AccessShareLock);
  384                          6861                 :            112 :         tupleDesc = RelationGetDescr(rel);
                               6862                 :                : 
                               6863                 :                :         /*
                               6864                 :                :          * If objsubid identifies a specific column, refer to that in error
                               6865                 :                :          * messages.  Otherwise, search to see if there's a user column of the
                               6866                 :                :          * type.  (We assume system columns are never of interesting types.)
                               6867                 :                :          * The search is needed because an index containing an expression
                               6868                 :                :          * column of the target type will just be recorded as a whole-relation
                               6869                 :                :          * dependency.  If we do not find a column of the type, the dependency
                               6870                 :                :          * must indicate that the type is transiently referenced in an index
                               6871                 :                :          * expression but not stored on disk, which we assume is OK, just as
                               6872                 :                :          * we do for references in views.  (It could also be that the target
                               6873                 :                :          * type is embedded in some container type that is stored in an index
                               6874                 :                :          * column, but the previous recursion should catch such cases.)
                               6875                 :                :          */
                               6876   [ +  +  +  - ]:            112 :         if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
                               6877                 :             33 :             att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
                               6878                 :                :         else
                               6879                 :                :         {
                               6880                 :             79 :             att = NULL;
                               6881         [ +  + ]:            203 :             for (int attno = 1; attno <= tupleDesc->natts; attno++)
                               6882                 :                :             {
                               6883                 :            127 :                 att = TupleDescAttr(tupleDesc, attno - 1);
                               6884   [ +  +  +  - ]:            127 :                 if (att->atttypid == typeOid && !att->attisdropped)
                               6885                 :              3 :                     break;
                               6886                 :            124 :                 att = NULL;
                               6887                 :                :             }
                               6888         [ +  + ]:             79 :             if (att == NULL)
                               6889                 :                :             {
                               6890                 :                :                 /* No such column, so assume OK */
                               6891                 :             76 :                 relation_close(rel, AccessShareLock);
                               6892                 :             76 :                 continue;
                               6893                 :                :             }
                               6894                 :                :         }
                               6895                 :                : 
                               6896                 :                :         /*
                               6897                 :                :          * We definitely should reject if the relation has storage.  If it's
                               6898                 :                :          * partitioned, then perhaps we don't have to reject: if there are
                               6899                 :                :          * partitions then we'll fail when we find one, else there is no
                               6900                 :                :          * stored data to worry about.  However, it's possible that the type
                               6901                 :                :          * change would affect conclusions about whether the type is sortable
                               6902                 :                :          * or hashable and thus (if it's a partitioning column) break the
                               6903                 :                :          * partitioning rule.  For now, reject for partitioned rels too.
                               6904                 :                :          */
                               6905   [ +  +  -  +  :             36 :         if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
                                     -  -  -  -  -  
                                                 - ]
  384 tgl@sss.pgh.pa.us        6906   [ #  #  #  # ]:UBC           0 :             RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
                               6907                 :                :         {
 4765 tgl@sss.pgh.pa.us        6908         [ +  + ]:CBC          36 :             if (origTypeName)
                               6909         [ +  - ]:             15 :                 ereport(ERROR,
                               6910                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               6911                 :                :                          errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
                               6912                 :                :                                 origTypeName,
                               6913                 :                :                                 RelationGetRelationName(rel),
                               6914                 :                :                                 NameStr(att->attname))));
                               6915         [ +  + ]:             21 :             else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
                               6916         [ +  - ]:              9 :                 ereport(ERROR,
                               6917                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               6918                 :                :                          errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
                               6919                 :                :                                 RelationGetRelationName(origRelation),
                               6920                 :                :                                 RelationGetRelationName(rel),
                               6921                 :                :                                 NameStr(att->attname))));
 4811 rhaas@postgresql.org     6922         [ +  + ]:             12 :             else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
 4765 tgl@sss.pgh.pa.us        6923         [ +  - ]:              3 :                 ereport(ERROR,
                               6924                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               6925                 :                :                          errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
                               6926                 :                :                                 RelationGetRelationName(origRelation),
                               6927                 :                :                                 RelationGetRelationName(rel),
                               6928                 :                :                                 NameStr(att->attname))));
                               6929                 :                :             else
                               6930         [ +  - ]:              9 :                 ereport(ERROR,
                               6931                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               6932                 :                :                          errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
                               6933                 :                :                                 RelationGetRelationName(origRelation),
                               6934                 :                :                                 RelationGetRelationName(rel),
                               6935                 :                :                                 NameStr(att->attname))));
                               6936                 :                :         }
 7252 tgl@sss.pgh.pa.us        6937         [ #  # ]:UBC           0 :         else if (OidIsValid(rel->rd_rel->reltype))
                               6938                 :                :         {
                               6939                 :                :             /*
                               6940                 :                :              * A view or composite type itself isn't a problem, but we must
                               6941                 :                :              * recursively check for indirect dependencies via its rowtype.
                               6942                 :                :              */
                               6943                 :              0 :             find_composite_type_dependencies(rel->rd_rel->reltype,
                               6944                 :                :                                              origRelation, origTypeName);
                               6945                 :                :         }
                               6946                 :                : 
                               6947                 :              0 :         relation_close(rel, AccessShareLock);
                               6948                 :                :     }
                               6949                 :                : 
 7252 tgl@sss.pgh.pa.us        6950                 :CBC        1880 :     systable_endscan(depScan);
                               6951                 :                : 
                               6952                 :           1880 :     relation_close(depRel, AccessShareLock);
                               6953                 :           1880 : }
                               6954                 :                : 
                               6955                 :                : 
                               6956                 :                : /*
                               6957                 :                :  * find_typed_table_dependencies
                               6958                 :                :  *
                               6959                 :                :  * Check to see if a composite type is being used as the type of a
                               6960                 :                :  * typed table.  Abort if any are found and behavior is RESTRICT.
                               6961                 :                :  * Else return the list of tables.
                               6962                 :                :  */
                               6963                 :                : static List *
 4891 peter_e@gmx.net          6964                 :            107 : find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
                               6965                 :                : {
                               6966                 :                :     Relation    classRel;
                               6967                 :                :     ScanKeyData key[1];
                               6968                 :                :     TableScanDesc scan;
                               6969                 :                :     HeapTuple   tuple;
                               6970                 :            107 :     List       *result = NIL;
                               6971                 :                : 
 1910 andres@anarazel.de       6972                 :            107 :     classRel = table_open(RelationRelationId, AccessShareLock);
                               6973                 :                : 
 4949 peter_e@gmx.net          6974                 :            107 :     ScanKeyInit(&key[0],
                               6975                 :                :                 Anum_pg_class_reloftype,
                               6976                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                               6977                 :                :                 ObjectIdGetDatum(typeOid));
                               6978                 :                : 
 1861 andres@anarazel.de       6979                 :            107 :     scan = table_beginscan_catalog(classRel, 1, key);
                               6980                 :                : 
 4755 rhaas@postgresql.org     6981         [ +  + ]:            125 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
                               6982                 :                :     {
 1972 andres@anarazel.de       6983                 :             30 :         Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
                               6984                 :                : 
 4891 peter_e@gmx.net          6985         [ +  + ]:             30 :         if (behavior == DROP_RESTRICT)
                               6986         [ +  - ]:             12 :             ereport(ERROR,
                               6987                 :                :                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
                               6988                 :                :                      errmsg("cannot alter type \"%s\" because it is the type of a typed table",
                               6989                 :                :                             typeName),
                               6990                 :                :                      errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
                               6991                 :                :         else
 1972 andres@anarazel.de       6992                 :             18 :             result = lappend_oid(result, classform->oid);
                               6993                 :                :     }
                               6994                 :                : 
 1861                          6995                 :             95 :     table_endscan(scan);
 1910                          6996                 :             95 :     table_close(classRel, AccessShareLock);
                               6997                 :                : 
 4891 peter_e@gmx.net          6998                 :             95 :     return result;
                               6999                 :                : }
                               7000                 :                : 
                               7001                 :                : 
                               7002                 :                : /*
                               7003                 :                :  * check_of_type
                               7004                 :                :  *
                               7005                 :                :  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF.  If it
                               7006                 :                :  * isn't suitable, throw an error.  Currently, we require that the type
                               7007                 :                :  * originated with CREATE TYPE AS.  We could support any row type, but doing so
                               7008                 :                :  * would require handling a number of extra corner cases in the DDL commands.
                               7009                 :                :  * (Also, allowing domain-over-composite would open up a can of worms about
                               7010                 :                :  * whether and how the domain's constraints should apply to derived tables.)
                               7011                 :                :  */
                               7012                 :                : void
 4743 rhaas@postgresql.org     7013                 :             85 : check_of_type(HeapTuple typetuple)
                               7014                 :                : {
                               7015                 :             85 :     Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
                               7016                 :             85 :     bool        typeOk = false;
                               7017                 :                : 
                               7018         [ +  - ]:             85 :     if (typ->typtype == TYPTYPE_COMPOSITE)
                               7019                 :                :     {
                               7020                 :                :         Relation    typeRelation;
                               7021                 :                : 
                               7022         [ -  + ]:             85 :         Assert(OidIsValid(typ->typrelid));
                               7023                 :             85 :         typeRelation = relation_open(typ->typrelid, AccessShareLock);
                               7024                 :             85 :         typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
                               7025                 :                : 
                               7026                 :                :         /*
                               7027                 :                :          * Close the parent rel, but keep our AccessShareLock on it until xact
                               7028                 :                :          * commit.  That will prevent someone else from deleting or ALTERing
                               7029                 :                :          * the type before the typed table creation/conversion commits.
                               7030                 :                :          */
                               7031                 :             85 :         relation_close(typeRelation, NoLock);
                               7032                 :                :     }
                               7033         [ +  + ]:             85 :     if (!typeOk)
                               7034         [ +  - ]:              3 :         ereport(ERROR,
                               7035                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               7036                 :                :                  errmsg("type %s is not a composite type",
                               7037                 :                :                         format_type_be(typ->oid))));
                               7038                 :             82 : }
                               7039                 :                : 
                               7040                 :                : 
                               7041                 :                : /*
                               7042                 :                :  * ALTER TABLE ADD COLUMN
                               7043                 :                :  *
                               7044                 :                :  * Adds an additional attribute to a relation making the assumption that
                               7045                 :                :  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
                               7046                 :                :  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
                               7047                 :                :  * AlterTableCmd's.
                               7048                 :                :  *
                               7049                 :                :  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
                               7050                 :                :  * have to decide at runtime whether to recurse or not depending on whether we
                               7051                 :                :  * actually add a column or merely merge with an existing column.  (We can't
                               7052                 :                :  * check this in a static pre-pass because it won't handle multiple inheritance
                               7053                 :                :  * situations correctly.)
                               7054                 :                :  */
                               7055                 :                : static void
 4891 peter_e@gmx.net          7056                 :            990 : ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                               7057                 :                :                 bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
                               7058                 :                :                 AlterTableUtilityContext *context)
                               7059                 :                : {
                               7060   [ +  +  +  + ]:            990 :     if (rel->rd_rel->reloftype && !recursing)
 5014                          7061         [ +  - ]:              3 :         ereport(ERROR,
                               7062                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               7063                 :                :                  errmsg("cannot add column to typed table")));
                               7064                 :                : 
 4949                          7065         [ +  + ]:            987 :     if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
 1551 tgl@sss.pgh.pa.us        7066                 :             29 :         ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
                               7067                 :                : 
 3334 alvherre@alvh.no-ip.     7068   [ +  +  +  + ]:            984 :     if (recurse && !is_view)
  489                          7069                 :            934 :         cmd->recurse = true;
 7284 tgl@sss.pgh.pa.us        7070                 :            984 : }
                               7071                 :                : 
                               7072                 :                : /*
                               7073                 :                :  * Add a column to a table.  The return value is the address of the
                               7074                 :                :  * new column in the parent relation.
                               7075                 :                :  *
                               7076                 :                :  * cmd is pass-by-ref so that we can replace it with the parse-transformed
                               7077                 :                :  * copy (but that happens only after we check for IF NOT EXISTS).
                               7078                 :                :  */
                               7079                 :                : static ObjectAddress
 4760 rhaas@postgresql.org     7080                 :           1293 : ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
                               7081                 :                :                 AlterTableCmd **cmd, bool recurse, bool recursing,
                               7082                 :                :                 LOCKMODE lockmode, AlterTablePass cur_pass,
                               7083                 :                :                 AlterTableUtilityContext *context)
                               7084                 :                : {
 7284 tgl@sss.pgh.pa.us        7085                 :           1293 :     Oid         myrelid = RelationGetRelid(rel);
 1551                          7086                 :           1293 :     ColumnDef  *colDef = castNode(ColumnDef, (*cmd)->def);
                               7087                 :           1293 :     bool        if_not_exists = (*cmd)->missing_ok;
                               7088                 :                :     Relation    pgclass,
                               7089                 :                :                 attrdesc;
                               7090                 :                :     HeapTuple   reltup;
                               7091                 :                :     Form_pg_attribute attribute;
                               7092                 :                :     int         newattnum;
                               7093                 :                :     char        relkind;
                               7094                 :                :     Expr       *defval;
                               7095                 :                :     List       *children;
                               7096                 :                :     ListCell   *child;
                               7097                 :                :     AlterTableCmd *childcmd;
                               7098                 :                :     ObjectAddress address;
                               7099                 :                :     TupleDesc   tupdesc;
                               7100                 :                : 
                               7101                 :                :     /* since this function recurses, it could be driven to stack overflow */
   58 akorotkov@postgresql     7102                 :           1293 :     check_stack_depth();
                               7103                 :                : 
                               7104                 :                :     /* At top level, permission check was done in ATPrepCmd, else do it */
 4760 rhaas@postgresql.org     7105         [ +  + ]:           1293 :     if (recursing)
 1011 peter@eisentraut.org     7106                 :            312 :         ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               7107                 :                : 
 2685 rhaas@postgresql.org     7108   [ +  +  +  + ]:           1293 :     if (rel->rd_rel->relispartition && !recursing)
                               7109         [ +  - ]:              6 :         ereport(ERROR,
                               7110                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               7111                 :                :                  errmsg("cannot add column to a partition")));
                               7112                 :                : 
 1910 andres@anarazel.de       7113                 :           1287 :     attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
                               7114                 :                : 
                               7115                 :                :     /*
                               7116                 :                :      * Are we adding the column to a recursion child?  If so, check whether to
                               7117                 :                :      * merge with an existing definition for the column.  If we do merge, we
                               7118                 :                :      * must not recurse.  Children will already have the column, and recursing
                               7119                 :                :      * into them would mess up attinhcount.
                               7120                 :                :      */
 7284 tgl@sss.pgh.pa.us        7121         [ +  + ]:           1287 :     if (colDef->inhcount > 0)
                               7122                 :                :     {
                               7123                 :                :         HeapTuple   tuple;
                               7124                 :                : 
                               7125                 :                :         /* Does child already have a column by this name? */
                               7126                 :            312 :         tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
                               7127         [ +  + ]:            312 :         if (HeapTupleIsValid(tuple))
                               7128                 :                :         {
                               7129                 :             18 :             Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
                               7130                 :                :             Oid         ctypeId;
                               7131                 :                :             int32       ctypmod;
                               7132                 :                :             Oid         ccollid;
                               7133                 :                : 
                               7134                 :                :             /* Child column must match on type, typmod, and collation */
 4785                          7135                 :             18 :             typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
 6315                          7136         [ +  - ]:             18 :             if (ctypeId != childatt->atttypid ||
                               7137         [ -  + ]:             18 :                 ctypmod != childatt->atttypmod)
 7284 tgl@sss.pgh.pa.us        7138         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               7139                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                               7140                 :                :                          errmsg("child table \"%s\" has different type for column \"%s\"",
                               7141                 :                :                                 RelationGetRelationName(rel), colDef->colname)));
 4785 tgl@sss.pgh.pa.us        7142                 :CBC          18 :             ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
 4814 peter_e@gmx.net          7143         [ -  + ]:             18 :             if (ccollid != childatt->attcollation)
 4814 peter_e@gmx.net          7144         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               7145                 :                :                         (errcode(ERRCODE_COLLATION_MISMATCH),
                               7146                 :                :                          errmsg("child table \"%s\" has different collation for column \"%s\"",
                               7147                 :                :                                 RelationGetRelationName(rel), colDef->colname),
                               7148                 :                :                          errdetail("\"%s\" versus \"%s\"",
                               7149                 :                :                                    get_collation_name(ccollid),
                               7150                 :                :                                    get_collation_name(childatt->attcollation))));
                               7151                 :                : 
                               7152                 :                :             /* Bump the existing child att's inhcount */
 7284 tgl@sss.pgh.pa.us        7153                 :CBC          18 :             childatt->attinhcount++;
  383 peter@eisentraut.org     7154         [ -  + ]:             18 :             if (childatt->attinhcount < 0)
  383 peter@eisentraut.org     7155         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               7156                 :                :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               7157                 :                :                         errmsg("too many inheritance parents"));
 2630 alvherre@alvh.no-ip.     7158                 :CBC          18 :             CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
                               7159                 :                : 
 7284 tgl@sss.pgh.pa.us        7160                 :             18 :             heap_freetuple(tuple);
                               7161                 :                : 
                               7162                 :                :             /* Inform the user about the merge */
                               7163         [ +  - ]:             18 :             ereport(NOTICE,
                               7164                 :                :                     (errmsg("merging definition of column \"%s\" for child \"%s\"",
                               7165                 :                :                             colDef->colname, RelationGetRelationName(rel))));
                               7166                 :                : 
 1910 andres@anarazel.de       7167                 :             18 :             table_close(attrdesc, RowExclusiveLock);
                               7168                 :                : 
                               7169                 :                :             /* Make the child column change visible */
   81 michael@paquier.xyz      7170                 :             18 :             CommandCounterIncrement();
                               7171                 :                : 
 3308 alvherre@alvh.no-ip.     7172                 :             18 :             return InvalidObjectAddress;
                               7173                 :                :         }
                               7174                 :                :     }
                               7175                 :                : 
                               7176                 :                :     /* skip if the name already exists and if_not_exists is true */
 1551 tgl@sss.pgh.pa.us        7177         [ +  + ]:           1269 :     if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
                               7178                 :                :     {
                               7179                 :             27 :         table_close(attrdesc, RowExclusiveLock);
                               7180                 :             27 :         return InvalidObjectAddress;
                               7181                 :                :     }
                               7182                 :                : 
                               7183                 :                :     /*
                               7184                 :                :      * Okay, we need to add the column, so go ahead and do parse
                               7185                 :                :      * transformation.  This can result in queueing up, or even immediately
                               7186                 :                :      * executing, subsidiary operations (such as creation of unique indexes);
                               7187                 :                :      * so we mustn't do it until we have made the if_not_exists check.
                               7188                 :                :      *
                               7189                 :                :      * When recursing, the command was already transformed and we needn't do
                               7190                 :                :      * so again.  Also, if context isn't given we can't transform.  (That
                               7191                 :                :      * currently happens only for AT_AddColumnToView; we expect that view.c
                               7192                 :                :      * passed us a ColumnDef that doesn't need work.)
                               7193                 :                :      */
                               7194   [ +  +  +  + ]:           1227 :     if (context != NULL && !recursing)
                               7195                 :                :     {
                               7196                 :            921 :         *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
                               7197                 :                :                                    cur_pass, context);
                               7198         [ -  + ]:            921 :         Assert(*cmd != NULL);
                               7199                 :            921 :         colDef = castNode(ColumnDef, (*cmd)->def);
                               7200                 :                :     }
                               7201                 :                : 
                               7202                 :                :     /*
                               7203                 :                :      * Regular inheritance children are independent enough not to inherit the
                               7204                 :                :      * identity column from parent hence cannot recursively add identity
                               7205                 :                :      * column if the table has inheritance children.
                               7206                 :                :      *
                               7207                 :                :      * Partitions, on the other hand, are integral part of a partitioned table
                               7208                 :                :      * and inherit identity column.  Hence propagate identity column down the
                               7209                 :                :      * partition hierarchy.
                               7210                 :                :      */
 2565 peter_e@gmx.net          7211   [ +  +  +  - ]:           1227 :     if (colDef->identity &&
                               7212         [ +  + ]:             27 :         recurse &&
   89 peter@eisentraut.org     7213   [ +  +  +  + ]:GNC          51 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
 1082 alvherre@alvh.no-ip.     7214                 :CBC          24 :         find_inheritance_children(myrelid, NoLock) != NIL)
 2565 peter_e@gmx.net          7215         [ +  - ]:              3 :         ereport(ERROR,
                               7216                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7217                 :                :                  errmsg("cannot recursively add identity column to table that has child tables")));
                               7218                 :                : 
 1551 tgl@sss.pgh.pa.us        7219                 :           1224 :     pgclass = table_open(RelationRelationId, RowExclusiveLock);
                               7220                 :                : 
                               7221                 :           1224 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
                               7222         [ -  + ]:           1224 :     if (!HeapTupleIsValid(reltup))
 1551 tgl@sss.pgh.pa.us        7223         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
 1551 tgl@sss.pgh.pa.us        7224                 :CBC        1224 :     relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
                               7225                 :                : 
                               7226                 :                :     /* Determine the new attribute's number */
 1972 andres@anarazel.de       7227                 :           1224 :     newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
                               7228         [ -  + ]:           1224 :     if (newattnum > MaxHeapAttributeNumber)
 1972 andres@anarazel.de       7229         [ #  # ]:UBC           0 :         ereport(ERROR,
                               7230                 :                :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
                               7231                 :                :                  errmsg("tables can have at most %d columns",
                               7232                 :                :                         MaxHeapAttributeNumber)));
                               7233                 :                : 
                               7234                 :                :     /*
                               7235                 :                :      * Construct new attribute's pg_attribute entry.
                               7236                 :                :      */
   93 peter@eisentraut.org     7237                 :GNC        1224 :     tupdesc = BuildDescForRelation(list_make1(colDef));
                               7238                 :                : 
                               7239                 :           1218 :     attribute = TupleDescAttr(tupdesc, 0);
                               7240                 :                : 
                               7241                 :                :     /* Fix up attribute number */
                               7242                 :           1218 :     attribute->attnum = newattnum;
                               7243                 :                : 
                               7244                 :                :     /* make sure datatype is legal for a column */
                               7245                 :           1218 :     CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation,
 4766 tgl@sss.pgh.pa.us        7246                 :CBC        1218 :                        list_make1_oid(rel->rd_rel->reltype),
                               7247                 :                :                        0);
                               7248                 :                : 
 1353 michael@paquier.xyz      7249                 :           1203 :     InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
                               7250                 :                : 
 1910 andres@anarazel.de       7251                 :           1203 :     table_close(attrdesc, RowExclusiveLock);
                               7252                 :                : 
                               7253                 :                :     /*
                               7254                 :                :      * Update pg_class tuple as appropriate
                               7255                 :                :      */
 1972                          7256                 :           1203 :     ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
                               7257                 :                : 
 2630 alvherre@alvh.no-ip.     7258                 :           1203 :     CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
                               7259                 :                : 
 7284 tgl@sss.pgh.pa.us        7260                 :           1203 :     heap_freetuple(reltup);
                               7261                 :                : 
                               7262                 :                :     /* Post creation hook for new attribute */
 4057 rhaas@postgresql.org     7263         [ -  + ]:           1203 :     InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
                               7264                 :                : 
 1910 andres@anarazel.de       7265                 :           1203 :     table_close(pgclass, RowExclusiveLock);
                               7266                 :                : 
                               7267                 :                :     /* Make the attribute's catalog entry visible */
 7284 tgl@sss.pgh.pa.us        7268                 :           1203 :     CommandCounterIncrement();
                               7269                 :                : 
                               7270                 :                :     /*
                               7271                 :                :      * Store the DEFAULT, if any, in the catalogs
                               7272                 :                :      */
                               7273         [ +  + ]:           1203 :     if (colDef->raw_default)
                               7274                 :                :     {
                               7275                 :                :         RawColumnDefault *rawEnt;
                               7276                 :                : 
 8024                          7277                 :            350 :         rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
   93 peter@eisentraut.org     7278                 :GNC         350 :         rawEnt->attnum = attribute->attnum;
 7284 tgl@sss.pgh.pa.us        7279                 :CBC         350 :         rawEnt->raw_default = copyObject(colDef->raw_default);
                               7280                 :                : 
                               7281                 :                :         /*
                               7282                 :                :          * Attempt to skip a complete table rewrite by storing the specified
                               7283                 :                :          * DEFAULT value outside of the heap.  This may be disabled inside
                               7284                 :                :          * AddRelationNewConstraints if the optimization cannot be applied.
                               7285                 :                :          */
 1842 peter@eisentraut.org     7286                 :            350 :         rawEnt->missingMode = (!colDef->generated);
                               7287                 :                : 
                               7288                 :            350 :         rawEnt->generated = colDef->generated;
                               7289                 :                : 
                               7290                 :                :         /*
                               7291                 :                :          * This function is intended for CREATE TABLE, so it processes a
                               7292                 :                :          * _list_ of defaults, but we just do one.
                               7293                 :                :          */
 4046 rhaas@postgresql.org     7294                 :            350 :         AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
                               7295                 :                :                                   false, true, false, NULL);
                               7296                 :                : 
                               7297                 :                :         /* Make the additional catalog changes visible */
 7284 tgl@sss.pgh.pa.us        7298                 :            344 :         CommandCounterIncrement();
                               7299                 :                : 
                               7300                 :                :         /*
                               7301                 :                :          * Did the request for a missing value work? If not we'll have to do a
                               7302                 :                :          * rewrite
                               7303                 :                :          */
 2209 andrew@dunslane.net      7304         [ +  + ]:            344 :         if (!rawEnt->missingMode)
                               7305                 :             54 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
                               7306                 :                :     }
                               7307                 :                : 
                               7308                 :                :     /*
                               7309                 :                :      * Tell Phase 3 to fill in the default expression, if there is one.
                               7310                 :                :      *
                               7311                 :                :      * If there is no default, Phase 3 doesn't have to do anything, because
                               7312                 :                :      * that effectively means that the default is NULL.  The heap tuple access
                               7313                 :                :      * routines always check for attnum > # of attributes in tuple, and return
                               7314                 :                :      * NULL if so, so without any modification of the tuple data we will get
                               7315                 :                :      * the effect of NULL values in the new column.
                               7316                 :                :      *
                               7317                 :                :      * An exception occurs when the new column is of a domain type: the domain
                               7318                 :                :      * might have a not-null constraint, or a check constraint that indirectly
                               7319                 :                :      * rejects nulls.  If there are any domain constraints then we construct
                               7320                 :                :      * an explicit NULL default value that will be passed through
                               7321                 :                :      * CoerceToDomain processing.  (This is a tad inefficient, since it causes
                               7322                 :                :      * rewriting the table which we really don't have to do, but the present
                               7323                 :                :      * design of domain processing doesn't offer any simple way of checking
                               7324                 :                :      * the constraints more directly.)
                               7325                 :                :      *
                               7326                 :                :      * Note: we use build_column_default, and not just the cooked default
                               7327                 :                :      * returned by AddRelationNewConstraints, so that the right thing happens
                               7328                 :                :      * when a datatype's default applies.
                               7329                 :                :      *
                               7330                 :                :      * Note: it might seem that this should happen at the end of Phase 2, so
                               7331                 :                :      * that the effects of subsequent subcommands can be taken into account.
                               7332                 :                :      * It's intentional that we do it now, though.  The new column should be
                               7333                 :                :      * filled according to what is said in the ADD COLUMN subcommand, so that
                               7334                 :                :      * the effects are the same as if this subcommand had been run by itself
                               7335                 :                :      * and the later subcommands had been issued in new ALTER TABLE commands.
                               7336                 :                :      *
                               7337                 :                :      * We can skip this entirely for relations without storage, since Phase 3
                               7338                 :                :      * is certainly not going to touch them.  System attributes don't have
                               7339                 :                :      * interesting defaults, either.
                               7340                 :                :      */
  277 peter@eisentraut.org     7341   [ +  +  +  -  :GNC        1197 :     if (RELKIND_HAS_STORAGE(relkind))
                                     +  -  +  -  -  
                                                 + ]
                               7342                 :                :     {
                               7343                 :                :         /*
                               7344                 :                :          * For an identity column, we can't use build_column_default(),
                               7345                 :                :          * because the sequence ownership isn't set yet.  So do it manually.
                               7346                 :                :          */
 2263 peter_e@gmx.net          7347         [ +  + ]:CBC        1021 :         if (colDef->identity)
                               7348                 :                :         {
                               7349                 :             21 :             NextValueExpr *nve = makeNode(NextValueExpr);
                               7350                 :                : 
                               7351                 :             21 :             nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
   93 peter@eisentraut.org     7352                 :GNC          21 :             nve->typeId = attribute->atttypid;
                               7353                 :                : 
 2263 peter_e@gmx.net          7354                 :CBC          21 :             defval = (Expr *) nve;
                               7355                 :                : 
                               7356                 :                :             /* must do a rewrite for identity columns */
 2209 andrew@dunslane.net      7357                 :             21 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
                               7358                 :                :         }
                               7359                 :                :         else
   93 peter@eisentraut.org     7360                 :GNC        1000 :             defval = (Expr *) build_column_default(rel, attribute->attnum);
                               7361                 :                : 
                               7362   [ +  +  +  + ]:           1021 :         if (!defval && DomainHasConstraints(attribute->atttypid))
                               7363                 :                :         {
                               7364                 :                :             Oid         baseTypeId;
                               7365                 :                :             int32       baseTypeMod;
                               7366                 :                :             Oid         baseTypeColl;
                               7367                 :                : 
                               7368                 :              3 :             baseTypeMod = attribute->atttypmod;
                               7369                 :              3 :             baseTypeId = getBaseTypeAndTypmod(attribute->atttypid, &baseTypeMod);
 4769 tgl@sss.pgh.pa.us        7370                 :CBC           3 :             baseTypeColl = get_typcollation(baseTypeId);
                               7371                 :              3 :             defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
 5608 bruce@momjian.us         7372                 :              3 :             defval = (Expr *) coerce_to_target_type(NULL,
                               7373                 :                :                                                     (Node *) defval,
                               7374                 :                :                                                     baseTypeId,
                               7375                 :                :                                                     attribute->atttypid,
                               7376                 :                :                                                     attribute->atttypmod,
                               7377                 :                :                                                     COERCION_ASSIGNMENT,
                               7378                 :                :                                                     COERCE_IMPLICIT_CAST,
                               7379                 :                :                                                     -1);
 5421                          7380         [ -  + ]:              3 :             if (defval == NULL) /* should not happen */
 5608 bruce@momjian.us         7381         [ #  # ]:UBC           0 :                 elog(ERROR, "failed to coerce base type to domain");
                               7382                 :                :         }
                               7383                 :                : 
 5608 bruce@momjian.us         7384         [ +  + ]:CBC        1021 :         if (defval)
                               7385                 :                :         {
                               7386                 :                :             NewColumnValue *newval;
                               7387                 :                : 
                               7388                 :            303 :             newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
   93 peter@eisentraut.org     7389                 :GNC         303 :             newval->attnum = attribute->attnum;
 4681 rhaas@postgresql.org     7390                 :CBC         303 :             newval->expr = expression_planner(defval);
 1558 tgl@sss.pgh.pa.us        7391                 :            303 :             newval->is_generated = (colDef->generated != '\0');
                               7392                 :                : 
 5608 bruce@momjian.us         7393                 :            303 :             tab->newvals = lappend(tab->newvals, newval);
                               7394                 :                :         }
                               7395                 :                : 
   93 peter@eisentraut.org     7396         [ +  + ]:GNC        1021 :         if (DomainHasConstraints(attribute->atttypid))
 2209 andrew@dunslane.net      7397                 :CBC           6 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
                               7398                 :                : 
   93 peter@eisentraut.org     7399         [ +  + ]:GNC        1021 :         if (!TupleDescAttr(rel->rd_att, attribute->attnum - 1)->atthasmissing)
                               7400                 :                :         {
                               7401                 :                :             /*
                               7402                 :                :              * If the new column is NOT NULL, and there is no missing value,
                               7403                 :                :              * tell Phase 3 it needs to check for NULLs.
                               7404                 :                :              */
 1859 rhaas@postgresql.org     7405                 :CBC         796 :             tab->verify_new_notnull |= colDef->is_not_null;
                               7406                 :                :         }
                               7407                 :                :     }
                               7408                 :                : 
                               7409                 :                :     /*
                               7410                 :                :      * Add needed dependency entries for the new column.
                               7411                 :                :      */
   93 peter@eisentraut.org     7412                 :GNC        1197 :     add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
                               7413                 :           1197 :     add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
                               7414                 :                : 
                               7415                 :                :     /*
                               7416                 :                :      * Propagate to children as appropriate.  Unlike most other ALTER
                               7417                 :                :      * routines, we have to do this one level of recursion at a time; we can't
                               7418                 :                :      * use find_all_inheritors to do it in one pass.
                               7419                 :                :      */
                               7420                 :                :     children =
 1082 alvherre@alvh.no-ip.     7421                 :CBC        1197 :         find_inheritance_children(RelationGetRelid(rel), lockmode);
                               7422                 :                : 
                               7423                 :                :     /*
                               7424                 :                :      * If we are told not to recurse, there had better not be any child
                               7425                 :                :      * tables; else the addition would put them out of step.
                               7426                 :                :      */
 4760 rhaas@postgresql.org     7427   [ +  +  +  + ]:           1197 :     if (children && !recurse)
                               7428         [ +  - ]:              6 :         ereport(ERROR,
                               7429                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7430                 :                :                  errmsg("column must be added to child tables too")));
                               7431                 :                : 
                               7432                 :                :     /* Children should see column as singly inherited */
                               7433         [ +  + ]:           1191 :     if (!recursing)
                               7434                 :                :     {
 1551 tgl@sss.pgh.pa.us        7435                 :            897 :         childcmd = copyObject(*cmd);
                               7436                 :            897 :         colDef = castNode(ColumnDef, childcmd->def);
 4760 rhaas@postgresql.org     7437                 :            897 :         colDef->inhcount = 1;
                               7438                 :            897 :         colDef->is_local = false;
                               7439                 :                :     }
                               7440                 :                :     else
 1551 tgl@sss.pgh.pa.us        7441                 :            294 :         childcmd = *cmd;        /* no need to copy again */
                               7442                 :                : 
 4760 rhaas@postgresql.org     7443   [ +  +  +  +  :           1503 :     foreach(child, children)
                                              +  + ]
                               7444                 :                :     {
                               7445                 :            312 :         Oid         childrelid = lfirst_oid(child);
                               7446                 :                :         Relation    childrel;
                               7447                 :                :         AlteredTableInfo *childtab;
                               7448                 :                : 
                               7449                 :                :         /* find_inheritance_children already got lock */
 1910 andres@anarazel.de       7450                 :            312 :         childrel = table_open(childrelid, NoLock);
 4760 rhaas@postgresql.org     7451                 :            312 :         CheckTableNotInUse(childrel, "ALTER TABLE");
                               7452                 :                : 
                               7453                 :                :         /* Find or create work queue entry for this table */
                               7454                 :            312 :         childtab = ATGetQueueEntry(wqueue, childrel);
                               7455                 :                : 
                               7456                 :                :         /* Recurse to child; return value is ignored */
                               7457                 :            312 :         ATExecAddColumn(wqueue, childtab, childrel,
                               7458                 :                :                         &childcmd, recurse, true,
                               7459                 :                :                         lockmode, cur_pass, context);
                               7460                 :                : 
 1910 andres@anarazel.de       7461                 :            312 :         table_close(childrel, NoLock);
                               7462                 :                :     }
                               7463                 :                : 
 3308 alvherre@alvh.no-ip.     7464                 :           1191 :     ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
                               7465                 :           1191 :     return address;
                               7466                 :                : }
                               7467                 :                : 
                               7468                 :                : /*
                               7469                 :                :  * If a new or renamed column will collide with the name of an existing
                               7470                 :                :  * column and if_not_exists is false then error out, else do nothing.
                               7471                 :                :  */
                               7472                 :                : static bool
 3182 andrew@dunslane.net      7473                 :           1488 : check_for_column_name_collision(Relation rel, const char *colname,
                               7474                 :                :                                 bool if_not_exists)
                               7475                 :                : {
                               7476                 :                :     HeapTuple   attTuple;
                               7477                 :                :     int         attnum;
                               7478                 :                : 
                               7479                 :                :     /*
                               7480                 :                :      * this test is deliberately not attisdropped-aware, since if one tries to
                               7481                 :                :      * add a column matching a dropped column name, it's gonna fail anyway.
                               7482                 :                :      */
 4462 rhaas@postgresql.org     7483                 :           1488 :     attTuple = SearchSysCache2(ATTNAME,
                               7484                 :                :                                ObjectIdGetDatum(RelationGetRelid(rel)),
                               7485                 :                :                                PointerGetDatum(colname));
                               7486         [ +  + ]:           1488 :     if (!HeapTupleIsValid(attTuple))
 3182 andrew@dunslane.net      7487                 :           1440 :         return true;
                               7488                 :                : 
 4326 bruce@momjian.us         7489                 :             48 :     attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
 4462 rhaas@postgresql.org     7490                 :             48 :     ReleaseSysCache(attTuple);
                               7491                 :                : 
                               7492                 :                :     /*
                               7493                 :                :      * We throw a different error message for conflicts with system column
                               7494                 :                :      * names, since they are normally not shown and the user might otherwise
                               7495                 :                :      * be confused about the reason for the conflict.
                               7496                 :                :      */
 4326 bruce@momjian.us         7497         [ +  + ]:             48 :     if (attnum <= 0)
                               7498         [ +  - ]:              6 :         ereport(ERROR,
                               7499                 :                :                 (errcode(ERRCODE_DUPLICATE_COLUMN),
                               7500                 :                :                  errmsg("column name \"%s\" conflicts with a system column name",
                               7501                 :                :                         colname)));
                               7502                 :                :     else
                               7503                 :                :     {
 3182 andrew@dunslane.net      7504         [ +  + ]:             42 :         if (if_not_exists)
                               7505                 :                :         {
                               7506         [ +  - ]:             27 :             ereport(NOTICE,
                               7507                 :                :                     (errcode(ERRCODE_DUPLICATE_COLUMN),
                               7508                 :                :                      errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
                               7509                 :                :                             colname, RelationGetRelationName(rel))));
                               7510                 :             27 :             return false;
                               7511                 :                :         }
                               7512                 :                : 
 4326 bruce@momjian.us         7513         [ +  - ]:             15 :         ereport(ERROR,
                               7514                 :                :                 (errcode(ERRCODE_DUPLICATE_COLUMN),
                               7515                 :                :                  errmsg("column \"%s\" of relation \"%s\" already exists",
                               7516                 :                :                         colname, RelationGetRelationName(rel))));
                               7517                 :                :     }
                               7518                 :                : 
                               7519                 :                :     return true;
                               7520                 :                : }
                               7521                 :                : 
                               7522                 :                : /*
                               7523                 :                :  * Install a column's dependency on its datatype.
                               7524                 :                :  */
                               7525                 :                : static void
 4741 tgl@sss.pgh.pa.us        7526                 :           1651 : add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
                               7527                 :                : {
                               7528                 :                :     ObjectAddress myself,
                               7529                 :                :                 referenced;
                               7530                 :                : 
 6940                          7531                 :           1651 :     myself.classId = RelationRelationId;
 7284                          7532                 :           1651 :     myself.objectId = relid;
                               7533                 :           1651 :     myself.objectSubId = attnum;
 6940                          7534                 :           1651 :     referenced.classId = TypeRelationId;
 7284                          7535                 :           1651 :     referenced.objectId = typid;
                               7536                 :           1651 :     referenced.objectSubId = 0;
                               7537                 :           1651 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 4741                          7538                 :           1651 : }
                               7539                 :                : 
                               7540                 :                : /*
                               7541                 :                :  * Install a column's dependency on its collation.
                               7542                 :                :  */
                               7543                 :                : static void
                               7544                 :           1651 : add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
                               7545                 :                : {
                               7546                 :                :     ObjectAddress myself,
                               7547                 :                :                 referenced;
                               7548                 :                : 
                               7549                 :                :     /* We know the default collation is pinned, so don't bother recording it */
                               7550   [ +  +  +  + ]:           1651 :     if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
                               7551                 :                :     {
                               7552                 :              9 :         myself.classId = RelationRelationId;
                               7553                 :              9 :         myself.objectId = relid;
                               7554                 :              9 :         myself.objectSubId = attnum;
 4810 peter_e@gmx.net          7555                 :              9 :         referenced.classId = CollationRelationId;
                               7556                 :              9 :         referenced.objectId = collid;
                               7557                 :              9 :         referenced.objectSubId = 0;
                               7558                 :              9 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
                               7559                 :                :     }
 7284 tgl@sss.pgh.pa.us        7560                 :           1651 : }
                               7561                 :                : 
                               7562                 :                : /*
                               7563                 :                :  * ALTER TABLE ALTER COLUMN DROP NOT NULL
                               7564                 :                :  *
                               7565                 :                :  * Return the address of the modified column.  If the column was already
                               7566                 :                :  * nullable, InvalidObjectAddress is returned.
                               7567                 :                :  */
                               7568                 :                : static ObjectAddress
  233 alvherre@alvh.no-ip.     7569                 :GNC         119 : ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
                               7570                 :                :                   LOCKMODE lockmode)
                               7571                 :                : {
                               7572                 :                :     HeapTuple   tuple;
                               7573                 :                :     HeapTuple   conTup;
                               7574                 :                :     Form_pg_attribute attTup;
                               7575                 :                :     AttrNumber  attnum;
                               7576                 :                :     Relation    attr_rel;
                               7577                 :                :     ObjectAddress address;
                               7578                 :                :     List       *readyRels;
                               7579                 :                : 
                               7580                 :                :     /*
                               7581                 :                :      * lookup the attribute
                               7582                 :                :      */
 1910 andres@anarazel.de       7583                 :CBC         119 :     attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
                               7584                 :                : 
 7284 tgl@sss.pgh.pa.us        7585                 :            119 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               7586         [ +  + ]:            119 :     if (!HeapTupleIsValid(tuple))
                               7587         [ +  - ]:              9 :         ereport(ERROR,
                               7588                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               7589                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               7590                 :                :                         colName, RelationGetRelationName(rel))));
 2000 peter_e@gmx.net          7591                 :            110 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               7592                 :            110 :     attnum = attTup->attnum;
  233 alvherre@alvh.no-ip.     7593                 :GNC         110 :     ObjectAddressSubSet(address, RelationRelationId,
                               7594                 :                :                         RelationGetRelid(rel), attnum);
                               7595                 :                : 
                               7596                 :                :     /* If the column is already nullable there's nothing to do. */
                               7597         [ +  + ]:            110 :     if (!attTup->attnotnull)
                               7598                 :                :     {
                               7599                 :              3 :         table_close(attr_rel, RowExclusiveLock);
                               7600                 :              3 :         return InvalidObjectAddress;
                               7601                 :                :     }
                               7602                 :                : 
                               7603                 :                :     /* Prevent them from altering a system attribute */
 7284 tgl@sss.pgh.pa.us        7604         [ -  + ]:CBC         107 :     if (attnum <= 0)
 7284 tgl@sss.pgh.pa.us        7605         [ #  # ]:UBC           0 :         ereport(ERROR,
                               7606                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               7607                 :                :                  errmsg("cannot alter system column \"%s\"",
                               7608                 :                :                         colName)));
                               7609                 :                : 
 2000 peter_e@gmx.net          7610         [ +  + ]:CBC         107 :     if (attTup->attidentity)
 2565                          7611         [ +  - ]:              9 :         ereport(ERROR,
                               7612                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                               7613                 :                :                  errmsg("column \"%s\" of relation \"%s\" is an identity column",
                               7614                 :                :                         colName, RelationGetRelationName(rel))));
                               7615                 :                : 
                               7616                 :                :     /*
                               7617                 :                :      * It's not OK to remove a constraint only for the parent and leave it in
                               7618                 :                :      * the children, so disallow that.
                               7619                 :                :      */
  233 alvherre@alvh.no-ip.     7620         [ +  + ]:GNC          98 :     if (!recurse)
                               7621                 :                :     {
                               7622         [ +  - ]:              6 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               7623                 :                :         {
                               7624                 :                :             PartitionDesc partdesc;
                               7625                 :                : 
                               7626                 :              6 :             partdesc = RelationGetPartitionDesc(rel, true);
                               7627                 :                : 
                               7628         [ +  + ]:              6 :             if (partdesc->nparts > 0)
                               7629         [ +  - ]:              3 :                 ereport(ERROR,
                               7630                 :                :                         errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7631                 :                :                         errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
                               7632                 :                :                         errhint("Do not specify the ONLY keyword."));
                               7633                 :                :         }
  233 alvherre@alvh.no-ip.     7634   [ #  #  #  # ]:UNC           0 :         else if (rel->rd_rel->relhassubclass &&
                               7635                 :              0 :                  find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
                               7636                 :                :         {
                               7637         [ #  # ]:              0 :             ereport(ERROR,
                               7638                 :                :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7639                 :                :                     errmsg("not-null constraint on column \"%s\" must be removed in child tables too",
                               7640                 :                :                            colName),
                               7641                 :                :                     errhint("Do not specify the ONLY keyword."));
                               7642                 :                :         }
                               7643                 :                :     }
                               7644                 :                : 
                               7645                 :                :     /*
                               7646                 :                :      * If rel is partition, shouldn't drop NOT NULL if parent has the same.
                               7647                 :                :      */
 2685 rhaas@postgresql.org     7648         [ +  + ]:CBC          95 :     if (rel->rd_rel->relispartition)
                               7649                 :                :     {
  368 alvherre@alvh.no-ip.     7650                 :              9 :         Oid         parentId = get_partition_parent(RelationGetRelid(rel), false);
                               7651                 :              9 :         Relation    parent = table_open(parentId, AccessShareLock);
                               7652                 :              9 :         TupleDesc   tupDesc = RelationGetDescr(parent);
                               7653                 :                :         AttrNumber  parent_attnum;
                               7654                 :                : 
 2685 rhaas@postgresql.org     7655                 :              9 :         parent_attnum = get_attnum(parentId, colName);
 2429 andres@anarazel.de       7656         [ +  - ]:              9 :         if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
 2685 rhaas@postgresql.org     7657         [ +  - ]:              9 :             ereport(ERROR,
                               7658                 :                :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7659                 :                :                      errmsg("column \"%s\" is marked NOT NULL in parent table",
                               7660                 :                :                             colName)));
 1910 andres@anarazel.de       7661                 :UBC           0 :         table_close(parent, AccessShareLock);
                               7662                 :                :     }
                               7663                 :                : 
                               7664                 :                :     /*
                               7665                 :                :      * Find the constraint that makes this column NOT NULL.
                               7666                 :                :      */
  233 alvherre@alvh.no-ip.     7667                 :GNC          86 :     conTup = findNotNullConstraint(RelationGetRelid(rel), colName);
                               7668         [ +  + ]:             86 :     if (conTup == NULL)
                               7669                 :                :     {
                               7670                 :                :         Bitmapset  *pkcols;
                               7671                 :                : 
                               7672                 :                :         /*
                               7673                 :                :          * There's no not-null constraint, so throw an error.  If the column
                               7674                 :                :          * is in a primary key, we can throw a specific error.  Otherwise,
                               7675                 :                :          * this is unexpected.
                               7676                 :                :          */
                               7677                 :              6 :         pkcols = RelationGetIndexAttrBitmap(rel, INDEX_ATTR_BITMAP_PRIMARY_KEY);
                               7678         [ +  - ]:              6 :         if (bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
                               7679                 :                :                           pkcols))
                               7680         [ +  - ]:              6 :             ereport(ERROR,
                               7681                 :                :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7682                 :                :                     errmsg("column \"%s\" is in a primary key", colName));
                               7683                 :                : 
                               7684                 :                :         /* this shouldn't happen */
  233 alvherre@alvh.no-ip.     7685         [ #  # ]:UNC           0 :         elog(ERROR, "could not find not-null constraint on column \"%s\", relation \"%s\"",
                               7686                 :                :              colName, RelationGetRelationName(rel));
                               7687                 :                :     }
                               7688                 :                : 
  233 alvherre@alvh.no-ip.     7689                 :GNC          80 :     readyRels = NIL;
                               7690                 :             80 :     dropconstraint_internal(rel, conTup, DROP_RESTRICT, recurse, false,
                               7691                 :                :                             false, &readyRels, lockmode);
                               7692                 :                : 
                               7693                 :             62 :     heap_freetuple(conTup);
                               7694                 :                : 
  368 alvherre@alvh.no-ip.     7695         [ -  + ]:CBC          62 :     InvokeObjectPostAlterHook(RelationRelationId,
                               7696                 :                :                               RelationGetRelid(rel), attnum);
                               7697                 :                : 
 1910 andres@anarazel.de       7698                 :             62 :     table_close(attr_rel, RowExclusiveLock);
                               7699                 :                : 
 3308 alvherre@alvh.no-ip.     7700                 :             62 :     return address;
                               7701                 :                : }
                               7702                 :                : 
                               7703                 :                : /*
                               7704                 :                :  * Helper to set pg_attribute.attnotnull if it isn't set, and to tell phase 3
                               7705                 :                :  * to verify it; recurses to apply the same to children.
                               7706                 :                :  *
                               7707                 :                :  * When called to alter an existing table, 'wqueue' must be given so that we can
                               7708                 :                :  * queue a check that existing tuples pass the constraint.  When called from
                               7709                 :                :  * table creation, 'wqueue' should be passed as NULL.
                               7710                 :                :  *
                               7711                 :                :  * Returns true if the flag was set in any table, otherwise false.
                               7712                 :                :  */
                               7713                 :                : static bool
  233 alvherre@alvh.no-ip.     7714                 :GNC       11554 : set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse,
                               7715                 :                :                LOCKMODE lockmode)
                               7716                 :                : {
                               7717                 :                :     HeapTuple   tuple;
                               7718                 :                :     Form_pg_attribute attForm;
                               7719                 :          11554 :     bool        retval = false;
                               7720                 :                : 
                               7721                 :                :     /* Guard against stack overflow due to overly deep inheritance tree. */
  158                          7722                 :          11554 :     check_stack_depth();
                               7723                 :                : 
  233                          7724                 :          11554 :     tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), attnum);
                               7725         [ -  + ]:          11554 :     if (!HeapTupleIsValid(tuple))
  233 alvherre@alvh.no-ip.     7726         [ #  # ]:UNC           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
                               7727                 :                :              attnum, RelationGetRelid(rel));
  233 alvherre@alvh.no-ip.     7728                 :GNC       11554 :     attForm = (Form_pg_attribute) GETSTRUCT(tuple);
                               7729         [ +  + ]:          11554 :     if (!attForm->attnotnull)
                               7730                 :                :     {
                               7731                 :                :         Relation    attr_rel;
                               7732                 :                : 
                               7733                 :            767 :         attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
                               7734                 :                : 
                               7735                 :            767 :         attForm->attnotnull = true;
                               7736                 :            767 :         CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
                               7737                 :                : 
                               7738                 :            767 :         table_close(attr_rel, RowExclusiveLock);
                               7739                 :                : 
                               7740                 :                :         /*
                               7741                 :                :          * And set up for existing values to be checked, unless another
                               7742                 :                :          * constraint already proves this.
                               7743                 :                :          */
                               7744   [ +  +  +  + ]:            767 :         if (wqueue && !NotNullImpliedByRelConstraints(rel, attForm))
                               7745                 :                :         {
                               7746                 :                :             AlteredTableInfo *tab;
                               7747                 :                : 
                               7748                 :            641 :             tab = ATGetQueueEntry(wqueue, rel);
                               7749                 :            641 :             tab->verify_new_notnull = true;
                               7750                 :                :         }
                               7751                 :                : 
                               7752                 :            767 :         retval = true;
                               7753                 :                :     }
                               7754                 :                : 
                               7755         [ +  + ]:          11554 :     if (recurse)
 2546 sfrost@snowman.net       7756                 :ECB        (18) :     {
                               7757                 :                :         List       *children;
                               7758                 :                :         ListCell   *lc;
                               7759                 :                : 
  233 alvherre@alvh.no-ip.     7760                 :GNC         477 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
                               7761   [ +  +  +  +  :            549 :         foreach(lc, children)
                                              +  + ]
                               7762                 :                :         {
                               7763                 :             72 :             Oid         childrelid = lfirst_oid(lc);
                               7764                 :                :             Relation    childrel;
                               7765                 :                :             AttrNumber  childattno;
                               7766                 :                : 
                               7767                 :                :             /* find_inheritance_children already got lock */
                               7768                 :             72 :             childrel = table_open(childrelid, NoLock);
                               7769                 :             72 :             CheckTableNotInUse(childrel, "ALTER TABLE");
                               7770                 :                : 
                               7771                 :             72 :             childattno = get_attnum(RelationGetRelid(childrel),
                               7772                 :             72 :                                     get_attname(RelationGetRelid(rel), attnum,
                               7773                 :                :                                                 false));
                               7774                 :             72 :             retval |= set_attnotnull(wqueue, childrel, childattno,
                               7775                 :                :                                      recurse, lockmode);
                               7776                 :             72 :             table_close(childrel, NoLock);
                               7777                 :                :         }
                               7778                 :                :     }
                               7779                 :                : 
                               7780                 :          11554 :     return retval;
                               7781                 :                : }
                               7782                 :                : 
                               7783                 :                : /*
                               7784                 :                :  * ALTER TABLE ALTER COLUMN SET NOT NULL
                               7785                 :                :  *
                               7786                 :                :  * Add a not-null constraint to a single table and its children.  Returns
                               7787                 :                :  * the address of the constraint added to the parent relation, if one gets
                               7788                 :                :  * added, or InvalidObjectAddress otherwise.
                               7789                 :                :  *
                               7790                 :                :  * We must recurse to child tables during execution, rather than using
                               7791                 :                :  * ALTER TABLE's normal prep-time recursion.
                               7792                 :                :  */
                               7793                 :                : static ObjectAddress
                               7794                 :            245 : ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName,
                               7795                 :                :                  bool recurse, bool recursing, List **readyRels,
                               7796                 :                :                  LOCKMODE lockmode)
                               7797                 :                : {
                               7798                 :                :     HeapTuple   tuple;
                               7799                 :                :     Relation    constr_rel;
                               7800                 :                :     ScanKeyData skey;
                               7801                 :                :     SysScanDesc conscan;
                               7802                 :                :     AttrNumber  attnum;
                               7803                 :                :     ObjectAddress address;
                               7804                 :                :     Constraint *constraint;
                               7805                 :                :     CookedConstraint *ccon;
                               7806                 :                :     List       *cooked;
                               7807                 :            245 :     bool        is_no_inherit = false;
                               7808                 :            245 :     List       *ready = NIL;
                               7809                 :                : 
                               7810                 :                :     /* Guard against stack overflow due to overly deep inheritance tree. */
  158                          7811                 :            245 :     check_stack_depth();
                               7812                 :                : 
                               7813                 :                :     /*
                               7814                 :                :      * In cases of multiple inheritance, we might visit the same child more
                               7815                 :                :      * than once.  In the topmost call, set up a list that we fill with all
                               7816                 :                :      * visited relations, to skip those.
                               7817                 :                :      */
  233                          7818         [ +  + ]:            245 :     if (readyRels == NULL)
                               7819                 :                :     {
                               7820         [ -  + ]:            180 :         Assert(!recursing);
                               7821                 :            180 :         readyRels = &ready;
                               7822                 :                :     }
                               7823         [ +  + ]:            245 :     if (list_member_oid(*readyRels, RelationGetRelid(rel)))
                               7824                 :              3 :         return InvalidObjectAddress;
                               7825                 :            242 :     *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
                               7826                 :                : 
                               7827                 :                :     /* At top level, permission check was done in ATPrepCmd, else do it */
                               7828         [ +  + ]:            242 :     if (recursing)
                               7829                 :                :     {
                               7830                 :             62 :         ATSimplePermissions(AT_AddConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               7831         [ -  + ]:             62 :         Assert(conName != NULL);
                               7832                 :                :     }
                               7833                 :                : 
                               7834                 :            242 :     attnum = get_attnum(RelationGetRelid(rel), colName);
                               7835         [ +  + ]:            242 :     if (attnum == InvalidAttrNumber)
 7574 tgl@sss.pgh.pa.us        7836         [ +  - ]:CBC           9 :         ereport(ERROR,
                               7837                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               7838                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               7839                 :                :                         colName, RelationGetRelationName(rel))));
                               7840                 :                : 
                               7841                 :                :     /* Prevent them from altering a system attribute */
 7284                          7842         [ -  + ]:            233 :     if (attnum <= 0)
 7574 tgl@sss.pgh.pa.us        7843         [ #  # ]:UBC           0 :         ereport(ERROR,
                               7844                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               7845                 :                :                  errmsg("cannot alter system column \"%s\"",
                               7846                 :                :                         colName)));
                               7847                 :                : 
                               7848                 :                :     /* See if there's already a constraint */
  233 alvherre@alvh.no-ip.     7849                 :GNC         233 :     constr_rel = table_open(ConstraintRelationId, RowExclusiveLock);
                               7850                 :            233 :     ScanKeyInit(&skey,
                               7851                 :                :                 Anum_pg_constraint_conrelid,
                               7852                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                               7853                 :                :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                               7854                 :            233 :     conscan = systable_beginscan(constr_rel, ConstraintRelidTypidNameIndexId, true,
                               7855                 :                :                                  NULL, 1, &skey);
                               7856                 :                : 
                               7857         [ +  + ]:            443 :     while (HeapTupleIsValid(tuple = systable_getnext(conscan)))
                               7858                 :                :     {
                               7859                 :            220 :         Form_pg_constraint conForm = (Form_pg_constraint) GETSTRUCT(tuple);
                               7860                 :            220 :         bool        changed = false;
                               7861                 :                :         HeapTuple   copytup;
                               7862                 :                : 
                               7863         [ +  + ]:            220 :         if (conForm->contype != CONSTRAINT_NOTNULL)
                               7864                 :            100 :             continue;
                               7865                 :                : 
                               7866         [ +  + ]:            120 :         if (extractNotNullColumn(tuple) != attnum)
                               7867                 :            110 :             continue;
                               7868                 :                : 
                               7869                 :             10 :         copytup = heap_copytuple(tuple);
                               7870                 :             10 :         conForm = (Form_pg_constraint) GETSTRUCT(copytup);
                               7871                 :                : 
                               7872                 :                :         /*
                               7873                 :                :          * If we find an appropriate constraint, we're almost done, but just
                               7874                 :                :          * need to change some properties on it: if we're recursing, increment
                               7875                 :                :          * coninhcount; if not, set conislocal if not already set.
                               7876                 :                :          */
                               7877         [ +  + ]:             10 :         if (recursing)
                               7878                 :                :         {
                               7879                 :              3 :             conForm->coninhcount++;
                               7880                 :              3 :             changed = true;
                               7881                 :                :         }
                               7882         [ -  + ]:              7 :         else if (!conForm->conislocal)
                               7883                 :                :         {
  233 alvherre@alvh.no-ip.     7884                 :UNC           0 :             conForm->conislocal = true;
                               7885                 :              0 :             changed = true;
                               7886                 :                :         }
                               7887                 :                : 
  233 alvherre@alvh.no-ip.     7888         [ +  + ]:GNC          10 :         if (changed)
                               7889                 :                :         {
                               7890                 :              3 :             CatalogTupleUpdate(constr_rel, &copytup->t_self, copytup);
                               7891                 :              3 :             ObjectAddressSet(address, ConstraintRelationId, conForm->oid);
                               7892                 :                :         }
                               7893                 :                : 
                               7894                 :             10 :         systable_endscan(conscan);
                               7895                 :             10 :         table_close(constr_rel, RowExclusiveLock);
                               7896                 :                : 
                               7897         [ +  + ]:             10 :         if (changed)
                               7898                 :              3 :             return address;
                               7899                 :                :         else
                               7900                 :              7 :             return InvalidObjectAddress;
                               7901                 :                :     }
                               7902                 :                : 
                               7903                 :            223 :     systable_endscan(conscan);
                               7904                 :            223 :     table_close(constr_rel, RowExclusiveLock);
                               7905                 :                : 
                               7906                 :                :     /*
                               7907                 :                :      * If we're asked not to recurse, and children exist, raise an error for
                               7908                 :                :      * partitioned tables.  For inheritance, we act as if NO INHERIT had been
                               7909                 :                :      * specified.
                               7910                 :                :      */
                               7911   [ +  +  +  + ]:            238 :     if (!recurse &&
                               7912                 :             15 :         find_inheritance_children(RelationGetRelid(rel),
                               7913                 :                :                                   NoLock) != NIL)
                               7914                 :                :     {
                               7915         [ +  + ]:             12 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               7916         [ +  - ]:              6 :             ereport(ERROR,
                               7917                 :                :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               7918                 :                :                     errmsg("constraint must be added to child tables too"),
                               7919                 :                :                     errhint("Do not specify the ONLY keyword."));
                               7920                 :                :         else
                               7921                 :              6 :             is_no_inherit = true;
                               7922                 :                :     }
                               7923                 :                : 
                               7924                 :                :     /*
                               7925                 :                :      * No constraint exists; we must add one.  First determine a name to use,
                               7926                 :                :      * if we haven't already.
                               7927                 :                :      */
                               7928         [ +  + ]:            217 :     if (!recursing)
                               7929                 :                :     {
                               7930         [ -  + ]:            158 :         Assert(conName == NULL);
                               7931                 :            158 :         conName = ChooseConstraintName(RelationGetRelationName(rel),
                               7932                 :                :                                        colName, "not_null",
                               7933                 :            158 :                                        RelationGetNamespace(rel),
                               7934                 :                :                                        NIL);
                               7935                 :                :     }
                               7936                 :            217 :     constraint = makeNode(Constraint);
                               7937                 :            217 :     constraint->contype = CONSTR_NOTNULL;
                               7938                 :            217 :     constraint->conname = conName;
                               7939                 :            217 :     constraint->deferrable = false;
                               7940                 :            217 :     constraint->initdeferred = false;
                               7941                 :            217 :     constraint->location = -1;
                               7942                 :            217 :     constraint->keys = list_make1(makeString(colName));
                               7943                 :            217 :     constraint->is_no_inherit = is_no_inherit;
                               7944                 :            217 :     constraint->inhcount = recursing ? 1 : 0;
                               7945                 :            217 :     constraint->skip_validation = false;
                               7946                 :            217 :     constraint->initially_valid = true;
                               7947                 :                : 
                               7948                 :                :     /* and do it */
                               7949                 :            217 :     cooked = AddRelationNewConstraints(rel, NIL, list_make1(constraint),
                               7950                 :            217 :                                        false, !recursing, false, NULL);
                               7951                 :            217 :     ccon = linitial(cooked);
                               7952                 :            217 :     ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
                               7953                 :                : 
  368 alvherre@alvh.no-ip.     7954         [ -  + ]:CBC         217 :     InvokeObjectPostAlterHook(RelationRelationId,
                               7955                 :                :                               RelationGetRelid(rel), attnum);
                               7956                 :                : 
                               7957                 :                :     /*
                               7958                 :                :      * Mark pg_attribute.attnotnull for the column. Tell that function not to
                               7959                 :                :      * recurse, because we're going to do it here.
                               7960                 :                :      */
  233 alvherre@alvh.no-ip.     7961                 :GNC         217 :     set_attnotnull(wqueue, rel, attnum, false, lockmode);
                               7962                 :                : 
                               7963                 :                :     /*
                               7964                 :                :      * Recurse to propagate the constraint to children that don't have one.
                               7965                 :                :      */
                               7966         [ +  + ]:            217 :     if (recurse)
                               7967                 :                :     {
                               7968                 :                :         List       *children;
                               7969                 :                :         ListCell   *lc;
                               7970                 :                : 
                               7971                 :            208 :         children = find_inheritance_children(RelationGetRelid(rel),
                               7972                 :                :                                              lockmode);
                               7973                 :                : 
                               7974   [ +  +  +  +  :            273 :         foreach(lc, children)
                                              +  + ]
                               7975                 :                :         {
                               7976                 :                :             Relation    childrel;
                               7977                 :                : 
                               7978                 :             65 :             childrel = table_open(lfirst_oid(lc), NoLock);
                               7979                 :                : 
                               7980                 :             65 :             ATExecSetNotNull(wqueue, childrel,
                               7981                 :                :                              conName, colName, recurse, true,
                               7982                 :                :                              readyRels, lockmode);
                               7983                 :                : 
                               7984                 :             65 :             table_close(childrel, NoLock);
                               7985                 :                :         }
                               7986                 :                :     }
                               7987                 :                : 
 3308 alvherre@alvh.no-ip.     7988                 :CBC         217 :     return address;
                               7989                 :                : }
                               7990                 :                : 
                               7991                 :                : /*
                               7992                 :                :  * ALTER TABLE ALTER COLUMN SET ATTNOTNULL
                               7993                 :                :  *
                               7994                 :                :  * This doesn't exist in the grammar; it's used when creating a
                               7995                 :                :  * primary key and the column is not already marked attnotnull.
                               7996                 :                :  */
                               7997                 :                : static ObjectAddress
  233 alvherre@alvh.no-ip.     7998                 :GNC        7120 : ATExecSetAttNotNull(List **wqueue, Relation rel,
                               7999                 :                :                     const char *colName, LOCKMODE lockmode)
                               8000                 :                : {
                               8001                 :                :     AttrNumber  attnum;
                               8002                 :           7120 :     ObjectAddress address = InvalidObjectAddress;
                               8003                 :                : 
                               8004                 :           7120 :     attnum = get_attnum(RelationGetRelid(rel), colName);
                               8005         [ +  + ]:           7120 :     if (attnum == InvalidAttrNumber)
 1818 tgl@sss.pgh.pa.us        8006         [ +  - ]:GBC           9 :         ereport(ERROR,
                               8007                 :                :                 errcode(ERRCODE_UNDEFINED_COLUMN),
                               8008                 :                :                 errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8009                 :                :                        colName, RelationGetRelationName(rel)));
                               8010                 :                : 
                               8011                 :                :     /*
                               8012                 :                :      * Make the change, if necessary, and only if so report the column as
                               8013                 :                :      * changed
                               8014                 :                :      */
  233 alvherre@alvh.no-ip.     8015         [ +  + ]:GNC        7111 :     if (set_attnotnull(wqueue, rel, attnum, false, lockmode))
                               8016                 :            338 :         ObjectAddressSubSet(address, RelationRelationId,
                               8017                 :                :                             RelationGetRelid(rel), attnum);
                               8018                 :                : 
                               8019                 :           7111 :     return address;
 1818 tgl@sss.pgh.pa.us        8020                 :ECB         (9) : }
                               8021                 :                : 
                               8022                 :                : /*
                               8023                 :                :  * NotNullImpliedByRelConstraints
                               8024                 :                :  *      Does rel's existing constraints imply NOT NULL for the given attribute?
                               8025                 :                :  */
                               8026                 :                : static bool
 1859 rhaas@postgresql.org     8027                 :CBC         666 : NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
                               8028                 :                : {
                               8029                 :            666 :     NullTest   *nnulltest = makeNode(NullTest);
                               8030                 :                : 
                               8031                 :           1332 :     nnulltest->arg = (Expr *) makeVar(1,
                               8032                 :            666 :                                       attr->attnum,
                               8033                 :                :                                       attr->atttypid,
                               8034                 :                :                                       attr->atttypmod,
                               8035                 :                :                                       attr->attcollation,
                               8036                 :                :                                       0);
                               8037                 :            666 :     nnulltest->nulltesttype = IS_NOT_NULL;
                               8038                 :                : 
                               8039                 :                :     /*
                               8040                 :                :      * argisrow = false is correct even for a composite column, because
                               8041                 :                :      * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
                               8042                 :                :      * case, just IS DISTINCT FROM NULL.
                               8043                 :                :      */
                               8044                 :            666 :     nnulltest->argisrow = false;
                               8045                 :            666 :     nnulltest->location = -1;
                               8046                 :                : 
                               8047         [ +  + ]:            666 :     if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
                               8048                 :                :     {
                               8049         [ +  + ]:             25 :         ereport(DEBUG1,
                               8050                 :                :                 (errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
                               8051                 :                :                                  RelationGetRelationName(rel), NameStr(attr->attname))));
                               8052                 :             25 :         return true;
                               8053                 :                :     }
                               8054                 :                : 
                               8055                 :            641 :     return false;
                               8056                 :                : }
                               8057                 :                : 
                               8058                 :                : /*
                               8059                 :                :  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
                               8060                 :                :  *
                               8061                 :                :  * Return the address of the affected column.
                               8062                 :                :  */
                               8063                 :                : static ObjectAddress
 7284 tgl@sss.pgh.pa.us        8064                 :            283 : ATExecColumnDefault(Relation rel, const char *colName,
                               8065                 :                :                     Node *newDefault, LOCKMODE lockmode)
                               8066                 :                : {
 2000 peter_e@gmx.net          8067                 :            283 :     TupleDesc   tupdesc = RelationGetDescr(rel);
                               8068                 :                :     AttrNumber  attnum;
                               8069                 :                :     ObjectAddress address;
                               8070                 :                : 
                               8071                 :                :     /*
                               8072                 :                :      * get the number of the attribute
                               8073                 :                :      */
 7284 tgl@sss.pgh.pa.us        8074                 :            283 :     attnum = get_attnum(RelationGetRelid(rel), colName);
                               8075         [ +  + ]:            283 :     if (attnum == InvalidAttrNumber)
                               8076         [ +  - ]:             15 :         ereport(ERROR,
                               8077                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8078                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8079                 :                :                         colName, RelationGetRelationName(rel))));
                               8080                 :                : 
                               8081                 :                :     /* Prevent them from altering a system attribute */
                               8082         [ -  + ]:            268 :     if (attnum <= 0)
 7574 tgl@sss.pgh.pa.us        8083         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8084                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8085                 :                :                  errmsg("cannot alter system column \"%s\"",
                               8086                 :                :                         colName)));
                               8087                 :                : 
 2000 peter_e@gmx.net          8088         [ +  + ]:CBC         268 :     if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
 2565                          8089   [ +  -  -  + ]:              9 :         ereport(ERROR,
                               8090                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                               8091                 :                :                  errmsg("column \"%s\" of relation \"%s\" is an identity column",
                               8092                 :                :                         colName, RelationGetRelationName(rel)),
                               8093                 :                :         /* translator: %s is an SQL ALTER command */
                               8094                 :                :                  newDefault ? 0 : errhint("Use %s instead.",
                               8095                 :                :                                           "ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY")));
                               8096                 :                : 
 1842 peter@eisentraut.org     8097         [ +  + ]:            259 :     if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
                               8098   [ +  -  -  +  :              3 :         ereport(ERROR,
                                              +  - ]
                               8099                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                               8100                 :                :                  errmsg("column \"%s\" of relation \"%s\" is a generated column",
                               8101                 :                :                         colName, RelationGetRelationName(rel)),
                               8102                 :                :                  newDefault ?
                               8103                 :                :         /* translator: %s is an SQL ALTER command */
                               8104                 :                :                  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... SET EXPRESSION") :
                               8105                 :                :                  (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_STORED ?
                               8106                 :                :                   errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION") : 0)));
                               8107                 :                : 
                               8108                 :                :     /*
                               8109                 :                :      * Remove any old default for the column.  We use RESTRICT here for
                               8110                 :                :      * safety, but at present we do not expect anything to depend on the
                               8111                 :                :      * default.
                               8112                 :                :      *
                               8113                 :                :      * We treat removing the existing default as an internal operation when it
                               8114                 :                :      * is preparatory to adding a new default, but as a user-initiated
                               8115                 :                :      * operation when the user asked for a drop.
                               8116                 :                :      */
 4462 rhaas@postgresql.org     8117                 :            256 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
                               8118                 :                :                       newDefault != NULL);
                               8119                 :                : 
 7284 tgl@sss.pgh.pa.us        8120         [ +  + ]:            256 :     if (newDefault)
                               8121                 :                :     {
                               8122                 :                :         /* SET DEFAULT */
                               8123                 :                :         RawColumnDefault *rawEnt;
                               8124                 :                : 
                               8125                 :            169 :         rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
                               8126                 :            169 :         rawEnt->attnum = attnum;
                               8127                 :            169 :         rawEnt->raw_default = newDefault;
 2209 andrew@dunslane.net      8128                 :            169 :         rawEnt->missingMode = false;
 1842 peter@eisentraut.org     8129                 :            169 :         rawEnt->generated = '\0';
                               8130                 :                : 
                               8131                 :                :         /*
                               8132                 :                :          * This function is intended for CREATE TABLE, so it processes a
                               8133                 :                :          * _list_ of defaults, but we just do one.
                               8134                 :                :          */
 4046 rhaas@postgresql.org     8135                 :            169 :         AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
                               8136                 :                :                                   false, true, false, NULL);
                               8137                 :                :     }
                               8138                 :                : 
 3308 alvherre@alvh.no-ip.     8139                 :            253 :     ObjectAddressSubSet(address, RelationRelationId,
                               8140                 :                :                         RelationGetRelid(rel), attnum);
                               8141                 :            253 :     return address;
                               8142                 :                : }
                               8143                 :                : 
                               8144                 :                : /*
                               8145                 :                :  * Add a pre-cooked default expression.
                               8146                 :                :  *
                               8147                 :                :  * Return the address of the affected column.
                               8148                 :                :  */
                               8149                 :                : static ObjectAddress
 1332 tgl@sss.pgh.pa.us        8150                 :             55 : ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
                               8151                 :                :                           Node *newDefault)
                               8152                 :                : {
                               8153                 :                :     ObjectAddress address;
                               8154                 :                : 
                               8155                 :                :     /* We assume no checking is required */
                               8156                 :                : 
                               8157                 :                :     /*
                               8158                 :                :      * Remove any old default for the column.  We use RESTRICT here for
                               8159                 :                :      * safety, but at present we do not expect anything to depend on the
                               8160                 :                :      * default.  (In ordinary cases, there could not be a default in place
                               8161                 :                :      * anyway, but it's possible when combining LIKE with inheritance.)
                               8162                 :                :      */
                               8163                 :             55 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
                               8164                 :                :                       true);
                               8165                 :                : 
                               8166                 :             55 :     (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
                               8167                 :                : 
                               8168                 :             55 :     ObjectAddressSubSet(address, RelationRelationId,
                               8169                 :                :                         RelationGetRelid(rel), attnum);
                               8170                 :             55 :     return address;
                               8171                 :                : }
                               8172                 :                : 
                               8173                 :                : /*
                               8174                 :                :  * ALTER TABLE ALTER COLUMN ADD IDENTITY
                               8175                 :                :  *
                               8176                 :                :  * Return the address of the affected column.
                               8177                 :                :  */
                               8178                 :                : static ObjectAddress
 2565 peter_e@gmx.net          8179                 :             74 : ATExecAddIdentity(Relation rel, const char *colName,
                               8180                 :                :                   Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
                               8181                 :                : {
                               8182                 :                :     Relation    attrelation;
                               8183                 :                :     HeapTuple   tuple;
                               8184                 :                :     Form_pg_attribute attTup;
                               8185                 :                :     AttrNumber  attnum;
                               8186                 :                :     ObjectAddress address;
                               8187                 :             74 :     ColumnDef  *cdef = castNode(ColumnDef, def);
                               8188                 :                :     bool        ispartitioned;
                               8189                 :                : 
   89 peter@eisentraut.org     8190                 :GNC          74 :     ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                               8191   [ +  +  -  + ]:             74 :     if (ispartitioned && !recurse)
   89 peter@eisentraut.org     8192         [ #  # ]:UNC           0 :         ereport(ERROR,
                               8193                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8194                 :                :                  errmsg("cannot add identity to a column of only the partitioned table"),
                               8195                 :                :                  errhint("Do not specify the ONLY keyword.")));
                               8196                 :                : 
   89 peter@eisentraut.org     8197   [ +  +  +  + ]:GNC          74 :     if (rel->rd_rel->relispartition && !recursing)
                               8198         [ +  - ]:              6 :         ereport(ERROR,
                               8199                 :                :                 errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8200                 :                :                 errmsg("cannot add identity to a column of a partition"));
                               8201                 :                : 
 1910 andres@anarazel.de       8202                 :CBC          68 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               8203                 :                : 
 2565 peter_e@gmx.net          8204                 :             68 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               8205         [ -  + ]:             68 :     if (!HeapTupleIsValid(tuple))
 2565 peter_e@gmx.net          8206         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8207                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8208                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8209                 :                :                         colName, RelationGetRelationName(rel))));
 2565 peter_e@gmx.net          8210                 :CBC          68 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8211                 :             68 :     attnum = attTup->attnum;
                               8212                 :                : 
                               8213                 :                :     /* Can't alter a system attribute */
                               8214         [ -  + ]:             68 :     if (attnum <= 0)
 2565 peter_e@gmx.net          8215         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8216                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8217                 :                :                  errmsg("cannot alter system column \"%s\"",
                               8218                 :                :                         colName)));
                               8219                 :                : 
                               8220                 :                :     /*
                               8221                 :                :      * Creating a column as identity implies NOT NULL, so adding the identity
                               8222                 :                :      * to an existing column that is not NOT NULL would create a state that
                               8223                 :                :      * cannot be reproduced without contortions.
                               8224                 :                :      */
 2565 peter_e@gmx.net          8225         [ +  + ]:CBC          68 :     if (!attTup->attnotnull)
                               8226         [ +  - ]:              3 :         ereport(ERROR,
                               8227                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8228                 :                :                  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
                               8229                 :                :                         colName, RelationGetRelationName(rel))));
                               8230                 :                : 
                               8231         [ +  + ]:             65 :     if (attTup->attidentity)
                               8232         [ +  - ]:              9 :         ereport(ERROR,
                               8233                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8234                 :                :                  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
                               8235                 :                :                         colName, RelationGetRelationName(rel))));
                               8236                 :                : 
                               8237         [ +  + ]:             56 :     if (attTup->atthasdef)
                               8238         [ +  - ]:              3 :         ereport(ERROR,
                               8239                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8240                 :                :                  errmsg("column \"%s\" of relation \"%s\" already has a default value",
                               8241                 :                :                         colName, RelationGetRelationName(rel))));
                               8242                 :                : 
                               8243                 :             53 :     attTup->attidentity = cdef->identity;
                               8244                 :             53 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8245                 :                : 
                               8246         [ -  + ]:             53 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8247                 :                :                               RelationGetRelid(rel),
                               8248                 :                :                               attTup->attnum);
                               8249                 :             53 :     ObjectAddressSubSet(address, RelationRelationId,
                               8250                 :                :                         RelationGetRelid(rel), attnum);
                               8251                 :             53 :     heap_freetuple(tuple);
                               8252                 :                : 
 1910 andres@anarazel.de       8253                 :             53 :     table_close(attrelation, RowExclusiveLock);
                               8254                 :                : 
                               8255                 :                :     /*
                               8256                 :                :      * Recurse to propagate the identity column to partitions.  Identity is
                               8257                 :                :      * not inherited in regular inheritance children.
                               8258                 :                :      */
   89 peter@eisentraut.org     8259   [ +  -  +  + ]:GNC          53 :     if (recurse && ispartitioned)
                               8260                 :                :     {
                               8261                 :                :         List       *children;
                               8262                 :                :         ListCell   *lc;
                               8263                 :                : 
                               8264                 :              5 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
                               8265                 :                : 
                               8266   [ +  +  +  +  :              8 :         foreach(lc, children)
                                              +  + ]
                               8267                 :                :         {
                               8268                 :                :             Relation    childrel;
                               8269                 :                : 
                               8270                 :              3 :             childrel = table_open(lfirst_oid(lc), NoLock);
                               8271                 :              3 :             ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
                               8272                 :              3 :             table_close(childrel, NoLock);
                               8273                 :                :         }
                               8274                 :                :     }
                               8275                 :                : 
 2565 peter_e@gmx.net          8276                 :CBC          53 :     return address;
                               8277                 :                : }
                               8278                 :                : 
                               8279                 :                : /*
                               8280                 :                :  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
                               8281                 :                :  *
                               8282                 :                :  * Return the address of the affected column.
                               8283                 :                :  */
                               8284                 :                : static ObjectAddress
   89 peter@eisentraut.org     8285                 :GNC          37 : ATExecSetIdentity(Relation rel, const char *colName, Node *def,
                               8286                 :                :                   LOCKMODE lockmode, bool recurse, bool recursing)
                               8287                 :                : {
                               8288                 :                :     ListCell   *option;
 2524 bruce@momjian.us         8289                 :CBC          37 :     DefElem    *generatedEl = NULL;
                               8290                 :                :     HeapTuple   tuple;
                               8291                 :                :     Form_pg_attribute attTup;
                               8292                 :                :     AttrNumber  attnum;
                               8293                 :                :     Relation    attrelation;
                               8294                 :                :     ObjectAddress address;
                               8295                 :                :     bool        ispartitioned;
                               8296                 :                : 
   89 peter@eisentraut.org     8297                 :GNC          37 :     ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                               8298   [ +  +  +  + ]:             37 :     if (ispartitioned && !recurse)
                               8299         [ +  - ]:              3 :         ereport(ERROR,
                               8300                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8301                 :                :                  errmsg("cannot change identity column of only the partitioned table"),
                               8302                 :                :                  errhint("Do not specify the ONLY keyword.")));
                               8303                 :                : 
                               8304   [ +  +  +  + ]:             34 :     if (rel->rd_rel->relispartition && !recursing)
                               8305         [ +  - ]:              6 :         ereport(ERROR,
                               8306                 :                :                 errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8307                 :                :                 errmsg("cannot change identity column of a partition"));
                               8308                 :                : 
 2565 peter_e@gmx.net          8309   [ +  +  +  +  :CBC          50 :     foreach(option, castNode(List, def))
                                              +  + ]
                               8310                 :                :     {
 2524 bruce@momjian.us         8311                 :             22 :         DefElem    *defel = lfirst_node(DefElem, option);
                               8312                 :                : 
 2565 peter_e@gmx.net          8313         [ +  - ]:             22 :         if (strcmp(defel->defname, "generated") == 0)
                               8314                 :                :         {
                               8315         [ -  + ]:             22 :             if (generatedEl)
 2565 peter_e@gmx.net          8316         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               8317                 :                :                         (errcode(ERRCODE_SYNTAX_ERROR),
                               8318                 :                :                          errmsg("conflicting or redundant options")));
 2565 peter_e@gmx.net          8319                 :CBC          22 :             generatedEl = defel;
                               8320                 :                :         }
                               8321                 :                :         else
 2565 peter_e@gmx.net          8322         [ #  # ]:UBC           0 :             elog(ERROR, "option \"%s\" not recognized",
                               8323                 :                :                  defel->defname);
                               8324                 :                :     }
                               8325                 :                : 
                               8326                 :                :     /*
                               8327                 :                :      * Even if there is nothing to change here, we run all the checks.  There
                               8328                 :                :      * will be a subsequent ALTER SEQUENCE that relies on everything being
                               8329                 :                :      * there.
                               8330                 :                :      */
                               8331                 :                : 
 1910 andres@anarazel.de       8332                 :CBC          28 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
 2565 peter_e@gmx.net          8333                 :             28 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               8334         [ -  + ]:             28 :     if (!HeapTupleIsValid(tuple))
 2565 peter_e@gmx.net          8335         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8336                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8337                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8338                 :                :                         colName, RelationGetRelationName(rel))));
                               8339                 :                : 
 2565 peter_e@gmx.net          8340                 :CBC          28 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8341                 :             28 :     attnum = attTup->attnum;
                               8342                 :                : 
                               8343         [ -  + ]:             28 :     if (attnum <= 0)
 2565 peter_e@gmx.net          8344         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8345                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8346                 :                :                  errmsg("cannot alter system column \"%s\"",
                               8347                 :                :                         colName)));
                               8348                 :                : 
 2565 peter_e@gmx.net          8349         [ +  + ]:CBC          28 :     if (!attTup->attidentity)
                               8350         [ +  - ]:              3 :         ereport(ERROR,
                               8351                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8352                 :                :                  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
                               8353                 :                :                         colName, RelationGetRelationName(rel))));
                               8354                 :                : 
                               8355         [ +  + ]:             25 :     if (generatedEl)
                               8356                 :                :     {
                               8357                 :             22 :         attTup->attidentity = defGetInt32(generatedEl);
                               8358                 :             22 :         CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8359                 :                : 
                               8360         [ -  + ]:             22 :         InvokeObjectPostAlterHook(RelationRelationId,
                               8361                 :                :                                   RelationGetRelid(rel),
                               8362                 :                :                                   attTup->attnum);
                               8363                 :             22 :         ObjectAddressSubSet(address, RelationRelationId,
                               8364                 :                :                             RelationGetRelid(rel), attnum);
                               8365                 :                :     }
                               8366                 :                :     else
                               8367                 :              3 :         address = InvalidObjectAddress;
                               8368                 :                : 
                               8369                 :             25 :     heap_freetuple(tuple);
 1910 andres@anarazel.de       8370                 :             25 :     table_close(attrelation, RowExclusiveLock);
                               8371                 :                : 
                               8372                 :                :     /*
                               8373                 :                :      * Recurse to propagate the identity change to partitions. Identity is not
                               8374                 :                :      * inherited in regular inheritance children.
                               8375                 :                :      */
   89 peter@eisentraut.org     8376   [ +  +  +  -  :GNC          25 :     if (generatedEl && recurse && ispartitioned)
                                              +  + ]
                               8377                 :                :     {
                               8378                 :                :         List       *children;
                               8379                 :                :         ListCell   *lc;
                               8380                 :                : 
                               8381                 :              3 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
                               8382                 :                : 
                               8383   [ +  -  +  +  :              9 :         foreach(lc, children)
                                              +  + ]
                               8384                 :                :         {
                               8385                 :                :             Relation    childrel;
                               8386                 :                : 
                               8387                 :              6 :             childrel = table_open(lfirst_oid(lc), NoLock);
                               8388                 :              6 :             ATExecSetIdentity(childrel, colName, def, lockmode, recurse, true);
                               8389                 :              6 :             table_close(childrel, NoLock);
                               8390                 :                :         }
                               8391                 :                :     }
                               8392                 :                : 
 2565 peter_e@gmx.net          8393                 :CBC          25 :     return address;
                               8394                 :                : }
                               8395                 :                : 
                               8396                 :                : /*
                               8397                 :                :  * ALTER TABLE ALTER COLUMN DROP IDENTITY
                               8398                 :                :  *
                               8399                 :                :  * Return the address of the affected column.
                               8400                 :                :  */
                               8401                 :                : static ObjectAddress
   89 peter@eisentraut.org     8402                 :GNC          46 : ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
                               8403                 :                :                    bool recurse, bool recursing)
                               8404                 :                : {
                               8405                 :                :     HeapTuple   tuple;
                               8406                 :                :     Form_pg_attribute attTup;
                               8407                 :                :     AttrNumber  attnum;
                               8408                 :                :     Relation    attrelation;
                               8409                 :                :     ObjectAddress address;
                               8410                 :                :     Oid         seqid;
                               8411                 :                :     ObjectAddress seqaddress;
                               8412                 :                :     bool        ispartitioned;
                               8413                 :                : 
                               8414                 :             46 :     ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                               8415   [ +  +  +  + ]:             46 :     if (ispartitioned && !recurse)
                               8416         [ +  - ]:              3 :         ereport(ERROR,
                               8417                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8418                 :                :                  errmsg("cannot drop identity from a column of only the partitioned table"),
                               8419                 :                :                  errhint("Do not specify the ONLY keyword.")));
                               8420                 :                : 
                               8421   [ +  +  +  + ]:             43 :     if (rel->rd_rel->relispartition && !recursing)
                               8422         [ +  - ]:              3 :         ereport(ERROR,
                               8423                 :                :                 errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8424                 :                :                 errmsg("cannot drop identity from a column of a partition"));
                               8425                 :                : 
 1910 andres@anarazel.de       8426                 :CBC          40 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
 2565 peter_e@gmx.net          8427                 :             40 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               8428         [ -  + ]:             40 :     if (!HeapTupleIsValid(tuple))
 2565 peter_e@gmx.net          8429         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8430                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8431                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8432                 :                :                         colName, RelationGetRelationName(rel))));
                               8433                 :                : 
 2565 peter_e@gmx.net          8434                 :CBC          40 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8435                 :             40 :     attnum = attTup->attnum;
                               8436                 :                : 
                               8437         [ -  + ]:             40 :     if (attnum <= 0)
 2565 peter_e@gmx.net          8438         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8439                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8440                 :                :                  errmsg("cannot alter system column \"%s\"",
                               8441                 :                :                         colName)));
                               8442                 :                : 
 2565 peter_e@gmx.net          8443         [ +  + ]:CBC          40 :     if (!attTup->attidentity)
                               8444                 :                :     {
                               8445         [ +  + ]:              6 :         if (!missing_ok)
                               8446         [ +  - ]:              3 :             ereport(ERROR,
                               8447                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8448                 :                :                      errmsg("column \"%s\" of relation \"%s\" is not an identity column",
                               8449                 :                :                             colName, RelationGetRelationName(rel))));
                               8450                 :                :         else
                               8451                 :                :         {
                               8452         [ +  - ]:              3 :             ereport(NOTICE,
                               8453                 :                :                     (errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
                               8454                 :                :                             colName, RelationGetRelationName(rel))));
                               8455                 :              3 :             heap_freetuple(tuple);
 1910 andres@anarazel.de       8456                 :              3 :             table_close(attrelation, RowExclusiveLock);
 2565 peter_e@gmx.net          8457                 :              3 :             return InvalidObjectAddress;
                               8458                 :                :         }
                               8459                 :                :     }
                               8460                 :                : 
                               8461                 :             34 :     attTup->attidentity = '\0';
                               8462                 :             34 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8463                 :                : 
                               8464         [ -  + ]:             34 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8465                 :                :                               RelationGetRelid(rel),
                               8466                 :                :                               attTup->attnum);
                               8467                 :             34 :     ObjectAddressSubSet(address, RelationRelationId,
                               8468                 :                :                         RelationGetRelid(rel), attnum);
                               8469                 :             34 :     heap_freetuple(tuple);
                               8470                 :                : 
 1910 andres@anarazel.de       8471                 :             34 :     table_close(attrelation, RowExclusiveLock);
                               8472                 :                : 
                               8473                 :                :     /*
                               8474                 :                :      * Recurse to drop the identity from column in partitions.  Identity is
                               8475                 :                :      * not inherited in regular inheritance children so ignore them.
                               8476                 :                :      */
   89 peter@eisentraut.org     8477   [ +  -  +  + ]:GNC          34 :     if (recurse && ispartitioned)
                               8478                 :                :     {
                               8479                 :                :         List       *children;
                               8480                 :                :         ListCell   *lc;
                               8481                 :                : 
                               8482                 :              3 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
                               8483                 :                : 
                               8484   [ +  -  +  +  :              6 :         foreach(lc, children)
                                              +  + ]
                               8485                 :                :         {
                               8486                 :                :             Relation    childrel;
                               8487                 :                : 
                               8488                 :              3 :             childrel = table_open(lfirst_oid(lc), NoLock);
                               8489                 :              3 :             ATExecDropIdentity(childrel, colName, false, lockmode, recurse, true);
                               8490                 :              3 :             table_close(childrel, NoLock);
                               8491                 :                :         }
                               8492                 :                :     }
                               8493                 :                : 
                               8494         [ +  + ]:             34 :     if (!recursing)
                               8495                 :                :     {
                               8496                 :                :         /* drop the internal sequence */
                               8497                 :             16 :         seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
                               8498                 :             16 :         deleteDependencyRecordsForClass(RelationRelationId, seqid,
                               8499                 :                :                                         RelationRelationId, DEPENDENCY_INTERNAL);
                               8500                 :             16 :         CommandCounterIncrement();
                               8501                 :             16 :         seqaddress.classId = RelationRelationId;
                               8502                 :             16 :         seqaddress.objectId = seqid;
                               8503                 :             16 :         seqaddress.objectSubId = 0;
                               8504                 :             16 :         performDeletion(&seqaddress, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
                               8505                 :                :     }
                               8506                 :                : 
 2565 peter_e@gmx.net          8507                 :             34 :     return address;
                               8508                 :                : }
                               8509                 :                : 
                               8510                 :                : /*
                               8511                 :                :  * ALTER TABLE ALTER COLUMN SET EXPRESSION
                               8512                 :                :  *
                               8513                 :                :  * Return the address of the affected column.
                               8514                 :                :  */
                               8515                 :                : static ObjectAddress
  101 peter@eisentraut.org     8516                 :             42 : ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
                               8517                 :                :                     Node *newExpr, LOCKMODE lockmode)
                               8518                 :                : {
                               8519                 :                :     HeapTuple   tuple;
                               8520                 :                :     Form_pg_attribute attTup;
                               8521                 :                :     AttrNumber  attnum;
                               8522                 :                :     Oid         attrdefoid;
                               8523                 :                :     ObjectAddress address;
                               8524                 :                :     Expr       *defval;
                               8525                 :                :     NewColumnValue *newval;
                               8526                 :                :     RawColumnDefault *rawEnt;
                               8527                 :                : 
                               8528                 :             42 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
                               8529         [ -  + ]:             42 :     if (!HeapTupleIsValid(tuple))
  101 peter@eisentraut.org     8530         [ #  # ]:UNC           0 :         ereport(ERROR,
                               8531                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8532                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8533                 :                :                         colName, RelationGetRelationName(rel))));
                               8534                 :                : 
  101 peter@eisentraut.org     8535                 :GNC          42 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8536                 :             42 :     attnum = attTup->attnum;
                               8537                 :                : 
                               8538         [ -  + ]:             42 :     if (attnum <= 0)
  101 peter@eisentraut.org     8539         [ #  # ]:UNC           0 :         ereport(ERROR,
                               8540                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8541                 :                :                  errmsg("cannot alter system column \"%s\"",
                               8542                 :                :                         colName)));
                               8543                 :                : 
  101 peter@eisentraut.org     8544         [ +  + ]:GNC          42 :     if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
                               8545         [ +  - ]:              3 :         ereport(ERROR,
                               8546                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8547                 :                :                  errmsg("column \"%s\" of relation \"%s\" is not a generated column",
                               8548                 :                :                         colName, RelationGetRelationName(rel))));
                               8549                 :             39 :     ReleaseSysCache(tuple);
                               8550                 :                : 
                               8551                 :                :     /*
                               8552                 :                :      * Clear all the missing values if we're rewriting the table, since this
                               8553                 :                :      * renders them pointless.
                               8554                 :                :      */
                               8555                 :             39 :     RelationClearMissing(rel);
                               8556                 :                : 
                               8557                 :                :     /* make sure we don't conflict with later attribute modifications */
                               8558                 :             39 :     CommandCounterIncrement();
                               8559                 :                : 
                               8560                 :                :     /*
                               8561                 :                :      * Find everything that depends on the column (constraints, indexes, etc),
                               8562                 :                :      * and record enough information to let us recreate the objects after
                               8563                 :                :      * rewrite.
                               8564                 :                :      */
                               8565                 :             39 :     RememberAllDependentForRebuilding(tab, AT_SetExpression, rel, attnum, colName);
                               8566                 :                : 
                               8567                 :                :     /*
                               8568                 :                :      * Drop the dependency records of the GENERATED expression, in particular
                               8569                 :                :      * its INTERNAL dependency on the column, which would otherwise cause
                               8570                 :                :      * dependency.c to refuse to perform the deletion.
                               8571                 :                :      */
                               8572                 :             39 :     attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
                               8573         [ -  + ]:             39 :     if (!OidIsValid(attrdefoid))
  101 peter@eisentraut.org     8574         [ #  # ]:UNC           0 :         elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
                               8575                 :                :              RelationGetRelid(rel), attnum);
  101 peter@eisentraut.org     8576                 :GNC          39 :     (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
                               8577                 :                : 
                               8578                 :                :     /* Make above changes visible */
                               8579                 :             39 :     CommandCounterIncrement();
                               8580                 :                : 
                               8581                 :                :     /*
                               8582                 :                :      * Get rid of the GENERATED expression itself.  We use RESTRICT here for
                               8583                 :                :      * safety, but at present we do not expect anything to depend on the
                               8584                 :                :      * expression.
                               8585                 :                :      */
                               8586                 :             39 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT,
                               8587                 :                :                       false, false);
                               8588                 :                : 
                               8589                 :                :     /* Prepare to store the new expression, in the catalogs */
                               8590                 :             39 :     rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
                               8591                 :             39 :     rawEnt->attnum = attnum;
                               8592                 :             39 :     rawEnt->raw_default = newExpr;
                               8593                 :             39 :     rawEnt->missingMode = false;
                               8594                 :             39 :     rawEnt->generated = ATTRIBUTE_GENERATED_STORED;
                               8595                 :                : 
                               8596                 :                :     /* Store the generated expression */
                               8597                 :             39 :     AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
                               8598                 :                :                               false, true, false, NULL);
                               8599                 :                : 
                               8600                 :                :     /* Make above new expression visible */
                               8601                 :             39 :     CommandCounterIncrement();
                               8602                 :                : 
                               8603                 :                :     /* Prepare for table rewrite */
                               8604                 :             39 :     defval = (Expr *) build_column_default(rel, attnum);
                               8605                 :                : 
                               8606                 :             39 :     newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
                               8607                 :             39 :     newval->attnum = attnum;
                               8608                 :             39 :     newval->expr = expression_planner(defval);
                               8609                 :             39 :     newval->is_generated = true;
                               8610                 :                : 
                               8611                 :             39 :     tab->newvals = lappend(tab->newvals, newval);
                               8612                 :             39 :     tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
                               8613                 :                : 
                               8614                 :                :     /* Drop any pg_statistic entry for the column */
                               8615                 :             39 :     RemoveStatistics(RelationGetRelid(rel), attnum);
                               8616                 :                : 
                               8617         [ -  + ]:             39 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8618                 :                :                               RelationGetRelid(rel), attnum);
                               8619                 :                : 
                               8620                 :             39 :     ObjectAddressSubSet(address, RelationRelationId,
                               8621                 :                :                         RelationGetRelid(rel), attnum);
  101 peter@eisentraut.org     8622                 :CBC          39 :     return address;
                               8623                 :                : }
                               8624                 :                : 
                               8625                 :                : /*
                               8626                 :                :  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
                               8627                 :                :  */
                               8628                 :                : static void
 1258                          8629                 :             22 : ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
                               8630                 :                : {
                               8631                 :                :     /*
                               8632                 :                :      * Reject ONLY if there are child tables.  We could implement this, but it
                               8633                 :                :      * is a bit complicated.  GENERATED clauses must be attached to the column
                               8634                 :                :      * definition and cannot be added later like DEFAULT, so if a child table
                               8635                 :                :      * has a generation expression that the parent does not have, the child
                               8636                 :                :      * column will necessarily be an attislocal column.  So to implement ONLY
                               8637                 :                :      * here, we'd need extra code to update attislocal of the direct child
                               8638                 :                :      * tables, somewhat similar to how DROP COLUMN does it, so that the
                               8639                 :                :      * resulting state can be properly dumped and restored.
                               8640                 :                :      */
                               8641   [ +  +  +  + ]:             28 :     if (!recurse &&
 1082 alvherre@alvh.no-ip.     8642                 :              6 :         find_inheritance_children(RelationGetRelid(rel), lockmode))
 1258 peter@eisentraut.org     8643         [ +  - ]:              3 :         ereport(ERROR,
                               8644                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8645                 :                :                  errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
                               8646                 :                : 
                               8647                 :                :     /*
                               8648                 :                :      * Cannot drop generation expression from inherited columns.
                               8649                 :                :      */
 1552                          8650         [ +  + ]:             19 :     if (!recursing)
                               8651                 :                :     {
                               8652                 :                :         HeapTuple   tuple;
                               8653                 :                :         Form_pg_attribute attTup;
                               8654                 :                : 
                               8655                 :             16 :         tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
                               8656         [ -  + ]:             16 :         if (!HeapTupleIsValid(tuple))
 1552 peter@eisentraut.org     8657         [ #  # ]:UBC           0 :             ereport(ERROR,
                               8658                 :                :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8659                 :                :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8660                 :                :                             cmd->name, RelationGetRelationName(rel))));
                               8661                 :                : 
 1552 peter@eisentraut.org     8662                 :CBC          16 :         attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8663                 :                : 
                               8664         [ +  + ]:             16 :         if (attTup->attinhcount > 0)
                               8665         [ +  - ]:              3 :             ereport(ERROR,
                               8666                 :                :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               8667                 :                :                      errmsg("cannot drop generation expression from inherited column")));
                               8668                 :                :     }
                               8669                 :             16 : }
                               8670                 :                : 
                               8671                 :                : /*
                               8672                 :                :  * Return the address of the affected column.
                               8673                 :                :  */
                               8674                 :                : static ObjectAddress
                               8675                 :             16 : ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
                               8676                 :                : {
                               8677                 :                :     HeapTuple   tuple;
                               8678                 :                :     Form_pg_attribute attTup;
                               8679                 :                :     AttrNumber  attnum;
                               8680                 :                :     Relation    attrelation;
                               8681                 :                :     Oid         attrdefoid;
                               8682                 :                :     ObjectAddress address;
                               8683                 :                : 
                               8684                 :             16 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               8685                 :             16 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               8686         [ -  + ]:             16 :     if (!HeapTupleIsValid(tuple))
 1552 peter@eisentraut.org     8687         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8688                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8689                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8690                 :                :                         colName, RelationGetRelationName(rel))));
                               8691                 :                : 
 1552 peter@eisentraut.org     8692                 :CBC          16 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                               8693                 :             16 :     attnum = attTup->attnum;
                               8694                 :                : 
                               8695         [ -  + ]:             16 :     if (attnum <= 0)
 1552 peter@eisentraut.org     8696         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8697                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8698                 :                :                  errmsg("cannot alter system column \"%s\"",
                               8699                 :                :                         colName)));
                               8700                 :                : 
 1552 peter@eisentraut.org     8701         [ +  + ]:CBC          16 :     if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
                               8702                 :                :     {
                               8703         [ +  + ]:              6 :         if (!missing_ok)
                               8704         [ +  - ]:              3 :             ereport(ERROR,
                               8705                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               8706                 :                :                      errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
                               8707                 :                :                             colName, RelationGetRelationName(rel))));
                               8708                 :                :         else
                               8709                 :                :         {
                               8710         [ +  - ]:              3 :             ereport(NOTICE,
                               8711                 :                :                     (errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
                               8712                 :                :                             colName, RelationGetRelationName(rel))));
                               8713                 :              3 :             heap_freetuple(tuple);
                               8714                 :              3 :             table_close(attrelation, RowExclusiveLock);
                               8715                 :              3 :             return InvalidObjectAddress;
                               8716                 :                :         }
                               8717                 :                :     }
                               8718                 :                : 
                               8719                 :                :     /*
                               8720                 :                :      * Mark the column as no longer generated.  (The atthasdef flag needs to
                               8721                 :                :      * get cleared too, but RemoveAttrDefault will handle that.)
                               8722                 :                :      */
                               8723                 :             10 :     attTup->attgenerated = '\0';
                               8724                 :             10 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               8725                 :                : 
                               8726         [ -  + ]:             10 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8727                 :                :                               RelationGetRelid(rel),
                               8728                 :                :                               attnum);
                               8729                 :             10 :     heap_freetuple(tuple);
                               8730                 :                : 
                               8731                 :             10 :     table_close(attrelation, RowExclusiveLock);
                               8732                 :                : 
                               8733                 :                :     /*
                               8734                 :                :      * Drop the dependency records of the GENERATED expression, in particular
                               8735                 :                :      * its INTERNAL dependency on the column, which would otherwise cause
                               8736                 :                :      * dependency.c to refuse to perform the deletion.
                               8737                 :                :      */
  755 tgl@sss.pgh.pa.us        8738                 :             10 :     attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
                               8739         [ -  + ]:             10 :     if (!OidIsValid(attrdefoid))
  755 tgl@sss.pgh.pa.us        8740         [ #  # ]:UBC           0 :         elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
                               8741                 :                :              RelationGetRelid(rel), attnum);
  755 tgl@sss.pgh.pa.us        8742                 :CBC          10 :     (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
                               8743                 :                : 
                               8744                 :                :     /* Make above changes visible */
                               8745                 :             10 :     CommandCounterIncrement();
                               8746                 :                : 
                               8747                 :                :     /*
                               8748                 :                :      * Get rid of the GENERATED expression itself.  We use RESTRICT here for
                               8749                 :                :      * safety, but at present we do not expect anything to depend on the
                               8750                 :                :      * default.
                               8751                 :                :      */
                               8752                 :             10 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT,
                               8753                 :                :                       false, false);
                               8754                 :                : 
                               8755                 :             10 :     ObjectAddressSubSet(address, RelationRelationId,
                               8756                 :                :                         RelationGetRelid(rel), attnum);
 1552 peter@eisentraut.org     8757                 :             10 :     return address;
                               8758                 :                : }
                               8759                 :                : 
                               8760                 :                : /*
                               8761                 :                :  * ALTER TABLE ALTER COLUMN SET STATISTICS
                               8762                 :                :  *
                               8763                 :                :  * Return value is the address of the modified column
                               8764                 :                :  */
                               8765                 :                : static ObjectAddress
 1586                          8766                 :             82 : ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
                               8767                 :                : {
   28 nathan@postgresql.or     8768                 :GNC          82 :     int         newtarget = 0;
                               8769                 :                :     bool        newtarget_default;
                               8770                 :                :     Relation    attrelation;
                               8771                 :                :     HeapTuple   tuple,
                               8772                 :                :                 newtuple;
                               8773                 :                :     Form_pg_attribute attrtuple;
                               8774                 :                :     AttrNumber  attnum;
                               8775                 :                :     ObjectAddress address;
                               8776                 :                :     Datum       repl_val[Natts_pg_attribute];
                               8777                 :                :     bool        repl_null[Natts_pg_attribute];
                               8778                 :                :     bool        repl_repl[Natts_pg_attribute];
                               8779                 :                : 
                               8780                 :                :     /*
                               8781                 :                :      * We allow referencing columns by numbers only for indexes, since table
                               8782                 :                :      * column numbers could contain gaps if columns are later dropped.
                               8783                 :                :      */
 2277 alvherre@alvh.no-ip.     8784         [ +  + ]:CBC          82 :     if (rel->rd_rel->relkind != RELKIND_INDEX &&
                               8785   [ +  -  -  + ]:             50 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
                               8786                 :                :         !colName)
 2412 simon@2ndQuadrant.co     8787         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8788                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8789                 :                :                  errmsg("cannot refer to non-index column by number")));
                               8790                 :                : 
                               8791                 :                :     /* -1 was used in previous versions for the default setting */
   28 peter@eisentraut.org     8792   [ +  -  +  + ]:GNC          82 :     if (newValue && intVal(newValue) != -1)
                               8793                 :                :     {
   92                          8794                 :             60 :         newtarget = intVal(newValue);
   28                          8795                 :             60 :         newtarget_default = false;
                               8796                 :                :     }
                               8797                 :                :     else
                               8798                 :             22 :         newtarget_default = true;
                               8799                 :                : 
                               8800         [ +  + ]:             82 :     if (!newtarget_default)
                               8801                 :                :     {
                               8802                 :                :         /*
                               8803                 :                :          * Limit target to a sane range
                               8804                 :                :          */
                               8805         [ -  + ]:             60 :         if (newtarget < 0)
                               8806                 :                :         {
   28 peter@eisentraut.org     8807         [ #  # ]:UNC           0 :             ereport(ERROR,
                               8808                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               8809                 :                :                      errmsg("statistics target %d is too low",
                               8810                 :                :                             newtarget)));
                               8811                 :                :         }
   28 peter@eisentraut.org     8812         [ -  + ]:GNC          60 :         else if (newtarget > MAX_STATISTICS_TARGET)
                               8813                 :                :         {
   28 peter@eisentraut.org     8814                 :UNC           0 :             newtarget = MAX_STATISTICS_TARGET;
                               8815         [ #  # ]:              0 :             ereport(WARNING,
                               8816                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               8817                 :                :                      errmsg("lowering statistics target to %d",
                               8818                 :                :                             newtarget)));
                               8819                 :                :         }
                               8820                 :                :     }
                               8821                 :                : 
 1910 andres@anarazel.de       8822                 :CBC          82 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               8823                 :                : 
 2412 simon@2ndQuadrant.co     8824         [ +  + ]:             82 :     if (colName)
                               8825                 :                :     {
   92 peter@eisentraut.org     8826                 :GNC          50 :         tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
                               8827                 :                : 
 2412 simon@2ndQuadrant.co     8828         [ +  + ]:CBC          50 :         if (!HeapTupleIsValid(tuple))
                               8829         [ +  - ]:              6 :             ereport(ERROR,
                               8830                 :                :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8831                 :                :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8832                 :                :                             colName, RelationGetRelationName(rel))));
                               8833                 :                :     }
                               8834                 :                :     else
                               8835                 :                :     {
   92 peter@eisentraut.org     8836                 :GNC          32 :         tuple = SearchSysCacheAttNum(RelationGetRelid(rel), colNum);
                               8837                 :                : 
 2412 simon@2ndQuadrant.co     8838         [ +  + ]:CBC          32 :         if (!HeapTupleIsValid(tuple))
                               8839         [ +  - ]:              6 :             ereport(ERROR,
                               8840                 :                :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8841                 :                :                      errmsg("column number %d of relation \"%s\" does not exist",
                               8842                 :                :                             colNum, RelationGetRelationName(rel))));
                               8843                 :                :     }
                               8844                 :                : 
 7284 tgl@sss.pgh.pa.us        8845                 :             70 :     attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
                               8846                 :                : 
 3308 alvherre@alvh.no-ip.     8847                 :             70 :     attnum = attrtuple->attnum;
                               8848         [ -  + ]:             70 :     if (attnum <= 0)
 7574 tgl@sss.pgh.pa.us        8849         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8850                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8851                 :                :                  errmsg("cannot alter system column \"%s\"",
                               8852                 :                :                         colName)));
                               8853                 :                : 
 2099 alvherre@alvh.no-ip.     8854         [ +  + ]:CBC          70 :     if (rel->rd_rel->relkind == RELKIND_INDEX ||
                               8855         [ -  + ]:             44 :         rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
                               8856                 :                :     {
                               8857         [ +  + ]:             26 :         if (attnum > rel->rd_index->indnkeyatts)
                               8858         [ +  - ]:              3 :             ereport(ERROR,
                               8859                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8860                 :                :                      errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
                               8861                 :                :                             NameStr(attrtuple->attname), RelationGetRelationName(rel))));
                               8862         [ +  + ]:             23 :         else if (rel->rd_index->indkey.values[attnum - 1] != 0)
                               8863         [ +  - ]:              9 :             ereport(ERROR,
                               8864                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8865                 :                :                      errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
                               8866                 :                :                             NameStr(attrtuple->attname), RelationGetRelationName(rel)),
                               8867                 :                :                      errhint("Alter statistics on table column instead.")));
                               8868                 :                :     }
                               8869                 :                : 
                               8870                 :                :     /* Build new tuple. */
   92 peter@eisentraut.org     8871                 :GNC          58 :     memset(repl_null, false, sizeof(repl_null));
                               8872                 :             58 :     memset(repl_repl, false, sizeof(repl_repl));
   28                          8873         [ +  + ]:             58 :     if (!newtarget_default)
   92                          8874                 :             36 :         repl_val[Anum_pg_attribute_attstattarget - 1] = newtarget;
                               8875                 :                :     else
                               8876                 :             22 :         repl_null[Anum_pg_attribute_attstattarget - 1] = true;
                               8877                 :             58 :     repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
                               8878                 :             58 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
                               8879                 :                :                                  repl_val, repl_null, repl_repl);
                               8880                 :             58 :     CatalogTupleUpdate(attrelation, &tuple->t_self, newtuple);
                               8881                 :                : 
 4046 rhaas@postgresql.org     8882         [ -  + ]:CBC          58 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8883                 :                :                               RelationGetRelid(rel),
                               8884                 :                :                               attrtuple->attnum);
 3308 alvherre@alvh.no-ip.     8885                 :             58 :     ObjectAddressSubSet(address, RelationRelationId,
                               8886                 :                :                         RelationGetRelid(rel), attnum);
                               8887                 :                : 
   92 peter@eisentraut.org     8888                 :GNC          58 :     heap_freetuple(newtuple);
                               8889                 :                : 
                               8890                 :             58 :     ReleaseSysCache(tuple);
                               8891                 :                : 
 1910 andres@anarazel.de       8892                 :CBC          58 :     table_close(attrelation, RowExclusiveLock);
                               8893                 :                : 
 3308 alvherre@alvh.no-ip.     8894                 :             58 :     return address;
                               8895                 :                : }
                               8896                 :                : 
                               8897                 :                : /*
                               8898                 :                :  * Return value is the address of the modified column
                               8899                 :                :  */
                               8900                 :                : static ObjectAddress
 5196 rhaas@postgresql.org     8901                 :             16 : ATExecSetOptions(Relation rel, const char *colName, Node *options,
                               8902                 :                :                  bool isReset, LOCKMODE lockmode)
                               8903                 :                : {
                               8904                 :                :     Relation    attrelation;
                               8905                 :                :     HeapTuple   tuple,
                               8906                 :                :                 newtuple;
                               8907                 :                :     Form_pg_attribute attrtuple;
                               8908                 :                :     AttrNumber  attnum;
                               8909                 :                :     Datum       datum,
                               8910                 :                :                 newOptions;
                               8911                 :                :     bool        isnull;
                               8912                 :                :     ObjectAddress address;
                               8913                 :                :     Datum       repl_val[Natts_pg_attribute];
                               8914                 :                :     bool        repl_null[Natts_pg_attribute];
                               8915                 :                :     bool        repl_repl[Natts_pg_attribute];
                               8916                 :                : 
 1910 andres@anarazel.de       8917                 :             16 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               8918                 :                : 
 5196 rhaas@postgresql.org     8919                 :             16 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
                               8920                 :                : 
 5369 tgl@sss.pgh.pa.us        8921         [ -  + ]:             16 :     if (!HeapTupleIsValid(tuple))
 5369 tgl@sss.pgh.pa.us        8922         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8923                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               8924                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               8925                 :                :                         colName, RelationGetRelationName(rel))));
 5369 tgl@sss.pgh.pa.us        8926                 :CBC          16 :     attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
                               8927                 :                : 
 3308 alvherre@alvh.no-ip.     8928                 :             16 :     attnum = attrtuple->attnum;
                               8929         [ -  + ]:             16 :     if (attnum <= 0)
 5369 tgl@sss.pgh.pa.us        8930         [ #  # ]:UBC           0 :         ereport(ERROR,
                               8931                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               8932                 :                :                  errmsg("cannot alter system column \"%s\"",
                               8933                 :                :                         colName)));
                               8934                 :                : 
                               8935                 :                :     /* Generate new proposed attoptions (text array) */
 5196 rhaas@postgresql.org     8936                 :CBC          16 :     datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
                               8937                 :                :                             &isnull);
                               8938         [ +  + ]:             16 :     newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
 2635 andres@anarazel.de       8939                 :             16 :                                      castNode(List, options), NULL, NULL,
                               8940                 :                :                                      false, isReset);
                               8941                 :                :     /* Validate new options */
 5196 rhaas@postgresql.org     8942                 :             16 :     (void) attribute_reloptions(newOptions, true);
                               8943                 :                : 
                               8944                 :                :     /* Build new tuple. */
                               8945                 :             16 :     memset(repl_null, false, sizeof(repl_null));
                               8946                 :             16 :     memset(repl_repl, false, sizeof(repl_repl));
                               8947         [ +  - ]:             16 :     if (newOptions != (Datum) 0)
                               8948                 :             16 :         repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
                               8949                 :                :     else
 5196 rhaas@postgresql.org     8950                 :UBC           0 :         repl_null[Anum_pg_attribute_attoptions - 1] = true;
 5196 rhaas@postgresql.org     8951                 :CBC          16 :     repl_repl[Anum_pg_attribute_attoptions - 1] = true;
                               8952                 :             16 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
                               8953                 :                :                                  repl_val, repl_null, repl_repl);
                               8954                 :                : 
                               8955                 :                :     /* Update system catalog. */
 2630 alvherre@alvh.no-ip.     8956                 :             16 :     CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
                               8957                 :                : 
 4046 rhaas@postgresql.org     8958         [ -  + ]:             16 :     InvokeObjectPostAlterHook(RelationRelationId,
                               8959                 :                :                               RelationGetRelid(rel),
                               8960                 :                :                               attrtuple->attnum);
 3308 alvherre@alvh.no-ip.     8961                 :             16 :     ObjectAddressSubSet(address, RelationRelationId,
                               8962                 :                :                         RelationGetRelid(rel), attnum);
                               8963                 :                : 
 5196 rhaas@postgresql.org     8964                 :             16 :     heap_freetuple(newtuple);
                               8965                 :                : 
 4046                          8966                 :             16 :     ReleaseSysCache(tuple);
                               8967                 :                : 
 1910 andres@anarazel.de       8968                 :             16 :     table_close(attrelation, RowExclusiveLock);
                               8969                 :                : 
 3308 alvherre@alvh.no-ip.     8970                 :             16 :     return address;
                               8971                 :                : }
                               8972                 :                : 
                               8973                 :                : /*
                               8974                 :                :  * Helper function for ATExecSetStorage and ATExecSetCompression
                               8975                 :                :  *
                               8976                 :                :  * Set the attstorage and/or attcompression fields for index columns
                               8977                 :                :  * associated with the specified table column.
                               8978                 :                :  */
                               8979                 :                : static void
 1122 rhaas@postgresql.org     8980                 :            141 : SetIndexStorageProperties(Relation rel, Relation attrelation,
                               8981                 :                :                           AttrNumber attnum,
                               8982                 :                :                           bool setstorage, char newstorage,
                               8983                 :                :                           bool setcompression, char newcompression,
                               8984                 :                :                           LOCKMODE lockmode)
                               8985                 :                : {
                               8986                 :                :     ListCell   *lc;
                               8987                 :                : 
                               8988   [ +  +  +  +  :            177 :     foreach(lc, RelationGetIndexList(rel))
                                              +  + ]
                               8989                 :                :     {
                               8990                 :             36 :         Oid         indexoid = lfirst_oid(lc);
                               8991                 :                :         Relation    indrel;
                               8992                 :             36 :         AttrNumber  indattnum = 0;
                               8993                 :                :         HeapTuple   tuple;
                               8994                 :                : 
                               8995                 :             36 :         indrel = index_open(indexoid, lockmode);
                               8996                 :                : 
                               8997         [ +  + ]:             60 :         for (int i = 0; i < indrel->rd_index->indnatts; i++)
                               8998                 :                :         {
                               8999         [ +  + ]:             39 :             if (indrel->rd_index->indkey.values[i] == attnum)
                               9000                 :                :             {
                               9001                 :             15 :                 indattnum = i + 1;
                               9002                 :             15 :                 break;
                               9003                 :                :             }
                               9004                 :                :         }
                               9005                 :                : 
                               9006         [ +  + ]:             36 :         if (indattnum == 0)
                               9007                 :                :         {
                               9008                 :             21 :             index_close(indrel, lockmode);
                               9009                 :             21 :             continue;
                               9010                 :                :         }
                               9011                 :                : 
                               9012                 :             15 :         tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
                               9013                 :                : 
                               9014         [ +  - ]:             15 :         if (HeapTupleIsValid(tuple))
                               9015                 :                :         {
 1053 tgl@sss.pgh.pa.us        9016                 :             15 :             Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
                               9017                 :                : 
                               9018         [ +  + ]:             15 :             if (setstorage)
 1122 rhaas@postgresql.org     9019                 :             12 :                 attrtuple->attstorage = newstorage;
                               9020                 :                : 
 1053 tgl@sss.pgh.pa.us        9021         [ +  + ]:             15 :             if (setcompression)
                               9022                 :              3 :                 attrtuple->attcompression = newcompression;
                               9023                 :                : 
 1122 rhaas@postgresql.org     9024                 :             15 :             CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               9025                 :                : 
                               9026         [ -  + ]:             15 :             InvokeObjectPostAlterHook(RelationRelationId,
                               9027                 :                :                                       RelationGetRelid(rel),
                               9028                 :                :                                       attrtuple->attnum);
                               9029                 :                : 
                               9030                 :             15 :             heap_freetuple(tuple);
                               9031                 :                :         }
                               9032                 :                : 
                               9033                 :             15 :         index_close(indrel, lockmode);
                               9034                 :                :     }
                               9035                 :            141 : }
                               9036                 :                : 
                               9037                 :                : /*
                               9038                 :                :  * ALTER TABLE ALTER COLUMN SET STORAGE
                               9039                 :                :  *
                               9040                 :                :  * Return value is the address of the modified column
                               9041                 :                :  */
                               9042                 :                : static ObjectAddress
 5009 simon@2ndQuadrant.co     9043                 :            117 : ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
                               9044                 :                : {
                               9045                 :                :     Relation    attrelation;
                               9046                 :                :     HeapTuple   tuple;
                               9047                 :                :     Form_pg_attribute attrtuple;
                               9048                 :                :     AttrNumber  attnum;
                               9049                 :                :     ObjectAddress address;
                               9050                 :                : 
 1910 andres@anarazel.de       9051                 :            117 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                               9052                 :                : 
 7284 tgl@sss.pgh.pa.us        9053                 :            117 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
                               9054                 :                : 
                               9055         [ +  + ]:            117 :     if (!HeapTupleIsValid(tuple))
                               9056         [ +  - ]:              6 :         ereport(ERROR,
                               9057                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                               9058                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                               9059                 :                :                         colName, RelationGetRelationName(rel))));
                               9060                 :            111 :     attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
                               9061                 :                : 
 3308 alvherre@alvh.no-ip.     9062                 :            111 :     attnum = attrtuple->attnum;
                               9063         [ -  + ]:            111 :     if (attnum <= 0)
 7284 tgl@sss.pgh.pa.us        9064         [ #  # ]:UBC           0 :         ereport(ERROR,
                               9065                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               9066                 :                :                  errmsg("cannot alter system column \"%s\"",
                               9067                 :                :                         colName)));
                               9068                 :                : 
  641 peter@eisentraut.org     9069                 :CBC         111 :     attrtuple->attstorage = GetAttributeStorage(attrtuple->atttypid, strVal(newValue));
                               9070                 :                : 
 2630 alvherre@alvh.no-ip.     9071                 :            111 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
                               9072                 :                : 
 4046 rhaas@postgresql.org     9073         [ -  + ]:            111 :     InvokeObjectPostAlterHook(RelationRelationId,
                               9074                 :                :                               RelationGetRelid(rel),
                               9075                 :                :                               attrtuple->attnum);
                               9076                 :                : 
                               9077                 :                :     /*
                               9078                 :                :      * Apply the change to indexes as well (only for simple index columns,
                               9079                 :                :      * matching behavior of index.c ConstructTupleDescriptor()).
                               9080                 :                :      */
 1122                          9081                 :            111 :     SetIndexStorageProperties(rel, attrelation, attnum,
  641 peter@eisentraut.org     9082                 :            111 :                               true, attrtuple->attstorage,
                               9083                 :                :                               false, 0,
                               9084                 :                :                               lockmode);
                               9085                 :                : 
                               9086                 :            111 :     heap_freetuple(tuple);
                               9087                 :                : 
 1910 andres@anarazel.de       9088                 :            111 :     table_close(attrelation, RowExclusiveLock);
                               9089                 :                : 
 3308 alvherre@alvh.no-ip.     9090                 :            111 :     ObjectAddressSubSet(address, RelationRelationId,
                               9091                 :                :                         RelationGetRelid(rel), attnum);
                               9092                 :            111 :     return address;
                               9093                 :                : }
                               9094                 :                : 
                               9095                 :                : 
                               9096                 :                : /*
                               9097                 :                :  * ALTER TABLE DROP COLUMN
                               9098                 :                :  *
                               9099                 :                :  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
                               9100                 :                :  * because we have to decide at runtime whether to recurse or not depending
                               9101                 :                :  * on whether attinhcount goes to zero or not.  (We can't check this in a
                               9102                 :                :  * static pre-pass because it won't handle multiple inheritance situations
                               9103                 :                :  * correctly.)
                               9104                 :                :  */
                               9105                 :                : static void
 4891 peter_e@gmx.net          9106                 :            805 : ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                               9107                 :                :                  AlterTableCmd *cmd, LOCKMODE lockmode,
                               9108                 :                :                  AlterTableUtilityContext *context)
                               9109                 :                : {
                               9110   [ +  +  +  + ]:            805 :     if (rel->rd_rel->reloftype && !recursing)
 5014                          9111         [ +  - ]:              3 :         ereport(ERROR,
                               9112                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               9113                 :                :                  errmsg("cannot drop column from typed table")));
                               9114                 :                : 
 4949                          9115         [ +  + ]:            802 :     if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
 1551 tgl@sss.pgh.pa.us        9116                 :             41 :         ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
                               9117                 :                : 
 5014 peter_e@gmx.net          9118         [ +  + ]:            799 :     if (recurse)
  489 alvherre@alvh.no-ip.     9119                 :            665 :         cmd->recurse = true;
 5014 peter_e@gmx.net          9120                 :            799 : }
                               9121                 :                : 
                               9122                 :                : /*
                               9123                 :                :  * Drops column 'colName' from relation 'rel' and returns the address of the
                               9124                 :                :  * dropped column.  The column is also dropped (or marked as no longer
                               9125                 :                :  * inherited from relation) from the relation's inheritance children, if any.
                               9126                 :                :  *
                               9127                 :                :  * In the recursive invocations for inheritance child relations, instead of
                               9128                 :                :  * dropping the column directly (if to be dropped at all), its object address
                               9129                 :                :  * is added to 'addrs', which must be non-NULL in such invocations.  All
                               9130                 :                :  * columns are dropped at the same time after all the children have been
                               9131                 :                :  * checked recursively.
                               9132                 :                :  */
                               9133                 :                : static ObjectAddress
 5541 tgl@sss.pgh.pa.us        9134                 :           1077 : ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
                               9135                 :                :                  DropBehavior behavior,
                               9136                 :                :                  bool recurse, bool recursing,
                               9137                 :                :                  bool missing_ok, LOCKMODE lockmode,
                               9138                 :                :                  ObjectAddresses *addrs)
                               9139                 :                : {
                               9140                 :                :     HeapTuple   tuple;
                               9141                 :                :     Form_pg_attribute targetatt;
                               9142                 :                :     AttrNumber  attnum;
                               9143                 :                :     List       *children;
                               9144                 :                :     ObjectAddress object;
                               9145                 :                :     bool        is_expr;
                               9146                 :                : 
                               9147                 :                :     /* At top level, permission check was done in ATPrepCmd, else do it */
 7284                          9148         [ +  + ]:           1077 :     if (recursing)
 1011 peter@eisentraut.org     9149                 :            278 :         ATSimplePermissions(AT_DropColumn, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               9150                 :                : 
                               9151                 :                :     /* Initialize addrs on the first invocation */
 1645 michael@paquier.xyz      9152   [ +  +  -  + ]:           1077 :     Assert(!recursing || addrs != NULL);
                               9153                 :                : 
                               9154                 :                :     /* since this function recurses, it could be driven to stack overflow */
   58 akorotkov@postgresql     9155                 :           1077 :     check_stack_depth();
                               9156                 :                : 
 1645 michael@paquier.xyz      9157         [ +  + ]:           1077 :     if (!recursing)
                               9158                 :            799 :         addrs = new_object_addresses();
                               9159                 :                : 
                               9160                 :                :     /*
                               9161                 :                :      * get the number of the attribute
                               9162                 :                :      */
 7284 tgl@sss.pgh.pa.us        9163                 :           1077 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
 5161 bruce@momjian.us         9164         [ +  + ]:           1077 :     if (!HeapTupleIsValid(tuple))
                               9165                 :                :     {
                               9166         [ +  + ]:             27 :         if (!missing_ok)
                               9167                 :                :         {
 5382 andrew@dunslane.net      9168         [ +  - ]:             18 :             ereport(ERROR,
                               9169                 :                :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                               9170                 :                :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
                               9171                 :                :                             colName, RelationGetRelationName(rel))));
                               9172                 :                :         }
                               9173                 :                :         else
                               9174                 :                :         {
                               9175         [ +  - ]:              9 :             ereport(NOTICE,
                               9176                 :                :                     (errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
                               9177                 :                :                             colName, RelationGetRelationName(rel))));
 3308 alvherre@alvh.no-ip.     9178                 :              9 :             return InvalidObjectAddress;
                               9179                 :                :         }
                               9180                 :                :     }
 7284 tgl@sss.pgh.pa.us        9181                 :           1050 :     targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
                               9182                 :                : 
                               9183                 :           1050 :     attnum = targetatt->attnum;
                               9184                 :                : 
                               9185                 :                :     /* Can't drop a system attribute */
 1972 andres@anarazel.de       9186         [ +  + ]:           1050 :     if (attnum <= 0)
 7284 tgl@sss.pgh.pa.us        9187         [ +  - ]:              3 :         ereport(ERROR,
                               9188                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               9189                 :                :                  errmsg("cannot drop system column \"%s\"",
                               9190                 :                :                         colName)));
                               9191                 :                : 
                               9192                 :                :     /*
                               9193                 :                :      * Don't drop inherited columns, unless recursing (presumably from a drop
                               9194                 :                :      * of the parent column)
                               9195                 :                :      */
                               9196   [ +  +  +  + ]:           1047 :     if (targetatt->attinhcount > 0 && !recursing)
                               9197         [ +  - ]:             24 :         ereport(ERROR,
                               9198                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9199                 :                :                  errmsg("cannot drop inherited column \"%s\"",
                               9200                 :                :                         colName)));
                               9201                 :                : 
                               9202                 :                :     /*
                               9203                 :                :      * Don't drop columns used in the partition key, either.  (If we let this
                               9204                 :                :      * go through, the key column's dependencies would cause a cascaded drop
                               9205                 :                :      * of the whole table, which is surely not what the user expected.)
                               9206                 :                :      */
 2292 rhaas@postgresql.org     9207         [ +  + ]:           1023 :     if (has_partition_attrs(rel,
                               9208                 :                :                             bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
                               9209                 :                :                             &is_expr))
 1728 tgl@sss.pgh.pa.us        9210         [ +  - ]:             15 :         ereport(ERROR,
                               9211                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9212                 :                :                  errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
                               9213                 :                :                         colName, RelationGetRelationName(rel))));
                               9214                 :                : 
 7284                          9215                 :           1008 :     ReleaseSysCache(tuple);
                               9216                 :                : 
                               9217                 :                :     /*
                               9218                 :                :      * Propagate to children as appropriate.  Unlike most other ALTER
                               9219                 :                :      * routines, we have to do this one level of recursion at a time; we can't
                               9220                 :                :      * use find_all_inheritors to do it in one pass.
                               9221                 :                :      */
                               9222                 :                :     children =
 1082 alvherre@alvh.no-ip.     9223                 :           1008 :         find_inheritance_children(RelationGetRelid(rel), lockmode);
                               9224                 :                : 
 7284 tgl@sss.pgh.pa.us        9225         [ +  + ]:           1008 :     if (children)
                               9226                 :                :     {
                               9227                 :                :         Relation    attr_rel;
                               9228                 :                :         ListCell   *child;
                               9229                 :                : 
                               9230                 :                :         /*
                               9231                 :                :          * In case of a partitioned table, the column must be dropped from the
                               9232                 :                :          * partitions as well.
                               9233                 :                :          */
 2685 rhaas@postgresql.org     9234   [ +  +  +  + ]:            151 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
                               9235         [ +  - ]:              3 :             ereport(ERROR,
                               9236                 :                :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9237                 :                :                      errmsg("cannot drop column from only the partitioned table when partitions exist"),
                               9238                 :                :                      errhint("Do not specify the ONLY keyword.")));
                               9239                 :                : 
 1910 andres@anarazel.de       9240                 :            148 :         attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
 7926 tgl@sss.pgh.pa.us        9241   [ +  -  +  +  :            441 :         foreach(child, children)
                                              +  + ]
                               9242                 :                :         {
 7263 neilc@samurai.com        9243                 :            296 :             Oid         childrelid = lfirst_oid(child);
                               9244                 :                :             Relation    childrel;
                               9245                 :                :             Form_pg_attribute childatt;
                               9246                 :                : 
                               9247                 :                :             /* find_inheritance_children already got lock */
 1910 andres@anarazel.de       9248                 :            296 :             childrel = table_open(childrelid, NoLock);
 5919 tgl@sss.pgh.pa.us        9249                 :            296 :             CheckTableNotInUse(childrel, "ALTER TABLE");
                               9250                 :                : 
 7875                          9251                 :            296 :             tuple = SearchSysCacheCopyAttName(childrelid, colName);
 2489                          9252         [ -  + ]:            296 :             if (!HeapTupleIsValid(tuple))   /* shouldn't happen */
 7574 tgl@sss.pgh.pa.us        9253         [ #  # ]:UBC           0 :                 elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
                               9254                 :                :                      colName, childrelid);
 7875 tgl@sss.pgh.pa.us        9255                 :CBC         296 :             childatt = (Form_pg_attribute) GETSTRUCT(tuple);
                               9256                 :                : 
 2489                          9257         [ -  + ]:            296 :             if (childatt->attinhcount <= 0) /* shouldn't happen */
 7574 tgl@sss.pgh.pa.us        9258         [ #  # ]:UBC           0 :                 elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
                               9259                 :                :                      childrelid, colName);
                               9260                 :                : 
 7284 tgl@sss.pgh.pa.us        9261         [ +  + ]:CBC         296 :             if (recurse)
                               9262                 :                :             {
                               9263                 :                :                 /*
                               9264                 :                :                  * If the child column has other definition sources, just
                               9265                 :                :                  * decrement its inheritance count; if not, recurse to delete
                               9266                 :                :                  * it.
                               9267                 :                :                  */
                               9268   [ +  -  +  + ]:            284 :                 if (childatt->attinhcount == 1 && !childatt->attislocal)
                               9269                 :                :                 {
                               9270                 :                :                     /* Time to delete this child column, too */
 5541                          9271                 :            278 :                     ATExecDropColumn(wqueue, childrel, colName,
                               9272                 :                :                                      behavior, true, true,
                               9273                 :                :                                      false, lockmode, addrs);
                               9274                 :                :                 }
                               9275                 :                :                 else
                               9276                 :                :                 {
                               9277                 :                :                     /* Child column must survive my deletion */
 7284                          9278                 :              6 :                     childatt->attinhcount--;
                               9279                 :                : 
 2630 alvherre@alvh.no-ip.     9280                 :              6 :                     CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
                               9281                 :                : 
                               9282                 :                :                     /* Make update visible */
 7284 tgl@sss.pgh.pa.us        9283                 :              6 :                     CommandCounterIncrement();
                               9284                 :                :                 }
                               9285                 :                :             }
                               9286                 :                :             else
                               9287                 :                :             {
                               9288                 :                :                 /*
                               9289                 :                :                  * If we were told to drop ONLY in this table (no recursion),
                               9290                 :                :                  * we need to mark the inheritors' attributes as locally
                               9291                 :                :                  * defined rather than inherited.
                               9292                 :                :                  */
 7875                          9293                 :             12 :                 childatt->attinhcount--;
 7284                          9294                 :             12 :                 childatt->attislocal = true;
                               9295                 :                : 
 2630 alvherre@alvh.no-ip.     9296                 :             12 :                 CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
                               9297                 :                : 
                               9298                 :                :                 /* Make update visible */
 7284 tgl@sss.pgh.pa.us        9299                 :             12 :                 CommandCounterIncrement();
                               9300                 :                :             }
                               9301                 :                : 
 7875                          9302                 :            293 :             heap_freetuple(tuple);
                               9303                 :                : 
 1910 andres@anarazel.de       9304                 :            293 :             table_close(childrel, NoLock);
                               9305                 :                :         }
                               9306                 :            145 :         table_close(attr_rel, RowExclusiveLock);
                               9307                 :                :     }
                               9308                 :                : 
                               9309                 :                :     /* Add object to delete */
 6940 tgl@sss.pgh.pa.us        9310                 :           1002 :     object.classId = RelationRelationId;
 7284                          9311                 :           1002 :     object.objectId = RelationGetRelid(rel);
 7926                          9312                 :           1002 :     object.objectSubId = attnum;
 1645 michael@paquier.xyz      9313                 :           1002 :     add_exact_object_address(&object, addrs);
                               9314                 :                : 
                               9315         [ +  + ]:           1002 :     if (!recursing)
                               9316                 :                :     {
                               9317                 :                :         /* Recursion has ended, drop everything that was collected */
                               9318                 :            727 :         performMultipleDeletions(addrs, behavior, 0);
                               9319                 :            703 :         free_object_addresses(addrs);
                               9320                 :                :     }
                               9321                 :                : 
  233 alvherre@alvh.no-ip.     9322                 :            978 :     return object;
                               9323                 :                : }
                               9324                 :                : 
                               9325                 :                : /*
                               9326                 :                :  * Prepare to add a primary key on an inheritance parent, by adding NOT NULL
                               9327                 :                :  * constraint on its children.
                               9328                 :                :  */
                               9329                 :                : static void
  233 alvherre@alvh.no-ip.     9330                 :GNC        4616 : ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd,
                               9331                 :                :                     LOCKMODE lockmode, AlterTableUtilityContext *context)
                               9332                 :                : {
                               9333                 :                :     List       *children;
                               9334                 :           4616 :     List       *newconstrs = NIL;
                               9335                 :                :     ListCell   *lc;
                               9336                 :                :     IndexStmt  *indexstmt;
                               9337                 :                : 
                               9338                 :                :     /* No work if not creating a primary key */
  226                          9339         [ -  + ]:           4616 :     if (!IsA(cmd->def, IndexStmt))
  226 alvherre@alvh.no-ip.     9340                 :UNC           0 :         return;
  226 alvherre@alvh.no-ip.     9341                 :GNC        4616 :     indexstmt = castNode(IndexStmt, cmd->def);
                               9342         [ +  + ]:           4616 :     if (!indexstmt->primary)
                               9343                 :           1944 :         return;
                               9344                 :                : 
                               9345                 :                :     /* No work if no legacy inheritance children are present */
  233                          9346         [ +  + ]:           2672 :     if (rel->rd_rel->relkind != RELKIND_RELATION ||
                               9347         [ +  + ]:           2606 :         !rel->rd_rel->relhassubclass)
                               9348                 :           2652 :         return;
                               9349                 :                : 
                               9350                 :             20 :     children = find_inheritance_children(RelationGetRelid(rel), lockmode);
                               9351                 :                : 
  226                          9352   [ +  -  +  +  :             40 :     foreach(lc, indexstmt->indexParams)
                                              +  + ]
                               9353                 :                :     {
  233                          9354                 :             20 :         IndexElem  *elem = lfirst_node(IndexElem, lc);
                               9355                 :                :         Constraint *nnconstr;
                               9356                 :                : 
                               9357         [ -  + ]:             20 :         Assert(elem->expr == NULL);
                               9358                 :                : 
                               9359                 :             20 :         nnconstr = makeNode(Constraint);
                               9360                 :             20 :         nnconstr->contype = CONSTR_NOTNULL;
                               9361                 :             20 :         nnconstr->conname = NULL;    /* XXX use PK name? */
                               9362                 :             20 :         nnconstr->inhcount = 1;
                               9363                 :             20 :         nnconstr->deferrable = false;
                               9364                 :             20 :         nnconstr->initdeferred = false;
                               9365                 :             20 :         nnconstr->location = -1;
                               9366                 :             20 :         nnconstr->keys = list_make1(makeString(elem->name));
                               9367                 :             20 :         nnconstr->skip_validation = false;
                               9368                 :             20 :         nnconstr->initially_valid = true;
                               9369                 :                : 
                               9370                 :             20 :         newconstrs = lappend(newconstrs, nnconstr);
                               9371                 :                :     }
                               9372                 :                : 
                               9373   [ +  -  +  +  :             60 :     foreach(lc, children)
                                              +  + ]
                               9374                 :                :     {
                               9375                 :             40 :         Oid         childrelid = lfirst_oid(lc);
                               9376                 :             40 :         Relation    childrel = table_open(childrelid, NoLock);
                               9377                 :             40 :         AlterTableCmd *newcmd = makeNode(AlterTableCmd);
                               9378                 :                :         ListCell   *lc2;
                               9379                 :                : 
                               9380                 :             40 :         newcmd->subtype = AT_AddConstraint;
                               9381                 :             40 :         newcmd->recurse = true;
                               9382                 :                : 
                               9383   [ +  -  +  +  :             80 :         foreach(lc2, newconstrs)
                                              +  + ]
                               9384                 :                :         {
                               9385                 :                :             /* ATPrepCmd copies newcmd, so we can scribble on it here */
                               9386                 :             40 :             newcmd->def = lfirst(lc2);
                               9387                 :                : 
                               9388                 :             40 :             ATPrepCmd(wqueue, childrel, newcmd,
                               9389                 :                :                       true, false, lockmode, context);
                               9390                 :                :         }
                               9391                 :                : 
                               9392                 :             40 :         table_close(childrel, NoLock);
                               9393                 :                :     }
                               9394                 :                : }
                               9395                 :                : 
                               9396                 :                : /*
                               9397                 :                :  * ALTER TABLE ADD INDEX
                               9398                 :                :  *
                               9399                 :                :  * There is no such command in the grammar, but parse_utilcmd.c converts
                               9400                 :                :  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands.  This lets
                               9401                 :                :  * us schedule creation of the index at the appropriate time during ALTER.
                               9402                 :                :  *
                               9403                 :                :  * Return value is the address of the new index.
                               9404                 :                :  */
                               9405                 :                : static ObjectAddress
 7284 tgl@sss.pgh.pa.us        9406                 :CBC         717 : ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
                               9407                 :                :                IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
                               9408                 :                : {
                               9409                 :                :     bool        check_rights;
                               9410                 :                :     bool        skip_build;
                               9411                 :                :     bool        quiet;
                               9412                 :                :     ObjectAddress address;
                               9413                 :                : 
                               9414         [ -  + ]:            717 :     Assert(IsA(stmt, IndexStmt));
 4290                          9415         [ -  + ]:            717 :     Assert(!stmt->concurrent);
                               9416                 :                : 
                               9417                 :                :     /* The IndexStmt has already been through transformIndexStmt */
 3339                          9418         [ -  + ]:            717 :     Assert(stmt->transformed);
                               9419                 :                : 
                               9420                 :                :     /* suppress schema rights check when rebuilding existing index */
 7284                          9421                 :            717 :     check_rights = !is_rebuild;
                               9422                 :                :     /* skip index build if phase 3 will do it or we're reusing an old one */
  648 rhaas@postgresql.org     9423   [ +  +  +  + ]:            717 :     skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
                               9424                 :                :     /* suppress notices when rebuilding existing index */
 7284 tgl@sss.pgh.pa.us        9425                 :            717 :     quiet = is_rebuild;
                               9426                 :                : 
 3330 alvherre@alvh.no-ip.     9427                 :            717 :     address = DefineIndex(RelationGetRelid(rel),
                               9428                 :                :                           stmt,
                               9429                 :                :                           InvalidOid,   /* no predefined OID */
                               9430                 :                :                           InvalidOid,   /* no parent index */
                               9431                 :                :                           InvalidOid,   /* no parent constraint */
                               9432                 :                :                           -1,   /* total_parts unknown */
                               9433                 :                :                           true, /* is_alter_table */
                               9434                 :                :                           check_rights,
                               9435                 :                :                           false,    /* check_not_in_use - we did it already */
                               9436                 :                :                           skip_build,
                               9437                 :                :                           quiet);
                               9438                 :                : 
                               9439                 :                :     /*
                               9440                 :                :      * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
                               9441                 :                :      * new index instead of building from scratch.  Restore associated fields.
                               9442                 :                :      * This may store InvalidSubTransactionId in both fields, in which case
                               9443                 :                :      * relcache.c will assume it can rebuild the relcache entry.  Hence, do
                               9444                 :                :      * this after the CCI that made catalog rows visible to any rebuild.  The
                               9445                 :                :      * DROP of the old edition of this index will have scheduled the storage
                               9446                 :                :      * for deletion at commit, so cancel that pending deletion.
                               9447                 :                :      */
  648 rhaas@postgresql.org     9448         [ +  + ]:            653 :     if (RelFileNumberIsValid(stmt->oldNumber))
                               9449                 :                :     {
 3330 alvherre@alvh.no-ip.     9450                 :             36 :         Relation    irel = index_open(address.objectId, NoLock);
                               9451                 :                : 
 1471 noah@leadboat.com        9452                 :             36 :         irel->rd_createSubid = stmt->oldCreateSubid;
  648 rhaas@postgresql.org     9453                 :             36 :         irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
                               9454                 :             36 :         RelationPreserveStorage(irel->rd_locator, true);
 4654                          9455                 :             36 :         index_close(irel, NoLock);
                               9456                 :                :     }
                               9457                 :                : 
 3308 alvherre@alvh.no-ip.     9458                 :            653 :     return address;
                               9459                 :                : }
                               9460                 :                : 
                               9461                 :                : /*
                               9462                 :                :  * ALTER TABLE ADD STATISTICS
                               9463                 :                :  *
                               9464                 :                :  * This is no such command in the grammar, but we use this internally to add
                               9465                 :                :  * AT_ReAddStatistics subcommands to rebuild extended statistics after a table
                               9466                 :                :  * column type change.
                               9467                 :                :  */
                               9468                 :                : static ObjectAddress
 1115 tomas.vondra@postgre     9469                 :              7 : ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
                               9470                 :                :                     CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
                               9471                 :                : {
                               9472                 :                :     ObjectAddress address;
                               9473                 :                : 
                               9474         [ -  + ]:              7 :     Assert(IsA(stmt, CreateStatsStmt));
                               9475                 :                : 
                               9476                 :                :     /* The CreateStatsStmt has already been through transformStatsStmt */
                               9477         [ -  + ]:              7 :     Assert(stmt->transformed);
                               9478                 :                : 
                               9479                 :              7 :     address = CreateStatistics(stmt);
                               9480                 :                : 
                               9481                 :              7 :     return address;
                               9482                 :                : }
                               9483                 :                : 
                               9484                 :                : /*
                               9485                 :                :  * ALTER TABLE ADD CONSTRAINT USING INDEX
                               9486                 :                :  *
                               9487                 :                :  * Returns the address of the new constraint.
                               9488                 :                :  */
                               9489                 :                : static ObjectAddress
 4828 tgl@sss.pgh.pa.us        9490                 :           4107 : ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
                               9491                 :                :                          IndexStmt *stmt, LOCKMODE lockmode)
                               9492                 :                : {
                               9493                 :           4107 :     Oid         index_oid = stmt->indexOid;
                               9494                 :                :     Relation    indexRel;
                               9495                 :                :     char       *indexName;
                               9496                 :                :     IndexInfo  *indexInfo;
                               9497                 :                :     char       *constraintName;
                               9498                 :                :     char        constraintType;
                               9499                 :                :     ObjectAddress address;
                               9500                 :                :     bits16      flags;
                               9501                 :                : 
                               9502         [ -  + ]:           4107 :     Assert(IsA(stmt, IndexStmt));
                               9503         [ -  + ]:           4107 :     Assert(OidIsValid(index_oid));
                               9504         [ -  + ]:           4107 :     Assert(stmt->isconstraint);
                               9505                 :                : 
                               9506                 :                :     /*
                               9507                 :                :      * Doing this on partitioned tables is not a simple feature to implement,
                               9508                 :                :      * so let's punt for now.
                               9509                 :                :      */
 2246 alvherre@alvh.no-ip.     9510         [ +  + ]:           4107 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               9511         [ +  - ]:              3 :         ereport(ERROR,
                               9512                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               9513                 :                :                  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
                               9514                 :                : 
 4828 tgl@sss.pgh.pa.us        9515                 :           4104 :     indexRel = index_open(index_oid, AccessShareLock);
                               9516                 :                : 
                               9517                 :           4104 :     indexName = pstrdup(RelationGetRelationName(indexRel));
                               9518                 :                : 
                               9519                 :           4104 :     indexInfo = BuildIndexInfo(indexRel);
                               9520                 :                : 
                               9521                 :                :     /* this should have been checked at parse time */
                               9522         [ -  + ]:           4104 :     if (!indexInfo->ii_Unique)
 4828 tgl@sss.pgh.pa.us        9523         [ #  # ]:UBC           0 :         elog(ERROR, "index \"%s\" is not unique", indexName);
                               9524                 :                : 
                               9525                 :                :     /*
                               9526                 :                :      * Determine name to assign to constraint.  We require a constraint to
                               9527                 :                :      * have the same name as the underlying index; therefore, use the index's
                               9528                 :                :      * existing name as the default constraint name, and if the user
                               9529                 :                :      * explicitly gives some other name for the constraint, rename the index
                               9530                 :                :      * to match.
                               9531                 :                :      */
 4828 tgl@sss.pgh.pa.us        9532                 :CBC        4104 :     constraintName = stmt->idxname;
                               9533         [ +  + ]:           4104 :     if (constraintName == NULL)
                               9534                 :           4094 :         constraintName = indexName;
                               9535         [ +  + ]:             10 :     else if (strcmp(constraintName, indexName) != 0)
                               9536                 :                :     {
                               9537         [ +  - ]:              7 :         ereport(NOTICE,
                               9538                 :                :                 (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
                               9539                 :                :                         indexName, constraintName)));
 1998 peter_e@gmx.net          9540                 :              7 :         RenameRelationInternal(index_oid, constraintName, false, true);
                               9541                 :                :     }
                               9542                 :                : 
                               9543                 :                :     /* Extra checks needed if making primary key */
 4828 tgl@sss.pgh.pa.us        9544         [ +  + ]:           4104 :     if (stmt->primary)
 2017 alvherre@alvh.no-ip.     9545                 :           2321 :         index_check_primary_key(rel, indexInfo, true, stmt);
                               9546                 :                : 
                               9547                 :                :     /* Note we currently don't support EXCLUSION constraints here */
 4828 tgl@sss.pgh.pa.us        9548         [ +  + ]:           4101 :     if (stmt->primary)
                               9549                 :           2318 :         constraintType = CONSTRAINT_PRIMARY;
                               9550                 :                :     else
                               9551                 :           1783 :         constraintType = CONSTRAINT_UNIQUE;
                               9552                 :                : 
                               9553                 :                :     /* Create the catalog entries for the constraint */
 2343 alvherre@alvh.no-ip.     9554                 :           4101 :     flags = INDEX_CONSTR_CREATE_UPDATE_INDEX |
                               9555                 :                :         INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS |
                               9556         [ -  + ]:           8202 :         (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
                               9557         [ -  + ]:           4101 :         (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
                               9558                 :           4101 :         (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
                               9559                 :                : 
 3308                          9560                 :           4101 :     address = index_constraint_create(rel,
                               9561                 :                :                                       index_oid,
                               9562                 :                :                                       InvalidOid,
                               9563                 :                :                                       indexInfo,
                               9564                 :                :                                       constraintName,
                               9565                 :                :                                       constraintType,
                               9566                 :                :                                       flags,
                               9567                 :                :                                       allowSystemTableMods,
                               9568                 :                :                                       false);   /* is_internal */
                               9569                 :                : 
 4828 tgl@sss.pgh.pa.us        9570                 :           4101 :     index_close(indexRel, NoLock);
                               9571                 :                : 
 3308 alvherre@alvh.no-ip.     9572                 :           4101 :     return address;
                               9573                 :                : }
                               9574                 :                : 
                               9575                 :                : /*
                               9576                 :                :  * ALTER TABLE ADD CONSTRAINT
                               9577                 :                :  *
                               9578                 :                :  * Return value is the address of the new constraint; if no constraint was
                               9579                 :                :  * added, InvalidObjectAddress is returned.
                               9580                 :                :  */
                               9581                 :                : static ObjectAddress
 5819 tgl@sss.pgh.pa.us        9582                 :           1920 : ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
                               9583                 :                :                     Constraint *newConstraint, bool recurse, bool is_readd,
                               9584                 :                :                     LOCKMODE lockmode)
                               9585                 :                : {
 3308 alvherre@alvh.no-ip.     9586                 :           1920 :     ObjectAddress address = InvalidObjectAddress;
                               9587                 :                : 
 5372 tgl@sss.pgh.pa.us        9588         [ -  + ]:           1920 :     Assert(IsA(newConstraint, Constraint));
                               9589                 :                : 
                               9590                 :                :     /*
                               9591                 :                :      * Currently, we only expect to see CONSTR_CHECK, CONSTR_NOTNULL and
                               9592                 :                :      * CONSTR_FOREIGN nodes arriving here (see the preprocessing done in
                               9593                 :                :      * parse_utilcmd.c).
                               9594                 :                :      */
                               9595      [ +  +  - ]:           1920 :     switch (newConstraint->contype)
                               9596                 :                :     {
                               9597                 :            688 :         case CONSTR_CHECK:
                               9598                 :                :         case CONSTR_NOTNULL:
                               9599                 :                :             address =
  233 alvherre@alvh.no-ip.     9600                 :GNC         688 :                 ATAddCheckNNConstraint(wqueue, tab, rel,
                               9601                 :                :                                        newConstraint, recurse, false, is_readd,
                               9602                 :                :                                        lockmode);
 5372 tgl@sss.pgh.pa.us        9603                 :CBC         649 :             break;
                               9604                 :                : 
                               9605                 :           1232 :         case CONSTR_FOREIGN:
                               9606                 :                : 
                               9607                 :                :             /*
                               9608                 :                :              * Assign or validate constraint name
                               9609                 :                :              */
                               9610         [ +  + ]:           1232 :             if (newConstraint->conname)
                               9611                 :                :             {
                               9612         [ -  + ]:            574 :                 if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
                               9613                 :                :                                          RelationGetRelid(rel),
                               9614                 :            574 :                                          newConstraint->conname))
 5372 tgl@sss.pgh.pa.us        9615         [ #  # ]:UBC           0 :                     ereport(ERROR,
                               9616                 :                :                             (errcode(ERRCODE_DUPLICATE_OBJECT),
                               9617                 :                :                              errmsg("constraint \"%s\" for relation \"%s\" already exists",
                               9618                 :                :                                     newConstraint->conname,
                               9619                 :                :                                     RelationGetRelationName(rel))));
                               9620                 :                :             }
                               9621                 :                :             else
 5372 tgl@sss.pgh.pa.us        9622                 :CBC         658 :                 newConstraint->conname =
                               9623                 :            658 :                     ChooseConstraintName(RelationGetRelationName(rel),
 1859 peter@eisentraut.org     9624                 :            658 :                                          ChooseForeignKeyConstraintNameAddition(newConstraint->fk_attrs),
                               9625                 :                :                                          "fkey",
 5372 tgl@sss.pgh.pa.us        9626                 :            658 :                                          RelationGetNamespace(rel),
                               9627                 :                :                                          NIL);
                               9628                 :                : 
 2202 alvherre@alvh.no-ip.     9629                 :           1232 :             address = ATAddForeignKeyConstraint(wqueue, tab, rel,
                               9630                 :                :                                                 newConstraint,
                               9631                 :                :                                                 recurse, false,
                               9632                 :                :                                                 lockmode);
 5372 tgl@sss.pgh.pa.us        9633                 :            988 :             break;
                               9634                 :                : 
 7284 tgl@sss.pgh.pa.us        9635                 :UBC           0 :         default:
 5372                          9636         [ #  # ]:              0 :             elog(ERROR, "unrecognized constraint type: %d",
                               9637                 :                :                  (int) newConstraint->contype);
                               9638                 :                :     }
                               9639                 :                : 
 3308 alvherre@alvh.no-ip.     9640                 :CBC        1637 :     return address;
                               9641                 :                : }
                               9642                 :                : 
                               9643                 :                : /*
                               9644                 :                :  * Generate the column-name portion of the constraint name for a new foreign
                               9645                 :                :  * key given the list of column names that reference the referenced
                               9646                 :                :  * table.  This will be passed to ChooseConstraintName along with the parent
                               9647                 :                :  * table name and the "fkey" suffix.
                               9648                 :                :  *
                               9649                 :                :  * We know that less than NAMEDATALEN characters will actually be used, so we
                               9650                 :                :  * can truncate the result once we've generated that many.
                               9651                 :                :  *
                               9652                 :                :  * XXX see also ChooseExtendedStatisticNameAddition and
                               9653                 :                :  * ChooseIndexNameAddition.
                               9654                 :                :  */
                               9655                 :                : static char *
 1859 peter@eisentraut.org     9656                 :           1021 : ChooseForeignKeyConstraintNameAddition(List *colnames)
                               9657                 :                : {
                               9658                 :                :     char        buf[NAMEDATALEN * 2];
                               9659                 :           1021 :     int         buflen = 0;
                               9660                 :                :     ListCell   *lc;
                               9661                 :                : 
                               9662                 :           1021 :     buf[0] = '\0';
                               9663   [ +  -  +  +  :           2253 :     foreach(lc, colnames)
                                              +  + ]
                               9664                 :                :     {
                               9665                 :           1232 :         const char *name = strVal(lfirst(lc));
                               9666                 :                : 
                               9667         [ +  + ]:           1232 :         if (buflen > 0)
                               9668                 :            211 :             buf[buflen++] = '_';    /* insert _ between names */
                               9669                 :                : 
                               9670                 :                :         /*
                               9671                 :                :          * At this point we have buflen <= NAMEDATALEN.  name should be less
                               9672                 :                :          * than NAMEDATALEN already, but use strlcpy for paranoia.
                               9673                 :                :          */
                               9674                 :           1232 :         strlcpy(buf + buflen, name, NAMEDATALEN);
                               9675                 :           1232 :         buflen += strlen(buf + buflen);
                               9676         [ -  + ]:           1232 :         if (buflen >= NAMEDATALEN)
 1859 peter@eisentraut.org     9677                 :UBC           0 :             break;
                               9678                 :                :     }
 1859 peter@eisentraut.org     9679                 :CBC        1021 :     return pstrdup(buf);
                               9680                 :                : }
                               9681                 :                : 
                               9682                 :                : /*
                               9683                 :                :  * Add a check or not-null constraint to a single table and its children.
                               9684                 :                :  * Returns the address of the constraint added to the parent relation,
                               9685                 :                :  * if one gets added, or InvalidObjectAddress otherwise.
                               9686                 :                :  *
                               9687                 :                :  * Subroutine for ATExecAddConstraint.
                               9688                 :                :  *
                               9689                 :                :  * We must recurse to child tables during execution, rather than using
                               9690                 :                :  * ALTER TABLE's normal prep-time recursion.  The reason is that all the
                               9691                 :                :  * constraints *must* be given the same name, else they won't be seen as
                               9692                 :                :  * related later.  If the user didn't explicitly specify a name, then
                               9693                 :                :  * AddRelationNewConstraints would normally assign different names to the
                               9694                 :                :  * child constraints.  To fix that, we must capture the name assigned at
                               9695                 :                :  * the parent table and pass that down.
                               9696                 :                :  */
                               9697                 :                : static ObjectAddress
  233 alvherre@alvh.no-ip.     9698                 :GNC         992 : ATAddCheckNNConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
                               9699                 :                :                        Constraint *constr, bool recurse, bool recursing,
                               9700                 :                :                        bool is_readd, LOCKMODE lockmode)
                               9701                 :                : {
                               9702                 :                :     List       *newcons;
                               9703                 :                :     ListCell   *lcon;
                               9704                 :                :     List       *children;
                               9705                 :                :     ListCell   *child;
 3308 alvherre@alvh.no-ip.     9706                 :CBC         992 :     ObjectAddress address = InvalidObjectAddress;
                               9707                 :                : 
                               9708                 :                :     /* Guard against stack overflow due to overly deep inheritance tree. */
  158 alvherre@alvh.no-ip.     9709                 :GNC         992 :     check_stack_depth();
                               9710                 :                : 
                               9711                 :                :     /* At top level, permission check was done in ATPrepCmd, else do it */
 5819 tgl@sss.pgh.pa.us        9712         [ +  + ]:CBC         992 :     if (recursing)
 1011 peter@eisentraut.org     9713                 :            237 :         ATSimplePermissions(AT_AddConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                               9714                 :                : 
                               9715                 :                :     /*
                               9716                 :                :      * Call AddRelationNewConstraints to do the work, making sure it works on
                               9717                 :                :      * a copy of the Constraint so transformExpr can't modify the original. It
                               9718                 :                :      * returns a list of cooked constraints.
                               9719                 :                :      *
                               9720                 :                :      * If the constraint ends up getting merged with a pre-existing one, it's
                               9721                 :                :      * omitted from the returned list, which is what we want: we do not need
                               9722                 :                :      * to do any validation work.  That can only happen at child tables,
                               9723                 :                :      * though, since we disallow merging at the top level.
                               9724                 :                :      */
 5819 tgl@sss.pgh.pa.us        9725                 :            992 :     newcons = AddRelationNewConstraints(rel, NIL,
                               9726                 :            992 :                                         list_make1(copyObject(constr)),
  479 michael@paquier.xyz      9727         [ +  + ]:            992 :                                         recursing || is_readd,  /* allow_merge */
 2489 tgl@sss.pgh.pa.us        9728                 :GIC         992 :                                         !recursing, /* is_local */
                               9729                 :                :                                         is_readd,   /* is_internal */
 2052 tgl@sss.pgh.pa.us        9730         [ +  + ]:CBC         992 :                                         NULL);  /* queryString not available
                               9731                 :                :                                                  * here */
                               9732                 :                : 
                               9733                 :                :     /* we don't expect more than one constraint here */
 3308 alvherre@alvh.no-ip.     9734         [ -  + ]:            956 :     Assert(list_length(newcons) <= 1);
                               9735                 :                : 
                               9736                 :                :     /* Add each to-be-validated constraint to Phase 3's queue */
 5819 tgl@sss.pgh.pa.us        9737   [ +  +  +  +  :           1852 :     foreach(lcon, newcons)
                                              +  + ]
                               9738                 :                :     {
                               9739                 :            896 :         CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
                               9740                 :                : 
  233 alvherre@alvh.no-ip.     9741   [ +  +  +  + ]:GNC         896 :         if (!ccon->skip_validation && ccon->contype != CONSTR_NOTNULL)
                               9742                 :                :         {
                               9743                 :                :             NewConstraint *newcon;
                               9744                 :                : 
 4701 alvherre@alvh.no-ip.     9745                 :CBC         398 :             newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
                               9746                 :            398 :             newcon->name = ccon->name;
                               9747                 :            398 :             newcon->contype = ccon->contype;
 2588 andres@anarazel.de       9748                 :            398 :             newcon->qual = ccon->expr;
                               9749                 :                : 
 4701 alvherre@alvh.no-ip.     9750                 :            398 :             tab->constraints = lappend(tab->constraints, newcon);
                               9751                 :                :         }
                               9752                 :                : 
                               9753                 :                :         /* Save the actually assigned name if it was defaulted */
 5372 tgl@sss.pgh.pa.us        9754         [ +  + ]:            896 :         if (constr->conname == NULL)
                               9755                 :            274 :             constr->conname = ccon->name;
                               9756                 :                : 
                               9757                 :                :         /*
                               9758                 :                :          * If adding a not-null constraint, set the pg_attribute flag and tell
                               9759                 :                :          * phase 3 to verify existing rows, if needed.
                               9760                 :                :          */
  233 alvherre@alvh.no-ip.     9761         [ +  + ]:GNC         896 :         if (constr->contype == CONSTR_NOTNULL)
                               9762                 :            301 :             set_attnotnull(wqueue, rel, ccon->attnum,
                               9763                 :            301 :                            !ccon->is_no_inherit, lockmode);
                               9764                 :                : 
 3308 alvherre@alvh.no-ip.     9765                 :CBC         896 :         ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
                               9766                 :                :     }
                               9767                 :                : 
                               9768                 :                :     /* At this point we must have a locked-down name to use */
  233 alvherre@alvh.no-ip.     9769   [ +  +  -  + ]:GNC         956 :     Assert(newcons == NIL || constr->conname != NULL);
                               9770                 :                : 
                               9771                 :                :     /* Advance command counter in case same table is visited multiple times */
 5819 tgl@sss.pgh.pa.us        9772                 :CBC         956 :     CommandCounterIncrement();
                               9773                 :                : 
                               9774                 :                :     /*
                               9775                 :                :      * If the constraint got merged with an existing constraint, we're done.
                               9776                 :                :      * We mustn't recurse to child tables in this case, because they've
                               9777                 :                :      * already got the constraint, and visiting them again would lead to an
                               9778                 :                :      * incorrect value for coninhcount.
                               9779                 :                :      */
 5003 rhaas@postgresql.org     9780         [ +  + ]:            956 :     if (newcons == NIL)
 3308 alvherre@alvh.no-ip.     9781                 :             60 :         return address;
                               9782                 :                : 
                               9783                 :                :     /*
                               9784                 :                :      * If adding a NO INHERIT constraint, no need to find our children.
                               9785                 :                :      */
 3068 tgl@sss.pgh.pa.us        9786         [ +  + ]:            896 :     if (constr->is_no_inherit)
 3308 alvherre@alvh.no-ip.     9787                 :             36 :         return address;
                               9788                 :                : 
                               9789                 :                :     /*
                               9790                 :                :      * Propagate to children as appropriate.  Unlike most other ALTER
                               9791                 :                :      * routines, we have to do this one level of recursion at a time; we can't
                               9792                 :                :      * use find_all_inheritors to do it in one pass.
                               9793                 :                :      */
                               9794                 :                :     children =
 1082                          9795                 :            860 :         find_inheritance_children(RelationGetRelid(rel), lockmode);
                               9796                 :                : 
                               9797                 :                :     /*
                               9798                 :                :      * Check if ONLY was specified with ALTER TABLE.  If so, allow the
                               9799                 :                :      * constraint creation only if there are no children currently.  Error out
                               9800                 :                :      * otherwise.
                               9801                 :                :      */
 4377                          9802   [ +  +  +  + ]:            860 :     if (!recurse && children != NIL)
                               9803         [ +  - ]:              3 :         ereport(ERROR,
                               9804                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9805                 :                :                  errmsg("constraint must be added to child tables too")));
                               9806                 :                : 
                               9807                 :                :     /*
                               9808                 :                :      * The constraint must appear as inherited in children, so create a
                               9809                 :                :      * modified constraint object to use.
                               9810                 :                :      */
  233 alvherre@alvh.no-ip.     9811                 :GNC         857 :     constr = copyObject(constr);
                               9812                 :            857 :     constr->inhcount = 1;
 5819 tgl@sss.pgh.pa.us        9813   [ +  +  +  +  :CBC        1091 :     foreach(child, children)
                                              +  + ]
                               9814                 :                :     {
                               9815                 :            237 :         Oid         childrelid = lfirst_oid(child);
                               9816                 :                :         Relation    childrel;
                               9817                 :                :         AlteredTableInfo *childtab;
                               9818                 :                : 
                               9819                 :                :         /* find_inheritance_children already got lock */
 1910 andres@anarazel.de       9820                 :            237 :         childrel = table_open(childrelid, NoLock);
 5819 tgl@sss.pgh.pa.us        9821                 :            237 :         CheckTableNotInUse(childrel, "ALTER TABLE");
                               9822                 :                : 
                               9823                 :                :         /* Find or create work queue entry for this table */
                               9824                 :            237 :         childtab = ATGetQueueEntry(wqueue, childrel);
                               9825                 :                : 
                               9826                 :                :         /*
                               9827                 :                :          * Recurse to child.  XXX if we didn't create a constraint on the
                               9828                 :                :          * parent because it already existed, and we do create one on a child,
                               9829                 :                :          * should we return that child's constraint ObjectAddress here?
                               9830                 :                :          */
  233 alvherre@alvh.no-ip.     9831                 :GNC         237 :         ATAddCheckNNConstraint(wqueue, childtab, childrel,
                               9832                 :                :                                constr, recurse, true, is_readd, lockmode);
                               9833                 :                : 
 1910 andres@anarazel.de       9834                 :CBC         234 :         table_close(childrel, NoLock);
                               9835                 :                :     }
                               9836                 :                : 
 3308 alvherre@alvh.no-ip.     9837                 :            854 :     return address;
                               9838                 :                : }
                               9839                 :                : 
                               9840                 :                : /*
                               9841                 :                :  * Add a foreign-key constraint to a single table; return the new constraint's
                               9842                 :                :  * address.
                               9843                 :                :  *
                               9844                 :                :  * Subroutine for ATExecAddConstraint.  Must already hold exclusive
                               9845                 :                :  * lock on the rel, and have done appropriate validity checks for it.
                               9846                 :                :  * We do permissions checks here, however.
                               9847                 :                :  *
                               9848                 :                :  * When the referenced or referencing tables (or both) are partitioned,
                               9849                 :                :  * multiple pg_constraint rows are required -- one for each partitioned table
                               9850                 :                :  * and each partition on each side (fortunately, not one for every combination
                               9851                 :                :  * thereof).  We also need action triggers on each leaf partition on the
                               9852                 :                :  * referenced side, and check triggers on each leaf partition on the
                               9853                 :                :  * referencing side.
                               9854                 :                :  */
                               9855                 :                : static ObjectAddress
 2202                          9856                 :           1232 : ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
                               9857                 :                :                           Constraint *fkconstraint,
                               9858                 :                :                           bool recurse, bool recursing, LOCKMODE lockmode)
                               9859                 :                : {
                               9860                 :                :     Relation    pkrel;
  638 peter@eisentraut.org     9861                 :           1232 :     int16       pkattnum[INDEX_MAX_KEYS] = {0};
                               9862                 :           1232 :     int16       fkattnum[INDEX_MAX_KEYS] = {0};
                               9863                 :           1232 :     Oid         pktypoid[INDEX_MAX_KEYS] = {0};
                               9864                 :           1232 :     Oid         fktypoid[INDEX_MAX_KEYS] = {0};
                               9865                 :           1232 :     Oid         opclasses[INDEX_MAX_KEYS] = {0};
                               9866                 :           1232 :     Oid         pfeqoperators[INDEX_MAX_KEYS] = {0};
                               9867                 :           1232 :     Oid         ppeqoperators[INDEX_MAX_KEYS] = {0};
                               9868                 :           1232 :     Oid         ffeqoperators[INDEX_MAX_KEYS] = {0};
                               9869                 :           1232 :     int16       fkdelsetcols[INDEX_MAX_KEYS] = {0};
                               9870                 :                :     bool        with_period;
                               9871                 :                :     bool        pk_has_without_overlaps;
                               9872                 :                :     int         i;
                               9873                 :                :     int         numfks,
                               9874                 :                :                 numpks,
                               9875                 :                :                 numfkdelsetcols;
                               9876                 :                :     Oid         indexOid;
                               9877                 :                :     bool        old_check_ok;
                               9878                 :                :     ObjectAddress address;
 4430 alvherre@alvh.no-ip.     9879                 :           1232 :     ListCell   *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
                               9880                 :                : 
                               9881                 :                :     /*
                               9882                 :                :      * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
                               9883                 :                :      * delete rows out from under us.
                               9884                 :                :      */
 3709 rhaas@postgresql.org     9885         [ +  + ]:           1232 :     if (OidIsValid(fkconstraint->old_pktable_oid))
 1910 andres@anarazel.de       9886                 :             36 :         pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
                               9887                 :                :     else
                               9888                 :           1196 :         pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
                               9889                 :                : 
                               9890                 :                :     /*
                               9891                 :                :      * Validity checks (permission checks wait till we have the column
                               9892                 :                :      * numbers)
                               9893                 :                :      */
 2202 alvherre@alvh.no-ip.     9894         [ +  + ]:           1232 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               9895                 :                :     {
                               9896         [ +  + ]:            165 :         if (!recurse)
                               9897         [ +  - ]:              3 :             ereport(ERROR,
                               9898                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               9899                 :                :                      errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
                               9900                 :                :                             RelationGetRelationName(rel),
                               9901                 :                :                             RelationGetRelationName(pkrel))));
                               9902   [ +  +  +  + ]:            162 :         if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
                               9903         [ +  - ]:              3 :             ereport(ERROR,
                               9904                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               9905                 :                :                      errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
                               9906                 :                :                             RelationGetRelationName(rel),
                               9907                 :                :                             RelationGetRelationName(pkrel)),
                               9908                 :                :                      errdetail("This feature is not yet supported on partitioned tables.")));
                               9909                 :                :     }
                               9910                 :                : 
 1838                          9911         [ +  + ]:           1226 :     if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
                               9912         [ -  + ]:            148 :         pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 7284 tgl@sss.pgh.pa.us        9913         [ #  # ]:UBC           0 :         ereport(ERROR,
                               9914                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                               9915                 :                :                  errmsg("referenced relation \"%s\" is not a table",
                               9916                 :                :                         RelationGetRelationName(pkrel))));
                               9917                 :                : 
 7284 tgl@sss.pgh.pa.us        9918   [ +  +  +  + ]:CBC        1226 :     if (!allowSystemTableMods && IsSystemRelation(pkrel))
 7574                          9919         [ +  - ]:              1 :         ereport(ERROR,
                               9920                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                               9921                 :                :                  errmsg("permission denied: \"%s\" is a system catalog",
                               9922                 :                :                         RelationGetRelationName(pkrel))));
                               9923                 :                : 
                               9924                 :                :     /*
                               9925                 :                :      * References from permanent or unlogged tables to temp tables, and from
                               9926                 :                :      * permanent tables to unlogged tables, are disallowed because the
                               9927                 :                :      * referenced data can vanish out from under us.  References from temp
                               9928                 :                :      * tables to any other table type are also disallowed, because other
                               9929                 :                :      * backends might need to run the RI triggers on the perm table, but they
                               9930                 :                :      * can't reliably see tuples in the local buffers of other backends.
                               9931                 :                :      */
 4871 rhaas@postgresql.org     9932   [ +  +  +  - ]:           1225 :     switch (rel->rd_rel->relpersistence)
                               9933                 :                :     {
                               9934                 :           1070 :         case RELPERSISTENCE_PERMANENT:
 1119 bruce@momjian.us         9935         [ -  + ]:           1070 :             if (!RelationIsPermanent(pkrel))
 4871 rhaas@postgresql.org     9936         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               9937                 :                :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9938                 :                :                          errmsg("constraints on permanent tables may reference only permanent tables")));
 4871 rhaas@postgresql.org     9939                 :CBC        1070 :             break;
 4855                          9940                 :             16 :         case RELPERSISTENCE_UNLOGGED:
 1119 bruce@momjian.us         9941         [ +  - ]:             16 :             if (!RelationIsPermanent(pkrel)
 4855 rhaas@postgresql.org     9942         [ -  + ]:             16 :                 && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
 4855 rhaas@postgresql.org     9943         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               9944                 :                :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9945                 :                :                          errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
 4855 rhaas@postgresql.org     9946                 :CBC          16 :             break;
 4871                          9947                 :            139 :         case RELPERSISTENCE_TEMP:
                               9948         [ -  + ]:            139 :             if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
 4871 rhaas@postgresql.org     9949         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               9950                 :                :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9951                 :                :                          errmsg("constraints on temporary tables may reference only temporary tables")));
 4136 tgl@sss.pgh.pa.us        9952   [ +  -  -  + ]:CBC         139 :             if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
 4136 tgl@sss.pgh.pa.us        9953         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               9954                 :                :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                               9955                 :                :                          errmsg("constraints on temporary tables must involve temporary tables of this session")));
 4871 rhaas@postgresql.org     9956                 :CBC         139 :             break;
                               9957                 :                :     }
                               9958                 :                : 
                               9959                 :                :     /*
                               9960                 :                :      * Look up the referencing attributes to make sure they exist, and record
                               9961                 :                :      * their attnums and type OIDs.
                               9962                 :                :      */
 7875 tgl@sss.pgh.pa.us        9963                 :           1225 :     numfks = transformColumnNameList(RelationGetRelid(rel),
                               9964                 :                :                                      fkconstraint->fk_attrs,
                               9965                 :                :                                      fkattnum, fktypoid);
   21 peter@eisentraut.org     9966   [ +  +  +  + ]:GNC        1210 :     with_period = fkconstraint->fk_with_period || fkconstraint->pk_with_period;
                               9967   [ +  +  +  + ]:           1210 :     if (with_period && !fkconstraint->fk_with_period)
                               9968         [ +  - ]:             12 :         ereport(ERROR,
                               9969                 :                :                 errcode(ERRCODE_INVALID_FOREIGN_KEY),
                               9970                 :                :                 errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
                               9971                 :                : 
  858 peter@eisentraut.org     9972                 :CBC        1198 :     numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
                               9973                 :                :                                               fkconstraint->fk_del_set_cols,
                               9974                 :                :                                               fkdelsetcols, NULL);
                               9975                 :           1195 :     validateFkOnDeleteSetColumns(numfks, fkattnum,
                               9976                 :                :                                  numfkdelsetcols, fkdelsetcols,
                               9977                 :                :                                  fkconstraint->fk_del_set_cols);
                               9978                 :                : 
                               9979                 :                :     /*
                               9980                 :                :      * If the attribute list for the referenced table was omitted, lookup the
                               9981                 :                :      * definition of the primary key and use it.  Otherwise, validate the
                               9982                 :                :      * supplied attribute list.  In either case, discover the index OID and
                               9983                 :                :      * index opclasses, and the attnums and type OIDs of the attributes.
                               9984                 :                :      */
 7875 tgl@sss.pgh.pa.us        9985         [ +  + ]:           1192 :     if (fkconstraint->pk_attrs == NIL)
                               9986                 :                :     {
                               9987                 :            535 :         numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
                               9988                 :                :                                             &fkconstraint->pk_attrs,
                               9989                 :                :                                             pkattnum, pktypoid,
                               9990                 :                :                                             opclasses, &pk_has_without_overlaps);
                               9991                 :                : 
                               9992                 :                :         /* If the primary key uses WITHOUT OVERLAPS, the fk must use PERIOD */
   21 peter@eisentraut.org     9993   [ +  +  +  + ]:GNC         535 :         if (pk_has_without_overlaps && !fkconstraint->fk_with_period)
                               9994         [ +  - ]:             12 :             ereport(ERROR,
                               9995                 :                :                     errcode(ERRCODE_INVALID_FOREIGN_KEY),
                               9996                 :                :                     errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
                               9997                 :                :     }
                               9998                 :                :     else
                               9999                 :                :     {
 7875 tgl@sss.pgh.pa.us       10000                 :CBC         657 :         numpks = transformColumnNameList(RelationGetRelid(pkrel),
                              10001                 :                :                                          fkconstraint->pk_attrs,
                              10002                 :                :                                          pkattnum, pktypoid);
                              10003                 :                : 
                              10004                 :                :         /* Since we got pk_attrs, one should be a period. */
   21 peter@eisentraut.org    10005   [ +  +  +  + ]:GNC         642 :         if (with_period && !fkconstraint->pk_with_period)
                              10006         [ +  - ]:             12 :             ereport(ERROR,
                              10007                 :                :                     errcode(ERRCODE_INVALID_FOREIGN_KEY),
                              10008                 :                :                     errmsg("foreign key uses PERIOD on the referencing table but not the referenced table"));
                              10009                 :                : 
                              10010                 :                :         /* Look for an index matching the column list */
 7337 tgl@sss.pgh.pa.us       10011                 :CBC         630 :         indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
                              10012                 :                :                                            with_period, opclasses, &pk_has_without_overlaps);
                              10013                 :                :     }
                              10014                 :                : 
                              10015                 :                :     /*
                              10016                 :                :      * If the referenced primary key has WITHOUT OVERLAPS, the foreign key
                              10017                 :                :      * must use PERIOD.
                              10018                 :                :      */
   21 peter@eisentraut.org    10019   [ +  +  +  + ]:GNC        1135 :     if (pk_has_without_overlaps && !with_period)
                              10020         [ +  - ]:              6 :         ereport(ERROR,
                              10021                 :                :                 errcode(ERRCODE_INVALID_FOREIGN_KEY),
                              10022                 :                :                 errmsg("foreign key must use PERIOD when referencing a primary using WITHOUT OVERLAPS"));
                              10023                 :                : 
                              10024                 :                :     /*
                              10025                 :                :      * Now we can check permissions.
                              10026                 :                :      */
 5561 tgl@sss.pgh.pa.us       10027                 :CBC        1129 :     checkFkeyPermissions(pkrel, pkattnum, numpks);
                              10028                 :                : 
                              10029                 :                :     /*
                              10030                 :                :      * Check some things for generated columns.
                              10031                 :                :      */
 1842 peter@eisentraut.org    10032         [ +  + ]:           2643 :     for (i = 0; i < numfks; i++)
                              10033                 :                :     {
                              10034                 :           1520 :         char        attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
                              10035                 :                : 
                              10036         [ +  + ]:           1520 :         if (attgenerated)
                              10037                 :                :         {
                              10038                 :                :             /*
                              10039                 :                :              * Check restrictions on UPDATE/DELETE actions, per SQL standard
                              10040                 :                :              */
                              10041         [ +  - ]:             15 :             if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
                              10042         [ +  - ]:             15 :                 fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
                              10043         [ +  + ]:             15 :                 fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
                              10044         [ +  - ]:              3 :                 ereport(ERROR,
                              10045                 :                :                         (errcode(ERRCODE_SYNTAX_ERROR),
                              10046                 :                :                          errmsg("invalid %s action for foreign key constraint containing generated column",
                              10047                 :                :                                 "ON UPDATE")));
                              10048         [ +  + ]:             12 :             if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
                              10049         [ -  + ]:              9 :                 fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
                              10050         [ +  - ]:              3 :                 ereport(ERROR,
                              10051                 :                :                         (errcode(ERRCODE_SYNTAX_ERROR),
                              10052                 :                :                          errmsg("invalid %s action for foreign key constraint containing generated column",
                              10053                 :                :                                 "ON DELETE")));
                              10054                 :                :         }
                              10055                 :                :     }
                              10056                 :                : 
                              10057                 :                :     /*
                              10058                 :                :      * Some actions are currently unsupported for foreign keys using PERIOD.
                              10059                 :                :      */
   21 peter@eisentraut.org    10060         [ +  + ]:GNC        1123 :     if (fkconstraint->fk_with_period)
                              10061                 :                :     {
                              10062         [ +  + ]:            119 :         if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE ||
                              10063         [ +  + ]:            113 :             fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
                              10064         [ +  + ]:            107 :             fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT)
                              10065         [ +  - ]:             18 :             ereport(ERROR,
                              10066                 :                :                     errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              10067                 :                :                     errmsg("unsupported %s action for foreign key constraint using PERIOD",
                              10068                 :                :                            "ON UPDATE"));
                              10069                 :                : 
                              10070         [ +  - ]:            101 :         if (fkconstraint->fk_del_action == FKCONSTR_ACTION_CASCADE ||
                              10071         [ +  - ]:            101 :             fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
                              10072         [ -  + ]:            101 :             fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
   21 peter@eisentraut.org    10073         [ #  # ]:UNC           0 :             ereport(ERROR,
                              10074                 :                :                     errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              10075                 :                :                     errmsg("unsupported %s action for foreign key constraint using PERIOD",
                              10076                 :                :                            "ON DELETE"));
                              10077                 :                :     }
                              10078                 :                : 
                              10079                 :                :     /*
                              10080                 :                :      * Look up the equality operators to use in the constraint.
                              10081                 :                :      *
                              10082                 :                :      * Note that we have to be careful about the difference between the actual
                              10083                 :                :      * PK column type and the opclass' declared input type, which might be
                              10084                 :                :      * only binary-compatible with it.  The declared opcintype is the right
                              10085                 :                :      * thing to probe pg_amop with.
                              10086                 :                :      */
 7875 tgl@sss.pgh.pa.us       10087         [ -  + ]:CBC        1105 :     if (numfks != numpks)
 7574 tgl@sss.pgh.pa.us       10088         [ #  # ]:UBC           0 :         ereport(ERROR,
                              10089                 :                :                 (errcode(ERRCODE_INVALID_FOREIGN_KEY),
                              10090                 :                :                  errmsg("number of referencing and referenced columns for foreign key disagree")));
                              10091                 :                : 
                              10092                 :                :     /*
                              10093                 :                :      * On the strength of a previous constraint, we might avoid scanning
                              10094                 :                :      * tables to validate this one.  See below.
                              10095                 :                :      */
 4430 alvherre@alvh.no-ip.    10096                 :CBC        1105 :     old_check_ok = (fkconstraint->old_conpfeqop != NIL);
                              10097   [ +  +  -  + ]:           1105 :     Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
                              10098                 :                : 
 7875 tgl@sss.pgh.pa.us       10099         [ +  + ]:           2397 :     for (i = 0; i < numpks; i++)
                              10100                 :                :     {
 6267                         10101                 :           1406 :         Oid         pktype = pktypoid[i];
                              10102                 :           1406 :         Oid         fktype = fktypoid[i];
                              10103                 :                :         Oid         fktyped;
                              10104                 :                :         HeapTuple   cla_ht;
                              10105                 :                :         Form_pg_opclass cla_tup;
                              10106                 :                :         Oid         amid;
                              10107                 :                :         Oid         opfamily;
                              10108                 :                :         Oid         opcintype;
                              10109                 :                :         Oid         pfeqop;
                              10110                 :                :         Oid         ppeqop;
                              10111                 :                :         Oid         ffeqop;
                              10112                 :                :         int16       eqstrategy;
                              10113                 :                :         Oid         pfeqop_right;
                              10114                 :                : 
                              10115                 :                :         /* We need several fields out of the pg_opclass entry */
 5173 rhaas@postgresql.org    10116                 :           1406 :         cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
 6269 tgl@sss.pgh.pa.us       10117         [ -  + ]:           1406 :         if (!HeapTupleIsValid(cla_ht))
 6269 tgl@sss.pgh.pa.us       10118         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
 6269 tgl@sss.pgh.pa.us       10119                 :CBC        1406 :         cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
                              10120                 :           1406 :         amid = cla_tup->opcmethod;
                              10121                 :           1406 :         opfamily = cla_tup->opcfamily;
 6267                         10122                 :           1406 :         opcintype = cla_tup->opcintype;
 6269                         10123                 :           1406 :         ReleaseSysCache(cla_ht);
                              10124                 :                : 
   21 peter@eisentraut.org    10125         [ +  + ]:GNC        1406 :         if (with_period)
                              10126                 :                :         {
                              10127                 :                :             StrategyNumber rtstrategy;
                              10128   [ +  -  +  + ]:            216 :             bool        for_overlaps = with_period && i == numpks - 1;
                              10129                 :                : 
                              10130                 :                :             /*
                              10131                 :                :              * GiST indexes are required to support temporal foreign keys
                              10132                 :                :              * because they combine equals and overlaps.
                              10133                 :                :              */
                              10134         [ -  + ]:            216 :             if (amid != GIST_AM_OID)
   21 peter@eisentraut.org    10135         [ #  # ]:UNC           0 :                 elog(ERROR, "only GiST indexes are supported for temporal foreign keys");
                              10136                 :                : 
   21 peter@eisentraut.org    10137         [ +  + ]:GNC         216 :             rtstrategy = for_overlaps ? RTOverlapStrategyNumber : RTEqualStrategyNumber;
                              10138                 :                : 
                              10139                 :                :             /*
                              10140                 :                :              * An opclass can use whatever strategy numbers it wants, so we
                              10141                 :                :              * ask the opclass what number it actually uses instead of our RT*
                              10142                 :                :              * constants.
                              10143                 :                :              */
                              10144                 :            216 :             eqstrategy = GistTranslateStratnum(opclasses[i], rtstrategy);
                              10145         [ -  + ]:            216 :             if (eqstrategy == InvalidStrategy)
                              10146                 :                :             {
                              10147                 :                :                 HeapTuple   tuple;
                              10148                 :                : 
   21 peter@eisentraut.org    10149                 :UNC           0 :                 tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
                              10150         [ #  # ]:              0 :                 if (!HeapTupleIsValid(tuple))
                              10151         [ #  # ]:              0 :                     elog(ERROR, "cache lookup failed for operator class %u", opclasses[i]);
                              10152                 :                : 
                              10153   [ #  #  #  # ]:              0 :                 ereport(ERROR,
                              10154                 :                :                         errcode(ERRCODE_UNDEFINED_OBJECT),
                              10155                 :                :                         for_overlaps
                              10156                 :                :                         ? errmsg("could not identify an overlaps operator for foreign key")
                              10157                 :                :                         : errmsg("could not identify an equality operator for foreign key"),
                              10158                 :                :                         errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".",
                              10159                 :                :                                   rtstrategy, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist"));
                              10160                 :                :             }
                              10161                 :                :         }
                              10162                 :                :         else
                              10163                 :                :         {
                              10164                 :                :             /*
                              10165                 :                :              * Check it's a btree; currently this can never fail since no
                              10166                 :                :              * other index AMs support unique indexes.  If we ever did have
                              10167                 :                :              * other types of unique indexes, we'd need a way to determine
                              10168                 :                :              * which operator strategy number is equality.  (We could use
                              10169                 :                :              * something like GistTranslateStratnum.)
                              10170                 :                :              */
   21 peter@eisentraut.org    10171         [ -  + ]:GNC        1190 :             if (amid != BTREE_AM_OID)
   21 peter@eisentraut.org    10172         [ #  # ]:UNC           0 :                 elog(ERROR, "only b-tree indexes are supported for foreign keys");
   21 peter@eisentraut.org    10173                 :GNC        1190 :             eqstrategy = BTEqualStrategyNumber;
                              10174                 :                :         }
                              10175                 :                : 
                              10176                 :                :         /*
                              10177                 :                :          * There had better be a primary equality operator for the index.
                              10178                 :                :          * We'll use it for PK = PK comparisons.
                              10179                 :                :          */
 6267 tgl@sss.pgh.pa.us       10180                 :CBC        1406 :         ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
                              10181                 :                :                                      eqstrategy);
                              10182                 :                : 
 6269                         10183         [ -  + ]:           1406 :         if (!OidIsValid(ppeqop))
 6269 tgl@sss.pgh.pa.us       10184         [ #  # ]:UBC           0 :             elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
                              10185                 :                :                  eqstrategy, opcintype, opcintype, opfamily);
                              10186                 :                : 
                              10187                 :                :         /*
                              10188                 :                :          * Are there equality operators that take exactly the FK type? Assume
                              10189                 :                :          * we should look through any domain here.
                              10190                 :                :          */
 6267 tgl@sss.pgh.pa.us       10191                 :CBC        1406 :         fktyped = getBaseType(fktype);
                              10192                 :                : 
                              10193                 :           1406 :         pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
                              10194                 :                :                                      eqstrategy);
                              10195         [ +  + ]:           1406 :         if (OidIsValid(pfeqop))
                              10196                 :                :         {
 4430 alvherre@alvh.no-ip.    10197                 :           1065 :             pfeqop_right = fktyped;
 6267 tgl@sss.pgh.pa.us       10198                 :           1065 :             ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
                              10199                 :                :                                          eqstrategy);
                              10200                 :                :         }
                              10201                 :                :         else
                              10202                 :                :         {
                              10203                 :                :             /* keep compiler quiet */
 4430 alvherre@alvh.no-ip.    10204                 :            341 :             pfeqop_right = InvalidOid;
                              10205                 :            341 :             ffeqop = InvalidOid;
                              10206                 :                :         }
                              10207                 :                : 
 6269 tgl@sss.pgh.pa.us       10208   [ +  +  -  + ]:           1406 :         if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
                              10209                 :                :         {
                              10210                 :                :             /*
                              10211                 :                :              * Otherwise, look for an implicit cast from the FK type to the
                              10212                 :                :              * opcintype, and if found, use the primary equality operator.
                              10213                 :                :              * This is a bit tricky because opcintype might be a polymorphic
                              10214                 :                :              * type such as ANYARRAY or ANYENUM; so what we have to test is
                              10215                 :                :              * whether the two actual column types can be concurrently cast to
                              10216                 :                :              * that type.  (Otherwise, we'd fail to reject combinations such
                              10217                 :                :              * as int[] and point[].)
                              10218                 :                :              */
                              10219                 :                :             Oid         input_typeids[2];
                              10220                 :                :             Oid         target_typeids[2];
                              10221                 :                : 
 6267                         10222                 :            341 :             input_typeids[0] = pktype;
                              10223                 :            341 :             input_typeids[1] = fktype;
                              10224                 :            341 :             target_typeids[0] = opcintype;
                              10225                 :            341 :             target_typeids[1] = opcintype;
                              10226         [ +  + ]:            341 :             if (can_coerce_type(2, input_typeids, target_typeids,
                              10227                 :                :                                 COERCION_IMPLICIT))
                              10228                 :                :             {
 6269                         10229                 :            227 :                 pfeqop = ffeqop = ppeqop;
 4430 alvherre@alvh.no-ip.    10230                 :            227 :                 pfeqop_right = opcintype;
                              10231                 :                :             }
                              10232                 :                :         }
                              10233                 :                : 
 6269 tgl@sss.pgh.pa.us       10234   [ +  +  -  + ]:           1406 :         if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
 7337                         10235         [ +  - ]:            114 :             ereport(ERROR,
                              10236                 :                :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              10237                 :                :                      errmsg("foreign key constraint \"%s\" cannot be implemented",
                              10238                 :                :                             fkconstraint->conname),
                              10239                 :                :                      errdetail("Key columns \"%s\" and \"%s\" "
                              10240                 :                :                                "are of incompatible types: %s and %s.",
                              10241                 :                :                                strVal(list_nth(fkconstraint->fk_attrs, i)),
                              10242                 :                :                                strVal(list_nth(fkconstraint->pk_attrs, i)),
                              10243                 :                :                                format_type_be(fktype),
                              10244                 :                :                                format_type_be(pktype))));
                              10245                 :                : 
 4430 alvherre@alvh.no-ip.    10246         [ +  + ]:           1292 :         if (old_check_ok)
                              10247                 :                :         {
                              10248                 :                :             /*
                              10249                 :                :              * When a pfeqop changes, revalidate the constraint.  We could
                              10250                 :                :              * permit intra-opfamily changes, but that adds subtle complexity
                              10251                 :                :              * without any concrete benefit for core types.  We need not
                              10252                 :                :              * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
                              10253                 :                :              */
                              10254                 :              3 :             old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
 1735 tgl@sss.pgh.pa.us       10255                 :              3 :             old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
                              10256                 :                :                                     old_pfeqop_item);
                              10257                 :                :         }
 4430 alvherre@alvh.no-ip.    10258         [ +  + ]:           1292 :         if (old_check_ok)
                              10259                 :                :         {
                              10260                 :                :             Oid         old_fktype;
                              10261                 :                :             Oid         new_fktype;
                              10262                 :                :             CoercionPathType old_pathtype;
                              10263                 :                :             CoercionPathType new_pathtype;
                              10264                 :                :             Oid         old_castfunc;
                              10265                 :                :             Oid         new_castfunc;
 2429 andres@anarazel.de      10266                 :              3 :             Form_pg_attribute attr = TupleDescAttr(tab->oldDesc,
                              10267                 :                :                                                    fkattnum[i] - 1);
                              10268                 :                : 
                              10269                 :                :             /*
                              10270                 :                :              * Identify coercion pathways from each of the old and new FK-side
                              10271                 :                :              * column types to the right (foreign) operand type of the pfeqop.
                              10272                 :                :              * We may assume that pg_constraint.conkey is not changing.
                              10273                 :                :              */
                              10274                 :              3 :             old_fktype = attr->atttypid;
 4430 alvherre@alvh.no-ip.    10275                 :              3 :             new_fktype = fktype;
                              10276                 :              3 :             old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
                              10277                 :                :                                         &old_castfunc);
                              10278                 :              3 :             new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
                              10279                 :                :                                         &new_castfunc);
                              10280                 :                : 
                              10281                 :                :             /*
                              10282                 :                :              * Upon a change to the cast from the FK column to its pfeqop
                              10283                 :                :              * operand, revalidate the constraint.  For this evaluation, a
                              10284                 :                :              * binary coercion cast is equivalent to no cast at all.  While
                              10285                 :                :              * type implementors should design implicit casts with an eye
                              10286                 :                :              * toward consistency of operations like equality, we cannot
                              10287                 :                :              * assume here that they have done so.
                              10288                 :                :              *
                              10289                 :                :              * A function with a polymorphic argument could change behavior
                              10290                 :                :              * arbitrarily in response to get_fn_expr_argtype().  Therefore,
                              10291                 :                :              * when the cast destination is polymorphic, we only avoid
                              10292                 :                :              * revalidation if the input type has not changed at all.  Given
                              10293                 :                :              * just the core data types and operator classes, this requirement
                              10294                 :                :              * prevents no would-be optimizations.
                              10295                 :                :              *
                              10296                 :                :              * If the cast converts from a base type to a domain thereon, then
                              10297                 :                :              * that domain type must be the opcintype of the unique index.
                              10298                 :                :              * Necessarily, the primary key column must then be of the domain
                              10299                 :                :              * type.  Since the constraint was previously valid, all values on
                              10300                 :                :              * the foreign side necessarily exist on the primary side and in
                              10301                 :                :              * turn conform to the domain.  Consequently, we need not treat
                              10302                 :                :              * domains specially here.
                              10303                 :                :              *
                              10304                 :                :              * Since we require that all collations share the same notion of
                              10305                 :                :              * equality (which they do, because texteq reduces to bitwise
                              10306                 :                :              * equality), we don't compare collation here.
                              10307                 :                :              *
                              10308                 :                :              * We need not directly consider the PK type.  It's necessarily
                              10309                 :                :              * binary coercible to the opcintype of the unique index column,
                              10310                 :                :              * and ri_triggers.c will only deal with PK datums in terms of
                              10311                 :                :              * that opcintype.  Changing the opcintype also changes pfeqop.
                              10312                 :                :              */
                              10313                 :              3 :             old_check_ok = (new_pathtype == old_pathtype &&
                              10314   [ +  -  +  -  :              6 :                             new_castfunc == old_castfunc &&
                                              +  - ]
                              10315   [ +  -  +  -  :              3 :                             (!IsPolymorphicType(pfeqop_right) ||
                                     +  -  +  -  +  
                                     -  +  -  +  -  
                                     +  -  +  -  -  
                                           +  -  - ]
                              10316                 :                :                              new_fktype == old_fktype));
                              10317                 :                :         }
                              10318                 :                : 
 6269 tgl@sss.pgh.pa.us       10319                 :           1292 :         pfeqoperators[i] = pfeqop;
                              10320                 :           1292 :         ppeqoperators[i] = ppeqop;
                              10321                 :           1292 :         ffeqoperators[i] = ffeqop;
                              10322                 :                :     }
                              10323                 :                : 
                              10324                 :                :     /*
                              10325                 :                :      * For FKs with PERIOD we need additional operators to check whether the
                              10326                 :                :      * referencing row's range is contained by the aggregated ranges of the
                              10327                 :                :      * referenced row(s). For rangetypes and multirangetypes this is
                              10328                 :                :      * fk.periodatt <@ range_agg(pk.periodatt). Those are the only types we
                              10329                 :                :      * support for now. FKs will look these up at "runtime", but we should
                              10330                 :                :      * make sure the lookup works here, even if we don't use the values.
                              10331                 :                :      */
   21 peter@eisentraut.org    10332         [ +  + ]:GNC         991 :     if (with_period)
                              10333                 :                :     {
                              10334                 :                :         Oid         periodoperoid;
                              10335                 :                :         Oid         aggedperiodoperoid;
                              10336                 :                : 
                              10337                 :             92 :         FindFKPeriodOpers(opclasses[numpks - 1], &periodoperoid, &aggedperiodoperoid);
                              10338                 :                :     }
                              10339                 :                : 
                              10340                 :                :     /*
                              10341                 :                :      * Create all the constraint and trigger objects, recursing to partitions
                              10342                 :                :      * as necessary.  First handle the referenced side.
                              10343                 :                :      */
 1838 alvherre@alvh.no-ip.    10344                 :CBC         988 :     address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
                              10345                 :                :                                      indexOid,
                              10346                 :                :                                      InvalidOid,    /* no parent constraint */
                              10347                 :                :                                      numfks,
                              10348                 :                :                                      pkattnum,
                              10349                 :                :                                      fkattnum,
                              10350                 :                :                                      pfeqoperators,
                              10351                 :                :                                      ppeqoperators,
                              10352                 :                :                                      ffeqoperators,
                              10353                 :                :                                      numfkdelsetcols,
                              10354                 :                :                                      fkdelsetcols,
                              10355                 :                :                                      old_check_ok,
                              10356                 :                :                                      InvalidOid, InvalidOid,
                              10357                 :                :                                      with_period);
                              10358                 :                : 
                              10359                 :                :     /* Now handle the referencing side. */
                              10360                 :            988 :     addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
                              10361                 :                :                             indexOid,
                              10362                 :                :                             address.objectId,
                              10363                 :                :                             numfks,
                              10364                 :                :                             pkattnum,
                              10365                 :                :                             fkattnum,
                              10366                 :                :                             pfeqoperators,
                              10367                 :                :                             ppeqoperators,
                              10368                 :                :                             ffeqoperators,
                              10369                 :                :                             numfkdelsetcols,
                              10370                 :                :                             fkdelsetcols,
                              10371                 :                :                             old_check_ok,
                              10372                 :                :                             lockmode,
                              10373                 :                :                             InvalidOid, InvalidOid,
                              10374                 :                :                             with_period);
                              10375                 :                : 
                              10376                 :                :     /*
                              10377                 :                :      * Done.  Close pk table, but keep lock until we've committed.
                              10378                 :                :      */
                              10379                 :            988 :     table_close(pkrel, NoLock);
                              10380                 :                : 
                              10381                 :            988 :     return address;
                              10382                 :                : }
                              10383                 :                : 
                              10384                 :                : /*
                              10385                 :                :  * validateFkOnDeleteSetColumns
                              10386                 :                :  *      Verifies that columns used in ON DELETE SET NULL/DEFAULT (...)
                              10387                 :                :  *      column lists are valid.
                              10388                 :                :  */
                              10389                 :                : void
  858 peter@eisentraut.org    10390                 :           1195 : validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
                              10391                 :                :                              int numfksetcols, const int16 *fksetcolsattnums,
                              10392                 :                :                              List *fksetcols)
                              10393                 :                : {
                              10394         [ +  + ]:           1207 :     for (int i = 0; i < numfksetcols; i++)
                              10395                 :                :     {
  703 tgl@sss.pgh.pa.us       10396                 :             15 :         int16       setcol_attnum = fksetcolsattnums[i];
                              10397                 :             15 :         bool        seen = false;
                              10398                 :                : 
  858 peter@eisentraut.org    10399         [ +  + ]:             27 :         for (int j = 0; j < numfks; j++)
                              10400                 :                :         {
                              10401         [ +  + ]:             24 :             if (fkattnums[j] == setcol_attnum)
                              10402                 :                :             {
                              10403                 :             12 :                 seen = true;
                              10404                 :             12 :                 break;
                              10405                 :                :             }
                              10406                 :                :         }
                              10407                 :                : 
                              10408         [ +  + ]:             15 :         if (!seen)
                              10409                 :                :         {
  703 tgl@sss.pgh.pa.us       10410                 :              3 :             char       *col = strVal(list_nth(fksetcols, i));
                              10411                 :                : 
  858 peter@eisentraut.org    10412         [ +  - ]:              3 :             ereport(ERROR,
                              10413                 :                :                     (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                              10414                 :                :                      errmsg("column \"%s\" referenced in ON DELETE SET action must be part of foreign key", col)));
                              10415                 :                :         }
                              10416                 :                :     }
                              10417                 :           1192 : }
                              10418                 :                : 
                              10419                 :                : /*
                              10420                 :                :  * addFkRecurseReferenced
                              10421                 :                :  *      subroutine for ATAddForeignKeyConstraint; recurses on the referenced
                              10422                 :                :  *      side of the constraint
                              10423                 :                :  *
                              10424                 :                :  * Create pg_constraint rows for the referenced side of the constraint,
                              10425                 :                :  * referencing the parent of the referencing side; also create action triggers
                              10426                 :                :  * on leaf partitions.  If the table is partitioned, recurse to handle each
                              10427                 :                :  * partition.
                              10428                 :                :  *
                              10429                 :                :  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
                              10430                 :                :  * of an ALTER TABLE sequence.
                              10431                 :                :  * fkconstraint is the constraint being added.
                              10432                 :                :  * rel is the root referencing relation.
                              10433                 :                :  * pkrel is the referenced relation; might be a partition, if recursing.
                              10434                 :                :  * indexOid is the OID of the index (on pkrel) implementing this constraint.
                              10435                 :                :  * parentConstr is the OID of a parent constraint; InvalidOid if this is a
                              10436                 :                :  * top-level constraint.
                              10437                 :                :  * numfks is the number of columns in the foreign key
                              10438                 :                :  * pkattnum is the attnum array of referenced attributes.
                              10439                 :                :  * fkattnum is the attnum array of referencing attributes.
                              10440                 :                :  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
                              10441                 :                :  *      (...) clause
                              10442                 :                :  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
                              10443                 :                :  *      NULL/DEFAULT clause
                              10444                 :                :  * pf/pp/ffeqoperators are OID array of operators between columns.
                              10445                 :                :  * old_check_ok signals that this constraint replaces an existing one that
                              10446                 :                :  * was already validated (thus this one doesn't need validation).
                              10447                 :                :  * parentDelTrigger and parentUpdTrigger, when being recursively called on
                              10448                 :                :  * a partition, are the OIDs of the parent action triggers for DELETE and
                              10449                 :                :  * UPDATE respectively.
                              10450                 :                :  */
                              10451                 :                : static ObjectAddress
 1838 alvherre@alvh.no-ip.    10452                 :           1348 : addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
                              10453                 :                :                        Relation pkrel, Oid indexOid, Oid parentConstr,
                              10454                 :                :                        int numfks,
                              10455                 :                :                        int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators,
                              10456                 :                :                        Oid *ppeqoperators, Oid *ffeqoperators,
                              10457                 :                :                        int numfkdelsetcols, int16 *fkdelsetcols,
                              10458                 :                :                        bool old_check_ok,
                              10459                 :                :                        Oid parentDelTrigger, Oid parentUpdTrigger,
                              10460                 :                :                        bool with_period)
                              10461                 :                : {
                              10462                 :                :     ObjectAddress address;
                              10463                 :                :     Oid         constrOid;
                              10464                 :                :     char       *conname;
                              10465                 :                :     bool        conislocal;
                              10466                 :                :     int         coninhcount;
                              10467                 :                :     bool        connoinherit;
                              10468                 :                :     Oid         deleteTriggerOid,
                              10469                 :                :                 updateTriggerOid;
                              10470                 :                : 
                              10471                 :                :     /*
                              10472                 :                :      * Verify relkind for each referenced partition.  At the top level, this
                              10473                 :                :      * is redundant with a previous check, but we need it when recursing.
                              10474                 :                :      */
                              10475         [ +  + ]:           1348 :     if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
                              10476         [ -  + ]:            189 :         pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 1838 alvherre@alvh.no-ip.    10477         [ #  # ]:UBC           0 :         ereport(ERROR,
                              10478                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              10479                 :                :                  errmsg("referenced relation \"%s\" is not a table",
                              10480                 :                :                         RelationGetRelationName(pkrel))));
                              10481                 :                : 
                              10482                 :                :     /*
                              10483                 :                :      * Caller supplies us with a constraint name; however, it may be used in
                              10484                 :                :      * this partition, so come up with a different one in that case.
                              10485                 :                :      */
 1838 alvherre@alvh.no-ip.    10486         [ +  + ]:CBC        1348 :     if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
                              10487                 :                :                              RelationGetRelid(rel),
                              10488                 :           1348 :                              fkconstraint->conname))
                              10489                 :            360 :         conname = ChooseConstraintName(RelationGetRelationName(rel),
                              10490                 :            360 :                                        ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
                              10491                 :                :                                        "fkey",
                              10492                 :            360 :                                        RelationGetNamespace(rel), NIL);
                              10493                 :                :     else
                              10494                 :            988 :         conname = fkconstraint->conname;
                              10495                 :                : 
                              10496         [ +  + ]:           1348 :     if (OidIsValid(parentConstr))
                              10497                 :                :     {
                              10498                 :            360 :         conislocal = false;
                              10499                 :            360 :         coninhcount = 1;
                              10500                 :            360 :         connoinherit = false;
                              10501                 :                :     }
                              10502                 :                :     else
                              10503                 :                :     {
                              10504                 :            988 :         conislocal = true;
                              10505                 :            988 :         coninhcount = 0;
                              10506                 :                : 
                              10507                 :                :         /*
                              10508                 :                :          * always inherit for partitioned tables, never for legacy inheritance
                              10509                 :                :          */
                              10510                 :            988 :         connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
                              10511                 :                :     }
                              10512                 :                : 
                              10513                 :                :     /*
                              10514                 :                :      * Record the FK constraint in pg_constraint.
                              10515                 :                :      */
                              10516                 :           1348 :     constrOid = CreateConstraintEntry(conname,
 7875 tgl@sss.pgh.pa.us       10517                 :           1348 :                                       RelationGetNamespace(rel),
                              10518                 :                :                                       CONSTRAINT_FOREIGN,
                              10519                 :           1348 :                                       fkconstraint->deferrable,
                              10520                 :           1348 :                                       fkconstraint->initdeferred,
 4772 simon@2ndQuadrant.co    10521                 :           1348 :                                       fkconstraint->initially_valid,
                              10522                 :                :                                       parentConstr,
                              10523                 :                :                                       RelationGetRelid(rel),
                              10524                 :                :                                       fkattnum,
                              10525                 :                :                                       numfks,
                              10526                 :                :                                       numfks,
                              10527                 :                :                                       InvalidOid,   /* not a domain constraint */
                              10528                 :                :                                       indexOid,
                              10529                 :                :                                       RelationGetRelid(pkrel),
                              10530                 :                :                                       pkattnum,
                              10531                 :                :                                       pfeqoperators,
                              10532                 :                :                                       ppeqoperators,
                              10533                 :                :                                       ffeqoperators,
                              10534                 :                :                                       numfks,
 7875 tgl@sss.pgh.pa.us       10535                 :           1348 :                                       fkconstraint->fk_upd_action,
                              10536                 :           1348 :                                       fkconstraint->fk_del_action,
                              10537                 :                :                                       fkdelsetcols,
                              10538                 :                :                                       numfkdelsetcols,
                              10539                 :           1348 :                                       fkconstraint->fk_matchtype,
                              10540                 :                :                                       NULL, /* no exclusion constraint */
                              10541                 :                :                                       NULL, /* no check constraint */
                              10542                 :                :                                       NULL,
                              10543                 :                :                                       conislocal,   /* islocal */
                              10544                 :                :                                       coninhcount,  /* inhcount */
                              10545                 :                :                                       connoinherit, /* conNoInherit */
                              10546                 :                :                                       with_period,  /* conPeriod */
                              10547                 :                :                                       false);   /* is_internal */
                              10548                 :                : 
 3308 alvherre@alvh.no-ip.    10549                 :           1348 :     ObjectAddressSet(address, ConstraintRelationId, constrOid);
                              10550                 :                : 
                              10551                 :                :     /*
                              10552                 :                :      * Mark the child constraint as part of the parent constraint; it must not
                              10553                 :                :      * be dropped on its own.  (This constraint is deleted when the partition
                              10554                 :                :      * is detached, but a special check needs to occur that the partition
                              10555                 :                :      * contains no referenced values.)
                              10556                 :                :      */
 1838                         10557         [ +  + ]:           1348 :     if (OidIsValid(parentConstr))
                              10558                 :                :     {
                              10559                 :                :         ObjectAddress referenced;
                              10560                 :                : 
                              10561                 :            360 :         ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
                              10562                 :            360 :         recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
                              10563                 :                :     }
                              10564                 :                : 
                              10565                 :                :     /* make new constraint visible, in case we add more */
                              10566                 :           1348 :     CommandCounterIncrement();
                              10567                 :                : 
                              10568                 :                :     /*
                              10569                 :                :      * Create the action triggers that enforce the constraint.
                              10570                 :                :      */
  830                         10571                 :           1348 :     createForeignKeyActionTriggers(rel, RelationGetRelid(pkrel),
                              10572                 :                :                                    fkconstraint,
                              10573                 :                :                                    constrOid, indexOid,
                              10574                 :                :                                    parentDelTrigger, parentUpdTrigger,
                              10575                 :                :                                    &deleteTriggerOid, &updateTriggerOid);
                              10576                 :                : 
                              10577                 :                :     /*
                              10578                 :                :      * If the referenced table is partitioned, recurse on ourselves to handle
                              10579                 :                :      * each partition.  We need one pg_constraint row created for each
                              10580                 :                :      * partition in addition to the pg_constraint row for the parent table.
                              10581                 :                :      */
 1838                         10582         [ +  + ]:           1348 :     if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              10583                 :                :     {
 1088                         10584                 :            189 :         PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
                              10585                 :                : 
 1838                         10586         [ +  + ]:            474 :         for (int i = 0; i < pd->nparts; i++)
                              10587                 :                :         {
                              10588                 :                :             Relation    partRel;
                              10589                 :                :             AttrMap    *map;
                              10590                 :                :             AttrNumber *mapped_pkattnum;
                              10591                 :                :             Oid         partIndexId;
                              10592                 :                : 
                              10593                 :            285 :             partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
                              10594                 :                : 
                              10595                 :                :             /*
                              10596                 :                :              * Map the attribute numbers in the referenced side of the FK
                              10597                 :                :              * definition to match the partition's column layout.
                              10598                 :                :              */
 1579 michael@paquier.xyz     10599                 :            285 :             map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
                              10600                 :                :                                                RelationGetDescr(pkrel),
                              10601                 :                :                                                false);
 1838 alvherre@alvh.no-ip.    10602         [ +  + ]:            285 :             if (map)
                              10603                 :                :             {
                              10604                 :             23 :                 mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
                              10605         [ +  + ]:             46 :                 for (int j = 0; j < numfks; j++)
 1579 michael@paquier.xyz     10606                 :             23 :                     mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
                              10607                 :                :             }
                              10608                 :                :             else
 1838 alvherre@alvh.no-ip.    10609                 :            262 :                 mapped_pkattnum = pkattnum;
                              10610                 :                : 
                              10611                 :                :             /* do the deed */
                              10612                 :            285 :             partIndexId = index_get_partition(partRel, indexOid);
                              10613         [ -  + ]:            285 :             if (!OidIsValid(partIndexId))
 1838 alvherre@alvh.no-ip.    10614         [ #  # ]:UBC           0 :                 elog(ERROR, "index for %u not found in partition %s",
                              10615                 :                :                      indexOid, RelationGetRelationName(partRel));
 1838 alvherre@alvh.no-ip.    10616                 :CBC         285 :             addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
                              10617                 :                :                                    partIndexId, constrOid, numfks,
                              10618                 :                :                                    mapped_pkattnum, fkattnum,
                              10619                 :                :                                    pfeqoperators, ppeqoperators, ffeqoperators,
                              10620                 :                :                                    numfkdelsetcols, fkdelsetcols,
                              10621                 :                :                                    old_check_ok,
                              10622                 :                :                                    deleteTriggerOid, updateTriggerOid,
                              10623                 :                :                                    with_period);
                              10624                 :                : 
                              10625                 :                :             /* Done -- clean up (but keep the lock) */
                              10626                 :            285 :             table_close(partRel, NoLock);
                              10627         [ +  + ]:            285 :             if (map)
                              10628                 :                :             {
                              10629                 :             23 :                 pfree(mapped_pkattnum);
 1579 michael@paquier.xyz     10630                 :             23 :                 free_attrmap(map);
                              10631                 :                :             }
                              10632                 :                :         }
                              10633                 :                :     }
                              10634                 :                : 
 1838 alvherre@alvh.no-ip.    10635                 :           1348 :     return address;
                              10636                 :                : }
                              10637                 :                : 
                              10638                 :                : /*
                              10639                 :                :  * addFkRecurseReferencing
                              10640                 :                :  *      subroutine for ATAddForeignKeyConstraint and CloneFkReferencing
                              10641                 :                :  *
                              10642                 :                :  * If the referencing relation is a plain relation, create the necessary check
                              10643                 :                :  * triggers that implement the constraint, and set up for Phase 3 constraint
                              10644                 :                :  * verification.  If the referencing relation is a partitioned table, then
                              10645                 :                :  * we create a pg_constraint row for it and recurse on this routine for each
                              10646                 :                :  * partition.
                              10647                 :                :  *
                              10648                 :                :  * We assume that the referenced relation is locked against concurrent
                              10649                 :                :  * deletions.  If it's a partitioned relation, every partition must be so
                              10650                 :                :  * locked.
                              10651                 :                :  *
                              10652                 :                :  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
                              10653                 :                :  * of an ALTER TABLE sequence.
                              10654                 :                :  * fkconstraint is the constraint being added.
                              10655                 :                :  * rel is the referencing relation; might be a partition, if recursing.
                              10656                 :                :  * pkrel is the root referenced relation.
                              10657                 :                :  * indexOid is the OID of the index (on pkrel) implementing this constraint.
                              10658                 :                :  * parentConstr is the OID of the parent constraint (there is always one).
                              10659                 :                :  * numfks is the number of columns in the foreign key
                              10660                 :                :  * pkattnum is the attnum array of referenced attributes.
                              10661                 :                :  * fkattnum is the attnum array of referencing attributes.
                              10662                 :                :  * pf/pp/ffeqoperators are OID array of operators between columns.
                              10663                 :                :  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
                              10664                 :                :  *      (...) clause
                              10665                 :                :  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
                              10666                 :                :  *      NULL/DEFAULT clause
                              10667                 :                :  * old_check_ok signals that this constraint replaces an existing one that
                              10668                 :                :  *      was already validated (thus this one doesn't need validation).
                              10669                 :                :  * lockmode is the lockmode to acquire on partitions when recursing.
                              10670                 :                :  * parentInsTrigger and parentUpdTrigger, when being recursively called on
                              10671                 :                :  * a partition, are the OIDs of the parent check triggers for INSERT and
                              10672                 :                :  * UPDATE respectively.
                              10673                 :                :  */
                              10674                 :                : static void
                              10675                 :           1373 : addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
                              10676                 :                :                         Relation pkrel, Oid indexOid, Oid parentConstr,
                              10677                 :                :                         int numfks, int16 *pkattnum, int16 *fkattnum,
                              10678                 :                :                         Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
                              10679                 :                :                         int numfkdelsetcols, int16 *fkdelsetcols,
                              10680                 :                :                         bool old_check_ok, LOCKMODE lockmode,
                              10681                 :                :                         Oid parentInsTrigger, Oid parentUpdTrigger,
                              10682                 :                :                         bool with_period)
                              10683                 :                : {
                              10684                 :                :     Oid         insertTriggerOid,
                              10685                 :                :                 updateTriggerOid;
                              10686                 :                : 
  534 peter@eisentraut.org    10687         [ -  + ]:           1373 :     Assert(OidIsValid(parentConstr));
                              10688                 :                : 
 1838 alvherre@alvh.no-ip.    10689         [ -  + ]:           1373 :     if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
 1838 alvherre@alvh.no-ip.    10690         [ #  # ]:UBC           0 :         ereport(ERROR,
                              10691                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              10692                 :                :                  errmsg("foreign key constraints are not supported on foreign tables")));
                              10693                 :                : 
                              10694                 :                :     /*
                              10695                 :                :      * Add the check triggers to it and, if necessary, schedule it to be
                              10696                 :                :      * checked in Phase 3.
                              10697                 :                :      *
                              10698                 :                :      * If the relation is partitioned, drill down to do it to its partitions.
                              10699                 :                :      */
  830 alvherre@alvh.no-ip.    10700                 :CBC        1373 :     createForeignKeyCheckTriggers(RelationGetRelid(rel),
                              10701                 :                :                                   RelationGetRelid(pkrel),
                              10702                 :                :                                   fkconstraint,
                              10703                 :                :                                   parentConstr,
                              10704                 :                :                                   indexOid,
                              10705                 :                :                                   parentInsTrigger, parentUpdTrigger,
                              10706                 :                :                                   &insertTriggerOid, &updateTriggerOid);
                              10707                 :                : 
 1838                         10708         [ +  + ]:           1373 :     if (rel->rd_rel->relkind == RELKIND_RELATION)
                              10709                 :                :     {
                              10710                 :                :         /*
                              10711                 :                :          * Tell Phase 3 to check that the constraint is satisfied by existing
                              10712                 :                :          * rows. We can skip this during table creation, when requested
                              10713                 :                :          * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
                              10714                 :                :          * and when we're recreating a constraint following a SET DATA TYPE
                              10715                 :                :          * operation that did not impugn its validity.
                              10716                 :                :          */
                              10717   [ +  +  +  +  :           1167 :         if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
                                              +  + ]
                              10718                 :                :         {
                              10719                 :                :             NewConstraint *newcon;
                              10720                 :                :             AlteredTableInfo *tab;
                              10721                 :                : 
                              10722                 :            396 :             tab = ATGetQueueEntry(wqueue, rel);
                              10723                 :                : 
 1913                         10724                 :            396 :             newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
 1838                         10725                 :            396 :             newcon->name = get_constraint_name(parentConstr);
 1913                         10726                 :            396 :             newcon->contype = CONSTR_FOREIGN;
 1838                         10727                 :            396 :             newcon->refrelid = RelationGetRelid(pkrel);
                              10728                 :            396 :             newcon->refindid = indexOid;
                              10729                 :            396 :             newcon->conid = parentConstr;
   21 peter@eisentraut.org    10730                 :GNC         396 :             newcon->conwithperiod = fkconstraint->fk_with_period;
 1913 alvherre@alvh.no-ip.    10731                 :CBC         396 :             newcon->qual = (Node *) fkconstraint;
                              10732                 :                : 
 1838                         10733                 :            396 :             tab->constraints = lappend(tab->constraints, newcon);
                              10734                 :                :         }
                              10735                 :                :     }
                              10736         [ +  - ]:            206 :     else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              10737                 :                :     {
 1088                         10738                 :            206 :         PartitionDesc pd = RelationGetPartitionDesc(rel, true);
                              10739                 :                :         Relation    trigrel;
                              10740                 :                : 
                              10741                 :                :         /*
                              10742                 :                :          * Triggers of the foreign keys will be manipulated a bunch of times
                              10743                 :                :          * in the loop below.  To avoid repeatedly opening/closing the trigger
                              10744                 :                :          * catalog relation, we open it here and pass it to the subroutines
                              10745                 :                :          * called below.
                              10746                 :                :          */
  830                         10747                 :            206 :         trigrel = table_open(TriggerRelationId, RowExclusiveLock);
                              10748                 :                : 
                              10749                 :                :         /*
                              10750                 :                :          * Recurse to take appropriate action on each partition; either we
                              10751                 :                :          * find an existing constraint to reparent to ours, or we create a new
                              10752                 :                :          * one.
                              10753                 :                :          */
 1838                         10754         [ +  + ]:            394 :         for (int i = 0; i < pd->nparts; i++)
                              10755                 :                :         {
                              10756                 :            188 :             Oid         partitionId = pd->oids[i];
                              10757                 :            188 :             Relation    partition = table_open(partitionId, lockmode);
                              10758                 :                :             List       *partFKs;
                              10759                 :                :             AttrMap    *attmap;
                              10760                 :                :             AttrNumber  mapped_fkattnum[INDEX_MAX_KEYS];
                              10761                 :                :             bool        attached;
                              10762                 :                :             char       *conname;
                              10763                 :                :             Oid         constrOid;
                              10764                 :                :             ObjectAddress address,
                              10765                 :                :                         referenced;
                              10766                 :                :             ListCell   *cell;
                              10767                 :                : 
                              10768                 :            188 :             CheckTableNotInUse(partition, "ALTER TABLE");
                              10769                 :                : 
 1579 michael@paquier.xyz     10770                 :            188 :             attmap = build_attrmap_by_name(RelationGetDescr(partition),
                              10771                 :                :                                            RelationGetDescr(rel),
                              10772                 :                :                                            false);
 1838 alvherre@alvh.no-ip.    10773         [ +  + ]:            484 :             for (int j = 0; j < numfks; j++)
 1579 michael@paquier.xyz     10774                 :            296 :                 mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
                              10775                 :                : 
                              10776                 :                :             /* Check whether an existing constraint can be repurposed */
 1838 alvherre@alvh.no-ip.    10777                 :            188 :             partFKs = copyObject(RelationGetFKeyList(partition));
                              10778                 :            188 :             attached = false;
                              10779   [ +  +  +  +  :            197 :             foreach(cell, partFKs)
                                              +  + ]
                              10780                 :                :             {
                              10781                 :                :                 ForeignKeyCacheInfo *fk;
                              10782                 :                : 
                              10783                 :             15 :                 fk = lfirst_node(ForeignKeyCacheInfo, cell);
                              10784         [ +  + ]:             15 :                 if (tryAttachPartitionForeignKey(fk,
                              10785                 :                :                                                  partitionId,
                              10786                 :                :                                                  parentConstr,
                              10787                 :                :                                                  numfks,
                              10788                 :                :                                                  mapped_fkattnum,
                              10789                 :                :                                                  pkattnum,
                              10790                 :                :                                                  pfeqoperators,
                              10791                 :                :                                                  insertTriggerOid,
                              10792                 :                :                                                  updateTriggerOid,
                              10793                 :                :                                                  trigrel))
                              10794                 :                :                 {
                              10795                 :              6 :                     attached = true;
                              10796                 :              6 :                     break;
                              10797                 :                :                 }
                              10798                 :                :             }
                              10799         [ +  + ]:            188 :             if (attached)
                              10800                 :                :             {
                              10801                 :              6 :                 table_close(partition, NoLock);
                              10802                 :              6 :                 continue;
                              10803                 :                :             }
                              10804                 :                : 
                              10805                 :                :             /*
                              10806                 :                :              * No luck finding a good constraint to reuse; create our own.
                              10807                 :                :              */
                              10808         [ -  + ]:            182 :             if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
                              10809                 :                :                                      RelationGetRelid(partition),
                              10810                 :            182 :                                      fkconstraint->conname))
 1838 alvherre@alvh.no-ip.    10811                 :UBC           0 :                 conname = ChooseConstraintName(RelationGetRelationName(partition),
                              10812                 :              0 :                                                ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
                              10813                 :                :                                                "fkey",
                              10814                 :              0 :                                                RelationGetNamespace(partition), NIL);
                              10815                 :                :             else
 1838 alvherre@alvh.no-ip.    10816                 :CBC         182 :                 conname = fkconstraint->conname;
                              10817                 :                :             constrOid =
                              10818                 :            182 :                 CreateConstraintEntry(conname,
                              10819                 :            182 :                                       RelationGetNamespace(partition),
                              10820                 :                :                                       CONSTRAINT_FOREIGN,
                              10821                 :            182 :                                       fkconstraint->deferrable,
                              10822                 :            182 :                                       fkconstraint->initdeferred,
                              10823                 :            182 :                                       fkconstraint->initially_valid,
                              10824                 :                :                                       parentConstr,
                              10825                 :                :                                       partitionId,
                              10826                 :                :                                       mapped_fkattnum,
                              10827                 :                :                                       numfks,
                              10828                 :                :                                       numfks,
                              10829                 :                :                                       InvalidOid,
                              10830                 :                :                                       indexOid,
                              10831                 :                :                                       RelationGetRelid(pkrel),
                              10832                 :                :                                       pkattnum,
                              10833                 :                :                                       pfeqoperators,
                              10834                 :                :                                       ppeqoperators,
                              10835                 :                :                                       ffeqoperators,
                              10836                 :                :                                       numfks,
                              10837                 :            182 :                                       fkconstraint->fk_upd_action,
                              10838                 :            182 :                                       fkconstraint->fk_del_action,
                              10839                 :                :                                       fkdelsetcols,
                              10840                 :                :                                       numfkdelsetcols,
                              10841                 :            182 :                                       fkconstraint->fk_matchtype,
                              10842                 :                :                                       NULL,
                              10843                 :                :                                       NULL,
                              10844                 :                :                                       NULL,
                              10845                 :                :                                       false,
                              10846                 :                :                                       1,
                              10847                 :                :                                       false,
                              10848                 :                :                                       with_period,  /* conPeriod */
                              10849                 :                :                                       false);
                              10850                 :                : 
                              10851                 :                :             /*
                              10852                 :                :              * Give this constraint partition-type dependencies on the parent
                              10853                 :                :              * constraint as well as the table.
                              10854                 :                :              */
                              10855                 :            182 :             ObjectAddressSet(address, ConstraintRelationId, constrOid);
                              10856                 :            182 :             ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
                              10857                 :            182 :             recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
                              10858                 :            182 :             ObjectAddressSet(referenced, RelationRelationId, partitionId);
                              10859                 :            182 :             recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
                              10860                 :                : 
                              10861                 :                :             /* Make all this visible before recursing */
                              10862                 :            182 :             CommandCounterIncrement();
                              10863                 :                : 
                              10864                 :                :             /* call ourselves to finalize the creation and we're done */
                              10865                 :            182 :             addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
                              10866                 :                :                                     indexOid,
                              10867                 :                :                                     constrOid,
                              10868                 :                :                                     numfks,
                              10869                 :                :                                     pkattnum,
                              10870                 :                :                                     mapped_fkattnum,
                              10871                 :                :                                     pfeqoperators,
                              10872                 :                :                                     ppeqoperators,
                              10873                 :                :                                     ffeqoperators,
                              10874                 :                :                                     numfkdelsetcols,
                              10875                 :                :                                     fkdelsetcols,
                              10876                 :                :                                     old_check_ok,
                              10877                 :                :                                     lockmode,
                              10878                 :                :                                     insertTriggerOid,
                              10879                 :                :                                     updateTriggerOid,
                              10880                 :                :                                     with_period);
                              10881                 :                : 
                              10882                 :            182 :             table_close(partition, NoLock);
                              10883                 :                :         }
                              10884                 :                : 
  830                         10885                 :            206 :         table_close(trigrel, RowExclusiveLock);
                              10886                 :                :     }
 7875 tgl@sss.pgh.pa.us       10887                 :           1373 : }
                              10888                 :                : 
                              10889                 :                : /*
                              10890                 :                :  * CloneForeignKeyConstraints
                              10891                 :                :  *      Clone foreign keys from a partitioned table to a newly acquired
                              10892                 :                :  *      partition.
                              10893                 :                :  *
                              10894                 :                :  * partitionRel is a partition of parentRel, so we can be certain that it has
                              10895                 :                :  * the same columns with the same datatypes.  The columns may be in different
                              10896                 :                :  * order, though.
                              10897                 :                :  *
                              10898                 :                :  * wqueue must be passed to set up phase 3 constraint checking, unless the
                              10899                 :                :  * referencing-side partition is known to be empty (such as in CREATE TABLE /
                              10900                 :                :  * PARTITION OF).
                              10901                 :                :  */
                              10902                 :                : static void
 1838 alvherre@alvh.no-ip.    10903                 :           5081 : CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
                              10904                 :                :                            Relation partitionRel)
                              10905                 :                : {
                              10906                 :                :     /* This only works for declarative partitioning */
                              10907         [ -  + ]:           5081 :     Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                              10908                 :                : 
                              10909                 :                :     /*
                              10910                 :                :      * Clone constraints for which the parent is on the referenced side.
                              10911                 :                :      */
                              10912                 :           5081 :     CloneFkReferenced(parentRel, partitionRel);
                              10913                 :                : 
                              10914                 :                :     /*
                              10915                 :                :      * Now clone constraints where the parent is on the referencing side.
                              10916                 :                :      */
                              10917                 :           5081 :     CloneFkReferencing(wqueue, parentRel, partitionRel);
                              10918                 :           5081 : }
                              10919                 :                : 
                              10920                 :                : /*
                              10921                 :                :  * CloneFkReferenced
                              10922                 :                :  *      Subroutine for CloneForeignKeyConstraints
                              10923                 :                :  *
                              10924                 :                :  * Find all the FKs that have the parent relation on the referenced side;
                              10925                 :                :  * clone those constraints to the given partition.  This is to be called
                              10926                 :                :  * when the partition is being created or attached.
                              10927                 :                :  *
                              10928                 :                :  * This ignores self-referencing FKs; those are handled by CloneFkReferencing.
                              10929                 :                :  *
                              10930                 :                :  * This recurses to partitions, if the relation being attached is partitioned.
                              10931                 :                :  * Recursion is done by calling addFkRecurseReferenced.
                              10932                 :                :  */
                              10933                 :                : static void
                              10934                 :           5081 : CloneFkReferenced(Relation parentRel, Relation partitionRel)
                              10935                 :                : {
                              10936                 :                :     Relation    pg_constraint;
                              10937                 :                :     AttrMap    *attmap;
                              10938                 :                :     ListCell   *cell;
                              10939                 :                :     SysScanDesc scan;
                              10940                 :                :     ScanKeyData key[2];
                              10941                 :                :     HeapTuple   tuple;
 1913                         10942                 :           5081 :     List       *clone = NIL;
                              10943                 :                :     Relation    trigrel;
                              10944                 :                : 
                              10945                 :                :     /*
                              10946                 :                :      * Search for any constraints where this partition's parent is in the
                              10947                 :                :      * referenced side.  However, we must not clone any constraint whose
                              10948                 :                :      * parent constraint is also going to be cloned, to avoid duplicates.  So
                              10949                 :                :      * do it in two steps: first construct the list of constraints to clone,
                              10950                 :                :      * then go over that list cloning those whose parents are not in the list.
                              10951                 :                :      * (We must not rely on the parent being seen first, since the catalog
                              10952                 :                :      * scan could return children first.)
                              10953                 :                :      */
 1910 andres@anarazel.de      10954                 :           5081 :     pg_constraint = table_open(ConstraintRelationId, RowShareLock);
 1838 alvherre@alvh.no-ip.    10955                 :           5081 :     ScanKeyInit(&key[0],
                              10956                 :                :                 Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
                              10957                 :                :                 F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel)));
                              10958                 :           5081 :     ScanKeyInit(&key[1],
                              10959                 :                :                 Anum_pg_constraint_contype, BTEqualStrategyNumber,
                              10960                 :                :                 F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
                              10961                 :                :     /* This is a seqscan, as we don't have a usable index ... */
                              10962                 :           5081 :     scan = systable_beginscan(pg_constraint, InvalidOid, true,
                              10963                 :                :                               NULL, 2, key);
 1913                         10964         [ +  + ]:           5246 :     while ((tuple = systable_getnext(scan)) != NULL)
                              10965                 :                :     {
 1838                         10966                 :            165 :         Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              10967                 :                : 
                              10968                 :            165 :         clone = lappend_oid(clone, constrForm->oid);
                              10969                 :                :     }
 1913                         10970                 :           5081 :     systable_endscan(scan);
 1838                         10971                 :           5081 :     table_close(pg_constraint, RowShareLock);
                              10972                 :                : 
                              10973                 :                :     /*
                              10974                 :                :      * Triggers of the foreign keys will be manipulated a bunch of times in
                              10975                 :                :      * the loop below.  To avoid repeatedly opening/closing the trigger
                              10976                 :                :      * catalog relation, we open it here and pass it to the subroutines called
                              10977                 :                :      * below.
                              10978                 :                :      */
  830                         10979                 :           5081 :     trigrel = table_open(TriggerRelationId, RowExclusiveLock);
                              10980                 :                : 
 1579 michael@paquier.xyz     10981                 :           5081 :     attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
                              10982                 :                :                                    RelationGetDescr(parentRel),
                              10983                 :                :                                    false);
 1838 alvherre@alvh.no-ip.    10984   [ +  +  +  +  :           5246 :     foreach(cell, clone)
                                              +  + ]
                              10985                 :                :     {
                              10986                 :            165 :         Oid         constrOid = lfirst_oid(cell);
                              10987                 :                :         Form_pg_constraint constrForm;
                              10988                 :                :         Relation    fkRel;
                              10989                 :                :         Oid         indexOid;
                              10990                 :                :         Oid         partIndexId;
                              10991                 :                :         int         numfks;
                              10992                 :                :         AttrNumber  conkey[INDEX_MAX_KEYS];
                              10993                 :                :         AttrNumber  mapped_confkey[INDEX_MAX_KEYS];
                              10994                 :                :         AttrNumber  confkey[INDEX_MAX_KEYS];
                              10995                 :                :         Oid         conpfeqop[INDEX_MAX_KEYS];
                              10996                 :                :         Oid         conppeqop[INDEX_MAX_KEYS];
                              10997                 :                :         Oid         conffeqop[INDEX_MAX_KEYS];
                              10998                 :                :         int         numfkdelsetcols;
                              10999                 :                :         AttrNumber  confdelsetcols[INDEX_MAX_KEYS];
                              11000                 :                :         Constraint *fkconstraint;
                              11001                 :                :         Oid         deleteTriggerOid,
                              11002                 :                :                     updateTriggerOid;
                              11003                 :                : 
  269 michael@paquier.xyz     11004                 :GNC         165 :         tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
 1838 alvherre@alvh.no-ip.    11005         [ -  + ]:CBC         165 :         if (!HeapTupleIsValid(tuple))
 1838 alvherre@alvh.no-ip.    11006         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for constraint %u", constrOid);
 1838 alvherre@alvh.no-ip.    11007                 :CBC         165 :         constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              11008                 :                : 
                              11009                 :                :         /*
                              11010                 :                :          * As explained above: don't try to clone a constraint for which we're
                              11011                 :                :          * going to clone the parent.
                              11012                 :                :          */
 1528                         11013         [ +  + ]:            165 :         if (list_member_oid(clone, constrForm->conparentid))
                              11014                 :                :         {
                              11015                 :             63 :             ReleaseSysCache(tuple);
  555                         11016                 :             90 :             continue;
                              11017                 :                :         }
                              11018                 :                : 
                              11019                 :                :         /*
                              11020                 :                :          * Don't clone self-referencing foreign keys, which can be in the
                              11021                 :                :          * partitioned table or in the partition-to-be.
                              11022                 :                :          */
                              11023         [ +  + ]:            102 :         if (constrForm->conrelid == RelationGetRelid(parentRel) ||
                              11024         [ +  + ]:             81 :             constrForm->conrelid == RelationGetRelid(partitionRel))
                              11025                 :                :         {
                              11026                 :             27 :             ReleaseSysCache(tuple);
 1528                         11027                 :             27 :             continue;
                              11028                 :                :         }
                              11029                 :                : 
                              11030                 :                :         /*
                              11031                 :                :          * Because we're only expanding the key space at the referenced side,
                              11032                 :                :          * we don't need to prevent any operation in the referencing table, so
                              11033                 :                :          * AccessShareLock suffices (assumes that dropping the constraint
                              11034                 :                :          * acquires AEL).
                              11035                 :                :          */
 1838                         11036                 :             75 :         fkRel = table_open(constrForm->conrelid, AccessShareLock);
                              11037                 :                : 
                              11038                 :             75 :         indexOid = constrForm->conindid;
                              11039                 :             75 :         DeconstructFkConstraintRow(tuple,
                              11040                 :                :                                    &numfks,
                              11041                 :                :                                    conkey,
                              11042                 :                :                                    confkey,
                              11043                 :                :                                    conpfeqop,
                              11044                 :                :                                    conppeqop,
                              11045                 :                :                                    conffeqop,
                              11046                 :                :                                    &numfkdelsetcols,
                              11047                 :                :                                    confdelsetcols);
                              11048                 :                : 
                              11049         [ +  + ]:            150 :         for (int i = 0; i < numfks; i++)
 1579 michael@paquier.xyz     11050                 :             75 :             mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
                              11051                 :                : 
 1838 alvherre@alvh.no-ip.    11052                 :             75 :         fkconstraint = makeNode(Constraint);
  528                         11053                 :             75 :         fkconstraint->contype = CONSTRAINT_FOREIGN;
 1838                         11054                 :             75 :         fkconstraint->conname = NameStr(constrForm->conname);
                              11055                 :             75 :         fkconstraint->deferrable = constrForm->condeferrable;
                              11056                 :             75 :         fkconstraint->initdeferred = constrForm->condeferred;
  528                         11057                 :             75 :         fkconstraint->location = -1;
                              11058                 :             75 :         fkconstraint->pktable = NULL;
                              11059                 :                :         /* ->fk_attrs determined below */
                              11060                 :             75 :         fkconstraint->pk_attrs = NIL;
 1838                         11061                 :             75 :         fkconstraint->fk_matchtype = constrForm->confmatchtype;
  528                         11062                 :             75 :         fkconstraint->fk_upd_action = constrForm->confupdtype;
                              11063                 :             75 :         fkconstraint->fk_del_action = constrForm->confdeltype;
                              11064                 :             75 :         fkconstraint->fk_del_set_cols = NIL;
                              11065                 :             75 :         fkconstraint->old_conpfeqop = NIL;
                              11066                 :             75 :         fkconstraint->old_pktable_oid = InvalidOid;
                              11067                 :             75 :         fkconstraint->skip_validation = false;
                              11068                 :             75 :         fkconstraint->initially_valid = true;
                              11069                 :                : 
                              11070                 :                :         /* set up colnames that are used to generate the constraint name */
 1838                         11071         [ +  + ]:            150 :         for (int i = 0; i < numfks; i++)
                              11072                 :                :         {
                              11073                 :                :             Form_pg_attribute att;
                              11074                 :                : 
                              11075                 :             75 :             att = TupleDescAttr(RelationGetDescr(fkRel),
                              11076                 :                :                                 conkey[i] - 1);
                              11077                 :             75 :             fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
                              11078                 :             75 :                                              makeString(NameStr(att->attname)));
                              11079                 :                :         }
                              11080                 :                : 
                              11081                 :                :         /*
                              11082                 :                :          * Add the new foreign key constraint pointing to the new partition.
                              11083                 :                :          * Because this new partition appears in the referenced side of the
                              11084                 :                :          * constraint, we don't need to set up for Phase 3 check.
                              11085                 :                :          */
                              11086                 :             75 :         partIndexId = index_get_partition(partitionRel, indexOid);
                              11087         [ -  + ]:             75 :         if (!OidIsValid(partIndexId))
 1838 alvherre@alvh.no-ip.    11088         [ #  # ]:UBC           0 :             elog(ERROR, "index for %u not found in partition %s",
                              11089                 :                :                  indexOid, RelationGetRelationName(partitionRel));
                              11090                 :                : 
                              11091                 :                :         /*
                              11092                 :                :          * Get the "action" triggers belonging to the constraint to pass as
                              11093                 :                :          * parent OIDs for similar triggers that will be created on the
                              11094                 :                :          * partition in addFkRecurseReferenced().
                              11095                 :                :          */
  830 alvherre@alvh.no-ip.    11096                 :CBC          75 :         GetForeignKeyActionTriggers(trigrel, constrOid,
                              11097                 :                :                                     constrForm->confrelid, constrForm->conrelid,
                              11098                 :                :                                     &deleteTriggerOid, &updateTriggerOid);
                              11099                 :                : 
 1838                         11100                 :             75 :         addFkRecurseReferenced(NULL,
                              11101                 :                :                                fkconstraint,
                              11102                 :                :                                fkRel,
                              11103                 :                :                                partitionRel,
                              11104                 :                :                                partIndexId,
                              11105                 :                :                                constrOid,
                              11106                 :                :                                numfks,
                              11107                 :                :                                mapped_confkey,
                              11108                 :                :                                conkey,
                              11109                 :                :                                conpfeqop,
                              11110                 :                :                                conppeqop,
                              11111                 :                :                                conffeqop,
                              11112                 :                :                                numfkdelsetcols,
                              11113                 :                :                                confdelsetcols,
                              11114                 :                :                                true,
                              11115                 :                :                                deleteTriggerOid,
                              11116                 :                :                                updateTriggerOid,
   21 peter@eisentraut.org    11117                 :GNC          75 :                                constrForm->conperiod);
                              11118                 :                : 
 1838 alvherre@alvh.no-ip.    11119                 :CBC          75 :         table_close(fkRel, NoLock);
                              11120                 :             75 :         ReleaseSysCache(tuple);
                              11121                 :                :     }
                              11122                 :                : 
  830                         11123                 :           5081 :     table_close(trigrel, RowExclusiveLock);
 1913                         11124                 :           5081 : }
                              11125                 :                : 
                              11126                 :                : /*
                              11127                 :                :  * CloneFkReferencing
                              11128                 :                :  *      Subroutine for CloneForeignKeyConstraints
                              11129                 :                :  *
                              11130                 :                :  * For each FK constraint of the parent relation in the given list, find an
                              11131                 :                :  * equivalent constraint in its partition relation that can be reparented;
                              11132                 :                :  * if one cannot be found, create a new constraint in the partition as its
                              11133                 :                :  * child.
                              11134                 :                :  *
                              11135                 :                :  * If wqueue is given, it is used to set up phase-3 verification for each
                              11136                 :                :  * cloned constraint; if omitted, we assume that such verification is not
                              11137                 :                :  * needed (example: the partition is being created anew).
                              11138                 :                :  */
                              11139                 :                : static void
 1838                         11140                 :           5081 : CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
                              11141                 :                : {
                              11142                 :                :     AttrMap    *attmap;
                              11143                 :                :     List       *partFKs;
                              11144                 :           5081 :     List       *clone = NIL;
                              11145                 :                :     ListCell   *cell;
                              11146                 :                :     Relation    trigrel;
                              11147                 :                : 
                              11148                 :                :     /* obtain a list of constraints that we need to clone */
                              11149   [ +  +  +  +  :           5529 :     foreach(cell, RelationGetFKeyList(parentRel))
                                              +  + ]
                              11150                 :                :     {
                              11151                 :            448 :         ForeignKeyCacheInfo *fk = lfirst(cell);
                              11152                 :                : 
                              11153                 :            448 :         clone = lappend_oid(clone, fk->conoid);
                              11154                 :                :     }
                              11155                 :                : 
                              11156                 :                :     /*
                              11157                 :                :      * Silently do nothing if there's nothing to do.  In particular, this
                              11158                 :                :      * avoids throwing a spurious error for foreign tables.
                              11159                 :                :      */
                              11160         [ +  + ]:           5081 :     if (clone == NIL)
                              11161                 :           4857 :         return;
                              11162                 :                : 
                              11163         [ -  + ]:            224 :     if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
 1838 alvherre@alvh.no-ip.    11164         [ #  # ]:UBC           0 :         ereport(ERROR,
                              11165                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              11166                 :                :                  errmsg("foreign key constraints are not supported on foreign tables")));
                              11167                 :                : 
                              11168                 :                :     /*
                              11169                 :                :      * Triggers of the foreign keys will be manipulated a bunch of times in
                              11170                 :                :      * the loop below.  To avoid repeatedly opening/closing the trigger
                              11171                 :                :      * catalog relation, we open it here and pass it to the subroutines called
                              11172                 :                :      * below.
                              11173                 :                :      */
  830 alvherre@alvh.no-ip.    11174                 :CBC         224 :     trigrel = table_open(TriggerRelationId, RowExclusiveLock);
                              11175                 :                : 
                              11176                 :                :     /*
                              11177                 :                :      * The constraint key may differ, if the columns in the partition are
                              11178                 :                :      * different.  This map is used to convert them.
                              11179                 :                :      */
 1579 michael@paquier.xyz     11180                 :            224 :     attmap = build_attrmap_by_name(RelationGetDescr(partRel),
                              11181                 :                :                                    RelationGetDescr(parentRel),
                              11182                 :                :                                    false);
                              11183                 :                : 
 1913 alvherre@alvh.no-ip.    11184                 :            224 :     partFKs = copyObject(RelationGetFKeyList(partRel));
                              11185                 :                : 
                              11186   [ +  -  +  +  :            672 :     foreach(cell, clone)
                                              +  + ]
                              11187                 :                :     {
                              11188                 :            448 :         Oid         parentConstrOid = lfirst_oid(cell);
                              11189                 :                :         Form_pg_constraint constrForm;
                              11190                 :                :         Relation    pkrel;
                              11191                 :                :         HeapTuple   tuple;
                              11192                 :                :         int         numfks;
                              11193                 :                :         AttrNumber  conkey[INDEX_MAX_KEYS];
                              11194                 :                :         AttrNumber  mapped_conkey[INDEX_MAX_KEYS];
                              11195                 :                :         AttrNumber  confkey[INDEX_MAX_KEYS];
                              11196                 :                :         Oid         conpfeqop[INDEX_MAX_KEYS];
                              11197                 :                :         Oid         conppeqop[INDEX_MAX_KEYS];
                              11198                 :                :         Oid         conffeqop[INDEX_MAX_KEYS];
                              11199                 :                :         int         numfkdelsetcols;
                              11200                 :                :         AttrNumber  confdelsetcols[INDEX_MAX_KEYS];
                              11201                 :                :         Constraint *fkconstraint;
                              11202                 :                :         bool        attached;
                              11203                 :                :         Oid         indexOid;
                              11204                 :                :         Oid         constrOid;
                              11205                 :                :         ObjectAddress address,
                              11206                 :                :                     referenced;
                              11207                 :                :         ListCell   *lc;
                              11208                 :                :         Oid         insertTriggerOid,
                              11209                 :                :                     updateTriggerOid;
                              11210                 :                :         bool        with_period;
                              11211                 :                : 
  269 michael@paquier.xyz     11212                 :GNC         448 :         tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parentConstrOid));
 1806 tgl@sss.pgh.pa.us       11213         [ -  + ]:CBC         448 :         if (!HeapTupleIsValid(tuple))
 1913 alvherre@alvh.no-ip.    11214         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for constraint %u",
                              11215                 :                :                  parentConstrOid);
 1913 alvherre@alvh.no-ip.    11216                 :CBC         448 :         constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              11217                 :                : 
                              11218                 :                :         /* Don't clone constraints whose parents are being cloned */
 1838                         11219         [ +  + ]:            448 :         if (list_member_oid(clone, constrForm->conparentid))
                              11220                 :                :         {
 1913                         11221                 :            212 :             ReleaseSysCache(tuple);
                              11222                 :            245 :             continue;
                              11223                 :                :         }
                              11224                 :                : 
                              11225                 :                :         /*
                              11226                 :                :          * Need to prevent concurrent deletions.  If pkrel is a partitioned
                              11227                 :                :          * relation, that means to lock all partitions.
                              11228                 :                :          */
 1838                         11229                 :            236 :         pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
                              11230         [ +  + ]:            236 :         if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              11231                 :             92 :             (void) find_all_inheritors(RelationGetRelid(pkrel),
                              11232                 :                :                                        ShareRowExclusiveLock, NULL);
                              11233                 :                : 
 1913                         11234                 :            236 :         DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
                              11235                 :                :                                    conpfeqop, conppeqop, conffeqop,
                              11236                 :                :                                    &numfkdelsetcols, confdelsetcols);
 1838                         11237         [ +  + ]:            541 :         for (int i = 0; i < numfks; i++)
 1579 michael@paquier.xyz     11238                 :            305 :             mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
                              11239                 :                : 
                              11240                 :                :         /*
                              11241                 :                :          * Get the "check" triggers belonging to the constraint to pass as
                              11242                 :                :          * parent OIDs for similar triggers that will be created on the
                              11243                 :                :          * partition in addFkRecurseReferencing().  They are also passed to
                              11244                 :                :          * tryAttachPartitionForeignKey() below to simply assign as parents to
                              11245                 :                :          * the partition's existing "check" triggers, that is, if the
                              11246                 :                :          * corresponding constraints is deemed attachable to the parent
                              11247                 :                :          * constraint.
                              11248                 :                :          */
  830 alvherre@alvh.no-ip.    11249                 :            236 :         GetForeignKeyCheckTriggers(trigrel, constrForm->oid,
                              11250                 :                :                                    constrForm->confrelid, constrForm->conrelid,
                              11251                 :                :                                    &insertTriggerOid, &updateTriggerOid);
                              11252                 :                : 
                              11253                 :                :         /*
                              11254                 :                :          * Before creating a new constraint, see whether any existing FKs are
                              11255                 :                :          * fit for the purpose.  If one is, attach the parent constraint to
                              11256                 :                :          * it, and don't clone anything.  This way we avoid the expensive
                              11257                 :                :          * verification step and don't end up with a duplicate FK, and we
                              11258                 :                :          * don't need to recurse to partitions for this constraint.
                              11259                 :                :          */
 1838                         11260                 :            236 :         attached = false;
  557 drowley@postgresql.o    11261   [ +  +  +  +  :            278 :         foreach(lc, partFKs)
                                              +  + ]
                              11262                 :                :         {
                              11263                 :             75 :             ForeignKeyCacheInfo *fk = lfirst_node(ForeignKeyCacheInfo, lc);
                              11264                 :                : 
 1838 alvherre@alvh.no-ip.    11265         [ +  + ]:             75 :             if (tryAttachPartitionForeignKey(fk,
                              11266                 :                :                                              RelationGetRelid(partRel),
                              11267                 :                :                                              parentConstrOid,
                              11268                 :                :                                              numfks,
                              11269                 :                :                                              mapped_conkey,
                              11270                 :                :                                              confkey,
                              11271                 :                :                                              conpfeqop,
                              11272                 :                :                                              insertTriggerOid,
                              11273                 :                :                                              updateTriggerOid,
                              11274                 :                :                                              trigrel))
                              11275                 :                :             {
                              11276                 :             33 :                 attached = true;
                              11277                 :             33 :                 table_close(pkrel, NoLock);
                              11278                 :             33 :                 break;
                              11279                 :                :             }
                              11280                 :                :         }
                              11281         [ +  + ]:            236 :         if (attached)
                              11282                 :                :         {
 1913                         11283                 :             33 :             ReleaseSysCache(tuple);
                              11284                 :             33 :             continue;
                              11285                 :                :         }
                              11286                 :                : 
                              11287                 :                :         /* No dice.  Set up to create our own constraint */
 1838                         11288                 :            203 :         fkconstraint = makeNode(Constraint);
  528                         11289                 :            203 :         fkconstraint->contype = CONSTRAINT_FOREIGN;
                              11290                 :                :         /* ->conname determined below */
 1838                         11291                 :            203 :         fkconstraint->deferrable = constrForm->condeferrable;
                              11292                 :            203 :         fkconstraint->initdeferred = constrForm->condeferred;
  528                         11293                 :            203 :         fkconstraint->location = -1;
                              11294                 :            203 :         fkconstraint->pktable = NULL;
                              11295                 :                :         /* ->fk_attrs determined below */
                              11296                 :            203 :         fkconstraint->pk_attrs = NIL;
 1838                         11297                 :            203 :         fkconstraint->fk_matchtype = constrForm->confmatchtype;
  528                         11298                 :            203 :         fkconstraint->fk_upd_action = constrForm->confupdtype;
                              11299                 :            203 :         fkconstraint->fk_del_action = constrForm->confdeltype;
                              11300                 :            203 :         fkconstraint->fk_del_set_cols = NIL;
                              11301                 :            203 :         fkconstraint->old_conpfeqop = NIL;
                              11302                 :            203 :         fkconstraint->old_pktable_oid = InvalidOid;
                              11303                 :            203 :         fkconstraint->skip_validation = false;
                              11304                 :            203 :         fkconstraint->initially_valid = true;
 1838                         11305         [ +  + ]:            451 :         for (int i = 0; i < numfks; i++)
                              11306                 :                :         {
                              11307                 :                :             Form_pg_attribute att;
                              11308                 :                : 
                              11309                 :            248 :             att = TupleDescAttr(RelationGetDescr(partRel),
                              11310                 :                :                                 mapped_conkey[i] - 1);
                              11311                 :            248 :             fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
                              11312                 :            248 :                                              makeString(NameStr(att->attname)));
                              11313                 :                :         }
  584                         11314         [ +  + ]:            203 :         if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
                              11315                 :                :                                  RelationGetRelid(partRel),
                              11316                 :            203 :                                  NameStr(constrForm->conname)))
                              11317                 :              3 :             fkconstraint->conname =
                              11318                 :              3 :                 ChooseConstraintName(RelationGetRelationName(partRel),
                              11319                 :              3 :                                      ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
                              11320                 :                :                                      "fkey",
                              11321                 :              3 :                                      RelationGetNamespace(partRel), NIL);
                              11322                 :                :         else
                              11323                 :            200 :             fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
                              11324                 :                : 
 1838                         11325                 :            203 :         indexOid = constrForm->conindid;
   21 peter@eisentraut.org    11326                 :GNC         203 :         with_period = constrForm->conperiod;
                              11327                 :                :         constrOid =
 1838 alvherre@alvh.no-ip.    11328                 :CBC         203 :             CreateConstraintEntry(fkconstraint->conname,
                              11329                 :                :                                   constrForm->connamespace,
                              11330                 :                :                                   CONSTRAINT_FOREIGN,
                              11331                 :            203 :                                   fkconstraint->deferrable,
                              11332                 :            203 :                                   fkconstraint->initdeferred,
 1913                         11333                 :            203 :                                   constrForm->convalidated,
                              11334                 :                :                                   parentConstrOid,
                              11335                 :                :                                   RelationGetRelid(partRel),
                              11336                 :                :                                   mapped_conkey,
                              11337                 :                :                                   numfks,
                              11338                 :                :                                   numfks,
                              11339                 :                :                                   InvalidOid,   /* not a domain constraint */
                              11340                 :                :                                   indexOid,
                              11341                 :                :                                   constrForm->confrelid, /* same foreign rel */
                              11342                 :                :                                   confkey,
                              11343                 :                :                                   conpfeqop,
                              11344                 :                :                                   conppeqop,
                              11345                 :                :                                   conffeqop,
                              11346                 :                :                                   numfks,
 1838                         11347                 :            203 :                                   fkconstraint->fk_upd_action,
                              11348                 :            203 :                                   fkconstraint->fk_del_action,
                              11349                 :                :                                   confdelsetcols,
                              11350                 :                :                                   numfkdelsetcols,
                              11351                 :            203 :                                   fkconstraint->fk_matchtype,
                              11352                 :                :                                   NULL,
                              11353                 :                :                                   NULL,
                              11354                 :                :                                   NULL,
                              11355                 :                :                                   false,    /* islocal */
                              11356                 :                :                                   1,    /* inhcount */
                              11357                 :                :                                   false,    /* conNoInherit */
                              11358                 :                :                                   with_period,  /* conPeriod */
                              11359                 :                :                                   true);
                              11360                 :                : 
                              11361                 :                :         /* Set up partition dependencies for the new constraint */
                              11362                 :            203 :         ObjectAddressSet(address, ConstraintRelationId, constrOid);
                              11363                 :            203 :         ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
                              11364                 :            203 :         recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
                              11365                 :            203 :         ObjectAddressSet(referenced, RelationRelationId,
                              11366                 :                :                          RelationGetRelid(partRel));
                              11367                 :            203 :         recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
                              11368                 :                : 
                              11369                 :                :         /* Done with the cloned constraint's tuple */
                              11370                 :            203 :         ReleaseSysCache(tuple);
                              11371                 :                : 
                              11372                 :                :         /* Make all this visible before recursing */
                              11373                 :            203 :         CommandCounterIncrement();
                              11374                 :                : 
                              11375                 :            203 :         addFkRecurseReferencing(wqueue,
                              11376                 :                :                                 fkconstraint,
                              11377                 :                :                                 partRel,
                              11378                 :                :                                 pkrel,
                              11379                 :                :                                 indexOid,
                              11380                 :                :                                 constrOid,
                              11381                 :                :                                 numfks,
                              11382                 :                :                                 confkey,
                              11383                 :                :                                 mapped_conkey,
                              11384                 :                :                                 conpfeqop,
                              11385                 :                :                                 conppeqop,
                              11386                 :                :                                 conffeqop,
                              11387                 :                :                                 numfkdelsetcols,
                              11388                 :                :                                 confdelsetcols,
                              11389                 :                :                                 false,  /* no old check exists */
                              11390                 :                :                                 AccessExclusiveLock,
                              11391                 :                :                                 insertTriggerOid,
                              11392                 :                :                                 updateTriggerOid,
                              11393                 :                :                                 with_period);
                              11394                 :            203 :         table_close(pkrel, NoLock);
                              11395                 :                :     }
                              11396                 :                : 
  830                         11397                 :            224 :     table_close(trigrel, RowExclusiveLock);
                              11398                 :                : }
                              11399                 :                : 
                              11400                 :                : /*
                              11401                 :                :  * When the parent of a partition receives [the referencing side of] a foreign
                              11402                 :                :  * key, we must propagate that foreign key to the partition.  However, the
                              11403                 :                :  * partition might already have an equivalent foreign key; this routine
                              11404                 :                :  * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined
                              11405                 :                :  * by the other parameters.  If they are equivalent, create the link between
                              11406                 :                :  * the two constraints and return true.
                              11407                 :                :  *
                              11408                 :                :  * If the given FK does not match the one defined by rest of the params,
                              11409                 :                :  * return false.
                              11410                 :                :  */
                              11411                 :                : static bool
 1838                         11412                 :             90 : tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
                              11413                 :                :                              Oid partRelid,
                              11414                 :                :                              Oid parentConstrOid,
                              11415                 :                :                              int numfks,
                              11416                 :                :                              AttrNumber *mapped_conkey,
                              11417                 :                :                              AttrNumber *confkey,
                              11418                 :                :                              Oid *conpfeqop,
                              11419                 :                :                              Oid parentInsTrigger,
                              11420                 :                :                              Oid parentUpdTrigger,
                              11421                 :                :                              Relation trigrel)
                              11422                 :                : {
                              11423                 :                :     HeapTuple   parentConstrTup;
                              11424                 :                :     Form_pg_constraint parentConstr;
                              11425                 :                :     HeapTuple   partcontup;
                              11426                 :                :     Form_pg_constraint partConstr;
                              11427                 :                :     ScanKeyData key;
                              11428                 :                :     SysScanDesc scan;
                              11429                 :                :     HeapTuple   trigtup;
                              11430                 :                :     Oid         insertTriggerOid,
                              11431                 :                :                 updateTriggerOid;
                              11432                 :                : 
                              11433                 :             90 :     parentConstrTup = SearchSysCache1(CONSTROID,
                              11434                 :                :                                       ObjectIdGetDatum(parentConstrOid));
 1806 tgl@sss.pgh.pa.us       11435         [ -  + ]:             90 :     if (!HeapTupleIsValid(parentConstrTup))
 1838 alvherre@alvh.no-ip.    11436         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
 1838 alvherre@alvh.no-ip.    11437                 :CBC          90 :     parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
                              11438                 :                : 
                              11439                 :                :     /*
                              11440                 :                :      * Do some quick & easy initial checks.  If any of these fail, we cannot
                              11441                 :                :      * use this constraint.
                              11442                 :                :      */
                              11443   [ +  -  -  + ]:             90 :     if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks)
                              11444                 :                :     {
 1838 alvherre@alvh.no-ip.    11445                 :UBC           0 :         ReleaseSysCache(parentConstrTup);
                              11446                 :              0 :         return false;
                              11447                 :                :     }
 1838 alvherre@alvh.no-ip.    11448         [ +  + ]:CBC         255 :     for (int i = 0; i < numfks; i++)
                              11449                 :                :     {
                              11450         [ +  - ]:            165 :         if (fk->conkey[i] != mapped_conkey[i] ||
                              11451         [ +  - ]:            165 :             fk->confkey[i] != confkey[i] ||
                              11452         [ -  + ]:            165 :             fk->conpfeqop[i] != conpfeqop[i])
                              11453                 :                :         {
 1838 alvherre@alvh.no-ip.    11454                 :UBC           0 :             ReleaseSysCache(parentConstrTup);
                              11455                 :              0 :             return false;
                              11456                 :                :         }
                              11457                 :                :     }
                              11458                 :                : 
                              11459                 :                :     /*
                              11460                 :                :      * Looks good so far; do some more extensive checks.  Presumably the check
                              11461                 :                :      * for 'convalidated' could be dropped, since we don't really care about
                              11462                 :                :      * that, but let's be careful for now.
                              11463                 :                :      */
 1838 alvherre@alvh.no-ip.    11464                 :CBC          90 :     partcontup = SearchSysCache1(CONSTROID,
                              11465                 :                :                                  ObjectIdGetDatum(fk->conoid));
 1806 tgl@sss.pgh.pa.us       11466         [ -  + ]:             90 :     if (!HeapTupleIsValid(partcontup))
 1806 tgl@sss.pgh.pa.us       11467         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
 1838 alvherre@alvh.no-ip.    11468                 :CBC          90 :     partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
                              11469         [ +  + ]:             90 :     if (OidIsValid(partConstr->conparentid) ||
                              11470         [ +  - ]:             78 :         !partConstr->convalidated ||
                              11471         [ +  + ]:             78 :         partConstr->condeferrable != parentConstr->condeferrable ||
                              11472         [ +  - ]:             64 :         partConstr->condeferred != parentConstr->condeferred ||
                              11473         [ +  + ]:             64 :         partConstr->confupdtype != parentConstr->confupdtype ||
                              11474         [ +  - ]:             46 :         partConstr->confdeltype != parentConstr->confdeltype ||
                              11475         [ +  + ]:             46 :         partConstr->confmatchtype != parentConstr->confmatchtype)
                              11476                 :                :     {
                              11477                 :             51 :         ReleaseSysCache(parentConstrTup);
                              11478                 :             51 :         ReleaseSysCache(partcontup);
                              11479                 :             51 :         return false;
                              11480                 :                :     }
                              11481                 :                : 
                              11482                 :             39 :     ReleaseSysCache(partcontup);
                              11483                 :             39 :     ReleaseSysCache(parentConstrTup);
                              11484                 :                : 
                              11485                 :                :     /*
                              11486                 :                :      * Looks good!  Attach this constraint.  The action triggers in the new
                              11487                 :                :      * partition become redundant -- the parent table already has equivalent
                              11488                 :                :      * ones, and those will be able to reach the partition.  Remove the ones
                              11489                 :                :      * in the partition.  We identify them because they have our constraint
                              11490                 :                :      * OID, as well as being on the referenced rel.
                              11491                 :                :      */
                              11492                 :             39 :     ScanKeyInit(&key,
                              11493                 :                :                 Anum_pg_trigger_tgconstraint,
                              11494                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              11495                 :                :                 ObjectIdGetDatum(fk->conoid));
                              11496                 :             39 :     scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
                              11497                 :                :                               NULL, 1, &key);
                              11498         [ +  + ]:            195 :     while ((trigtup = systable_getnext(scan)) != NULL)
                              11499                 :                :     {
                              11500                 :            156 :         Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
                              11501                 :                :         ObjectAddress trigger;
                              11502                 :                : 
                              11503         [ +  + ]:            156 :         if (trgform->tgconstrrelid != fk->conrelid)
                              11504                 :             78 :             continue;
                              11505         [ -  + ]:             78 :         if (trgform->tgrelid != fk->confrelid)
 1838 alvherre@alvh.no-ip.    11506                 :UBC           0 :             continue;
                              11507                 :                : 
                              11508                 :                :         /*
                              11509                 :                :          * The constraint is originally set up to contain this trigger as an
                              11510                 :                :          * implementation object, so there's a dependency record that links
                              11511                 :                :          * the two; however, since the trigger is no longer needed, we remove
                              11512                 :                :          * the dependency link in order to be able to drop the trigger while
                              11513                 :                :          * keeping the constraint intact.
                              11514                 :                :          */
 1838 alvherre@alvh.no-ip.    11515                 :CBC          78 :         deleteDependencyRecordsFor(TriggerRelationId,
                              11516                 :                :                                    trgform->oid,
                              11517                 :                :                                    false);
                              11518                 :                :         /* make dependency deletion visible to performDeletion */
                              11519                 :             78 :         CommandCounterIncrement();
                              11520                 :             78 :         ObjectAddressSet(trigger, TriggerRelationId,
                              11521                 :                :                          trgform->oid);
                              11522                 :             78 :         performDeletion(&trigger, DROP_RESTRICT, 0);
                              11523                 :                :         /* make trigger drop visible, in case the loop iterates */
                              11524                 :             78 :         CommandCounterIncrement();
                              11525                 :                :     }
                              11526                 :                : 
                              11527                 :             39 :     systable_endscan(scan);
                              11528                 :                : 
                              11529                 :             39 :     ConstraintSetParentConstraint(fk->conoid, parentConstrOid, partRelid);
                              11530                 :                : 
                              11531                 :                :     /*
                              11532                 :                :      * Like the constraint, attach partition's "check" triggers to the
                              11533                 :                :      * corresponding parent triggers.
                              11534                 :                :      */
  830                         11535                 :             39 :     GetForeignKeyCheckTriggers(trigrel,
                              11536                 :                :                                fk->conoid, fk->confrelid, fk->conrelid,
                              11537                 :                :                                &insertTriggerOid, &updateTriggerOid);
                              11538   [ +  -  -  + ]:             39 :     Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger));
                              11539                 :             39 :     TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger,
                              11540                 :                :                             partRelid);
                              11541   [ +  -  -  + ]:             39 :     Assert(OidIsValid(updateTriggerOid) && OidIsValid(parentUpdTrigger));
                              11542                 :             39 :     TriggerSetParentTrigger(trigrel, updateTriggerOid, parentUpdTrigger,
                              11543                 :                :                             partRelid);
                              11544                 :                : 
 1838                         11545                 :             39 :     CommandCounterIncrement();
                              11546                 :             39 :     return true;
                              11547                 :                : }
                              11548                 :                : 
                              11549                 :                : /*
                              11550                 :                :  * GetForeignKeyActionTriggers
                              11551                 :                :  *      Returns delete and update "action" triggers of the given relation
                              11552                 :                :  *      belonging to the given constraint
                              11553                 :                :  */
                              11554                 :                : static void
  830                         11555                 :             75 : GetForeignKeyActionTriggers(Relation trigrel,
                              11556                 :                :                             Oid conoid, Oid confrelid, Oid conrelid,
                              11557                 :                :                             Oid *deleteTriggerOid,
                              11558                 :                :                             Oid *updateTriggerOid)
                              11559                 :                : {
                              11560                 :                :     ScanKeyData key;
                              11561                 :                :     SysScanDesc scan;
                              11562                 :                :     HeapTuple   trigtup;
                              11563                 :                : 
                              11564                 :             75 :     *deleteTriggerOid = *updateTriggerOid = InvalidOid;
                              11565                 :             75 :     ScanKeyInit(&key,
                              11566                 :                :                 Anum_pg_trigger_tgconstraint,
                              11567                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              11568                 :                :                 ObjectIdGetDatum(conoid));
                              11569                 :                : 
                              11570                 :             75 :     scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
                              11571                 :                :                               NULL, 1, &key);
                              11572         [ +  + ]:            345 :     while ((trigtup = systable_getnext(scan)) != NULL)
                              11573                 :                :     {
                              11574                 :            270 :         Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
                              11575                 :                : 
                              11576         [ +  + ]:            270 :         if (trgform->tgconstrrelid != conrelid)
                              11577                 :            120 :             continue;
                              11578         [ -  + ]:            150 :         if (trgform->tgrelid != confrelid)
  830 alvherre@alvh.no-ip.    11579                 :UBC           0 :             continue;
                              11580                 :                :         /* Only ever look at "action" triggers on the PK side. */
  583 alvherre@alvh.no-ip.    11581         [ -  + ]:CBC         150 :         if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK)
  583 alvherre@alvh.no-ip.    11582                 :UBC           0 :             continue;
  830 alvherre@alvh.no-ip.    11583         [ +  + ]:CBC         150 :         if (TRIGGER_FOR_DELETE(trgform->tgtype))
                              11584                 :                :         {
                              11585         [ -  + ]:             75 :             Assert(*deleteTriggerOid == InvalidOid);
                              11586                 :             75 :             *deleteTriggerOid = trgform->oid;
                              11587                 :                :         }
                              11588         [ +  - ]:             75 :         else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
                              11589                 :                :         {
                              11590         [ -  + ]:             75 :             Assert(*updateTriggerOid == InvalidOid);
                              11591                 :             75 :             *updateTriggerOid = trgform->oid;
                              11592                 :                :         }
                              11593                 :                : #ifndef USE_ASSERT_CHECKING
                              11594                 :                :         /* In an assert-enabled build, continue looking to find duplicates */
                              11595                 :                :         if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid))
                              11596                 :                :             break;
                              11597                 :                : #endif
                              11598                 :                :     }
                              11599                 :                : 
                              11600         [ -  + ]:             75 :     if (!OidIsValid(*deleteTriggerOid))
  830 alvherre@alvh.no-ip.    11601         [ #  # ]:UBC           0 :         elog(ERROR, "could not find ON DELETE action trigger of foreign key constraint %u",
                              11602                 :                :              conoid);
  830 alvherre@alvh.no-ip.    11603         [ -  + ]:CBC          75 :     if (!OidIsValid(*updateTriggerOid))
  830 alvherre@alvh.no-ip.    11604         [ #  # ]:UBC           0 :         elog(ERROR, "could not find ON UPDATE action trigger of foreign key constraint %u",
                              11605                 :                :              conoid);
                              11606                 :                : 
  830 alvherre@alvh.no-ip.    11607                 :CBC          75 :     systable_endscan(scan);
                              11608                 :             75 : }
                              11609                 :                : 
                              11610                 :                : /*
                              11611                 :                :  * GetForeignKeyCheckTriggers
                              11612                 :                :  *      Returns insert and update "check" triggers of the given relation
                              11613                 :                :  *      belonging to the given constraint
                              11614                 :                :  */
                              11615                 :                : static void
                              11616                 :            308 : GetForeignKeyCheckTriggers(Relation trigrel,
                              11617                 :                :                            Oid conoid, Oid confrelid, Oid conrelid,
                              11618                 :                :                            Oid *insertTriggerOid,
                              11619                 :                :                            Oid *updateTriggerOid)
                              11620                 :                : {
                              11621                 :                :     ScanKeyData key;
                              11622                 :                :     SysScanDesc scan;
                              11623                 :                :     HeapTuple   trigtup;
                              11624                 :                : 
                              11625                 :            308 :     *insertTriggerOid = *updateTriggerOid = InvalidOid;
                              11626                 :            308 :     ScanKeyInit(&key,
                              11627                 :                :                 Anum_pg_trigger_tgconstraint,
                              11628                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              11629                 :                :                 ObjectIdGetDatum(conoid));
                              11630                 :                : 
                              11631                 :            308 :     scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
                              11632                 :                :                               NULL, 1, &key);
                              11633         [ +  + ]:           1348 :     while ((trigtup = systable_getnext(scan)) != NULL)
                              11634                 :                :     {
                              11635                 :           1040 :         Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
                              11636                 :                : 
                              11637         [ +  + ]:           1040 :         if (trgform->tgconstrrelid != confrelid)
                              11638                 :            382 :             continue;
                              11639         [ -  + ]:            658 :         if (trgform->tgrelid != conrelid)
  830 alvherre@alvh.no-ip.    11640                 :UBC           0 :             continue;
                              11641                 :                :         /* Only ever look at "check" triggers on the FK side. */
  583 alvherre@alvh.no-ip.    11642         [ +  + ]:CBC         658 :         if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK)
                              11643                 :             42 :             continue;
  830                         11644         [ +  + ]:            616 :         if (TRIGGER_FOR_INSERT(trgform->tgtype))
                              11645                 :                :         {
                              11646         [ -  + ]:            308 :             Assert(*insertTriggerOid == InvalidOid);
                              11647                 :            308 :             *insertTriggerOid = trgform->oid;
                              11648                 :                :         }
                              11649         [ +  - ]:            308 :         else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
                              11650                 :                :         {
                              11651         [ -  + ]:            308 :             Assert(*updateTriggerOid == InvalidOid);
                              11652                 :            308 :             *updateTriggerOid = trgform->oid;
                              11653                 :                :         }
                              11654                 :                : #ifndef USE_ASSERT_CHECKING
                              11655                 :                :         /* In an assert-enabled build, continue looking to find duplicates. */
                              11656                 :                :         if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid))
                              11657                 :                :             break;
                              11658                 :                : #endif
                              11659                 :                :     }
                              11660                 :                : 
                              11661         [ -  + ]:            308 :     if (!OidIsValid(*insertTriggerOid))
  830 alvherre@alvh.no-ip.    11662         [ #  # ]:UBC           0 :         elog(ERROR, "could not find ON INSERT check triggers of foreign key constraint %u",
                              11663                 :                :              conoid);
  830 alvherre@alvh.no-ip.    11664         [ -  + ]:CBC         308 :     if (!OidIsValid(*updateTriggerOid))
  830 alvherre@alvh.no-ip.    11665         [ #  # ]:UBC           0 :         elog(ERROR, "could not find ON UPDATE check triggers of foreign key constraint %u",
                              11666                 :                :              conoid);
                              11667                 :                : 
  830 alvherre@alvh.no-ip.    11668                 :CBC         308 :     systable_endscan(scan);
                              11669                 :            308 : }
                              11670                 :                : 
                              11671                 :                : /*
                              11672                 :                :  * ALTER TABLE ALTER CONSTRAINT
                              11673                 :                :  *
                              11674                 :                :  * Update the attributes of a constraint.
                              11675                 :                :  *
                              11676                 :                :  * Currently only works for Foreign Key constraints.
                              11677                 :                :  *
                              11678                 :                :  * If the constraint is modified, returns its address; otherwise, return
                              11679                 :                :  * InvalidObjectAddress.
                              11680                 :                :  */
                              11681                 :                : static ObjectAddress
 1075                         11682                 :             63 : ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
                              11683                 :                :                       bool recursing, LOCKMODE lockmode)
                              11684                 :                : {
                              11685                 :                :     Constraint *cmdcon;
                              11686                 :                :     Relation    conrel;
                              11687                 :                :     Relation    tgrel;
                              11688                 :                :     SysScanDesc scan;
                              11689                 :                :     ScanKeyData skey[3];
                              11690                 :                :     HeapTuple   contuple;
                              11691                 :                :     Form_pg_constraint currcon;
                              11692                 :                :     ObjectAddress address;
                              11693                 :             63 :     List       *otherrelids = NIL;
                              11694                 :                :     ListCell   *lc;
                              11695                 :                : 
 2635 andres@anarazel.de      11696                 :             63 :     cmdcon = castNode(Constraint, cmd->def);
                              11697                 :                : 
 1910                         11698                 :             63 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
 1075 alvherre@alvh.no-ip.    11699                 :             63 :     tgrel = table_open(TriggerRelationId, RowExclusiveLock);
                              11700                 :                : 
                              11701                 :                :     /*
                              11702                 :                :      * Find and check the target constraint
                              11703                 :                :      */
 2049 tgl@sss.pgh.pa.us       11704                 :             63 :     ScanKeyInit(&skey[0],
                              11705                 :                :                 Anum_pg_constraint_conrelid,
                              11706                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              11707                 :                :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                              11708                 :             63 :     ScanKeyInit(&skey[1],
                              11709                 :                :                 Anum_pg_constraint_contypid,
                              11710                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              11711                 :                :                 ObjectIdGetDatum(InvalidOid));
                              11712                 :             63 :     ScanKeyInit(&skey[2],
                              11713                 :                :                 Anum_pg_constraint_conname,
                              11714                 :                :                 BTEqualStrategyNumber, F_NAMEEQ,
                              11715                 :             63 :                 CStringGetDatum(cmdcon->conname));
                              11716                 :             63 :     scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
                              11717                 :                :                               true, NULL, 3, skey);
                              11718                 :                : 
                              11719                 :                :     /* There can be at most one matching row */
                              11720         [ -  + ]:             63 :     if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
 3942 simon@2ndQuadrant.co    11721         [ #  # ]:UBC           0 :         ereport(ERROR,
                              11722                 :                :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              11723                 :                :                  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
                              11724                 :                :                         cmdcon->conname, RelationGetRelationName(rel))));
                              11725                 :                : 
 2049 tgl@sss.pgh.pa.us       11726                 :CBC          63 :     currcon = (Form_pg_constraint) GETSTRUCT(contuple);
 3942 simon@2ndQuadrant.co    11727         [ -  + ]:             63 :     if (currcon->contype != CONSTRAINT_FOREIGN)
 3942 simon@2ndQuadrant.co    11728         [ #  # ]:UBC           0 :         ereport(ERROR,
                              11729                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              11730                 :                :                  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
                              11731                 :                :                         cmdcon->conname, RelationGetRelationName(rel))));
                              11732                 :                : 
                              11733                 :                :     /*
                              11734                 :                :      * If it's not the topmost constraint, raise an error.
                              11735                 :                :      *
                              11736                 :                :      * Altering a non-topmost constraint leaves some triggers untouched, since
                              11737                 :                :      * they are not directly connected to this constraint; also, pg_dump would
                              11738                 :                :      * ignore the deferrability status of the individual constraint, since it
                              11739                 :                :      * only dumps topmost constraints.  Avoid these problems by refusing this
                              11740                 :                :      * operation and telling the user to alter the parent constraint instead.
                              11741                 :                :      */
 1075 alvherre@alvh.no-ip.    11742         [ +  + ]:CBC          63 :     if (OidIsValid(currcon->conparentid))
                              11743                 :                :     {
                              11744                 :                :         HeapTuple   tp;
                              11745                 :              6 :         Oid         parent = currcon->conparentid;
                              11746                 :              6 :         char       *ancestorname = NULL;
                              11747                 :              6 :         char       *ancestortable = NULL;
                              11748                 :                : 
                              11749                 :                :         /* Loop to find the topmost constraint */
                              11750         [ +  - ]:             12 :         while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
                              11751                 :                :         {
                              11752                 :             12 :             Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
                              11753                 :                : 
                              11754                 :                :             /* If no parent, this is the constraint we want */
                              11755         [ +  + ]:             12 :             if (!OidIsValid(contup->conparentid))
                              11756                 :                :             {
                              11757                 :              6 :                 ancestorname = pstrdup(NameStr(contup->conname));
                              11758                 :              6 :                 ancestortable = get_rel_name(contup->conrelid);
                              11759                 :              6 :                 ReleaseSysCache(tp);
                              11760                 :              6 :                 break;
                              11761                 :                :             }
                              11762                 :                : 
                              11763                 :              6 :             parent = contup->conparentid;
                              11764                 :              6 :             ReleaseSysCache(tp);
                              11765                 :                :         }
                              11766                 :                : 
                              11767   [ +  -  +  -  :              6 :         ereport(ERROR,
                                              +  - ]
                              11768                 :                :                 (errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
                              11769                 :                :                         cmdcon->conname, RelationGetRelationName(rel)),
                              11770                 :                :                  ancestorname && ancestortable ?
                              11771                 :                :                  errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
                              11772                 :                :                            cmdcon->conname, ancestorname, ancestortable) : 0,
                              11773                 :                :                  errhint("You may alter the constraint it derives from instead.")));
                              11774                 :                :     }
                              11775                 :                : 
                              11776                 :                :     /*
                              11777                 :                :      * Do the actual catalog work.  We can skip changing if already in the
                              11778                 :                :      * desired state, but not if a partitioned table: partitions need to be
                              11779                 :                :      * processed regardless, in case they had the constraint locally changed.
                              11780                 :                :      */
                              11781                 :             57 :     address = InvalidObjectAddress;
                              11782         [ +  + ]:             57 :     if (currcon->condeferrable != cmdcon->deferrable ||
                              11783         [ -  + ]:              3 :         currcon->condeferred != cmdcon->initdeferred ||
 1075 alvherre@alvh.no-ip.    11784         [ #  # ]:UBC           0 :         rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              11785                 :                :     {
 1075 alvherre@alvh.no-ip.    11786         [ +  - ]:CBC          57 :         if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
                              11787                 :                :                                      &otherrelids, lockmode))
                              11788                 :             57 :             ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
                              11789                 :                :     }
                              11790                 :                : 
                              11791                 :                :     /*
                              11792                 :                :      * ATExecAlterConstrRecurse already invalidated relcache for the relations
                              11793                 :                :      * having the constraint itself; here we also invalidate for relations
                              11794                 :                :      * that have any triggers that are part of the constraint.
                              11795                 :                :      */
                              11796   [ +  -  +  +  :            129 :     foreach(lc, otherrelids)
                                              +  + ]
                              11797                 :             72 :         CacheInvalidateRelcacheByRelid(lfirst_oid(lc));
                              11798                 :                : 
                              11799                 :             57 :     systable_endscan(scan);
                              11800                 :                : 
                              11801                 :             57 :     table_close(tgrel, RowExclusiveLock);
                              11802                 :             57 :     table_close(conrel, RowExclusiveLock);
                              11803                 :                : 
                              11804                 :             57 :     return address;
                              11805                 :                : }
                              11806                 :                : 
                              11807                 :                : /*
                              11808                 :                :  * Recursive subroutine of ATExecAlterConstraint.  Returns true if the
                              11809                 :                :  * constraint is altered.
                              11810                 :                :  *
                              11811                 :                :  * *otherrelids is appended OIDs of relations containing affected triggers.
                              11812                 :                :  *
                              11813                 :                :  * Note that we must recurse even when the values are correct, in case
                              11814                 :                :  * indirect descendants have had their constraints altered locally.
                              11815                 :                :  * (This could be avoided if we forbade altering constraints in partitions
                              11816                 :                :  * but existing releases don't do that.)
                              11817                 :                :  */
                              11818                 :                : static bool
                              11819                 :             90 : ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
                              11820                 :                :                          Relation rel, HeapTuple contuple, List **otherrelids,
                              11821                 :                :                          LOCKMODE lockmode)
                              11822                 :                : {
                              11823                 :                :     Form_pg_constraint currcon;
                              11824                 :                :     Oid         conoid;
                              11825                 :                :     Oid         refrelid;
                              11826                 :             90 :     bool        changed = false;
                              11827                 :                : 
                              11828                 :                :     /* since this function recurses, it could be driven to stack overflow */
   58 akorotkov@postgresql    11829                 :             90 :     check_stack_depth();
                              11830                 :                : 
 1075 alvherre@alvh.no-ip.    11831                 :             90 :     currcon = (Form_pg_constraint) GETSTRUCT(contuple);
                              11832                 :             90 :     conoid = currcon->oid;
                              11833                 :             90 :     refrelid = currcon->confrelid;
                              11834                 :                : 
                              11835                 :                :     /*
                              11836                 :                :      * Update pg_constraint with the flags from cmdcon.
                              11837                 :                :      *
                              11838                 :                :      * If called to modify a constraint that's already in the desired state,
                              11839                 :                :      * silently do nothing.
                              11840                 :                :      */
 3942 simon@2ndQuadrant.co    11841         [ +  + ]:             90 :     if (currcon->condeferrable != cmdcon->deferrable ||
                              11842         [ +  - ]:              3 :         currcon->condeferred != cmdcon->initdeferred)
                              11843                 :                :     {
                              11844                 :                :         HeapTuple   copyTuple;
                              11845                 :                :         Form_pg_constraint copy_con;
                              11846                 :                :         HeapTuple   tgtuple;
                              11847                 :                :         ScanKeyData tgkey;
                              11848                 :                :         SysScanDesc tgscan;
                              11849                 :                : 
                              11850                 :             90 :         copyTuple = heap_copytuple(contuple);
                              11851                 :             90 :         copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
                              11852                 :             90 :         copy_con->condeferrable = cmdcon->deferrable;
                              11853                 :             90 :         copy_con->condeferred = cmdcon->initdeferred;
 2630 alvherre@alvh.no-ip.    11854                 :             90 :         CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
                              11855                 :                : 
 3942 simon@2ndQuadrant.co    11856         [ -  + ]:             90 :         InvokeObjectPostAlterHook(ConstraintRelationId,
                              11857                 :                :                                   conoid, 0);
                              11858                 :                : 
                              11859                 :             90 :         heap_freetuple(copyTuple);
 1075 alvherre@alvh.no-ip.    11860                 :             90 :         changed = true;
                              11861                 :                : 
                              11862                 :                :         /* Make new constraint flags visible to others */
                              11863                 :             90 :         CacheInvalidateRelcache(rel);
                              11864                 :                : 
                              11865                 :                :         /*
                              11866                 :                :          * Now we need to update the multiple entries in pg_trigger that
                              11867                 :                :          * implement the constraint.
                              11868                 :                :          */
 3942 simon@2ndQuadrant.co    11869                 :             90 :         ScanKeyInit(&tgkey,
                              11870                 :                :                     Anum_pg_trigger_tgconstraint,
                              11871                 :                :                     BTEqualStrategyNumber, F_OIDEQ,
                              11872                 :                :                     ObjectIdGetDatum(conoid));
                              11873                 :             90 :         tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
                              11874                 :                :                                     NULL, 1, &tgkey);
                              11875         [ +  + ]:            384 :         while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
                              11876                 :                :         {
 2727 tgl@sss.pgh.pa.us       11877                 :            294 :             Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
                              11878                 :                :             Form_pg_trigger copy_tg;
                              11879                 :                :             HeapTuple   tgCopyTuple;
                              11880                 :                : 
                              11881                 :                :             /*
                              11882                 :                :              * Remember OIDs of other relation(s) involved in FK constraint.
                              11883                 :                :              * (Note: it's likely that we could skip forcing a relcache inval
                              11884                 :                :              * for other rels that don't have a trigger whose properties
                              11885                 :                :              * change, but let's be conservative.)
                              11886                 :                :              */
                              11887         [ +  + ]:            294 :             if (tgform->tgrelid != RelationGetRelid(rel))
 1075 alvherre@alvh.no-ip.    11888                 :            144 :                 *otherrelids = list_append_unique_oid(*otherrelids,
                              11889                 :                :                                                       tgform->tgrelid);
                              11890                 :                : 
                              11891                 :                :             /*
                              11892                 :                :              * Update deferrability of RI_FKey_noaction_del,
                              11893                 :                :              * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
                              11894                 :                :              * triggers, but not others; see createForeignKeyActionTriggers
                              11895                 :                :              * and CreateFKCheckTrigger.
                              11896                 :                :              */
 2727 tgl@sss.pgh.pa.us       11897         [ +  + ]:            294 :             if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
                              11898         [ +  + ]:            237 :                 tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
                              11899         [ +  + ]:            171 :                 tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
                              11900         [ +  + ]:             96 :                 tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
                              11901                 :             21 :                 continue;
                              11902                 :                : 
  557 drowley@postgresql.o    11903                 :            273 :             tgCopyTuple = heap_copytuple(tgtuple);
                              11904                 :            273 :             copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple);
                              11905                 :                : 
 3942 simon@2ndQuadrant.co    11906                 :            273 :             copy_tg->tgdeferrable = cmdcon->deferrable;
                              11907                 :            273 :             copy_tg->tginitdeferred = cmdcon->initdeferred;
  557 drowley@postgresql.o    11908                 :            273 :             CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple);
                              11909                 :                : 
 1076 alvherre@alvh.no-ip.    11910         [ -  + ]:            273 :             InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
                              11911                 :                : 
  557 drowley@postgresql.o    11912                 :            273 :             heap_freetuple(tgCopyTuple);
                              11913                 :                :         }
                              11914                 :                : 
 3942 simon@2ndQuadrant.co    11915                 :             90 :         systable_endscan(tgscan);
                              11916                 :                :     }
                              11917                 :                : 
                              11918                 :                :     /*
                              11919                 :                :      * If the table at either end of the constraint is partitioned, we need to
                              11920                 :                :      * recurse and handle every constraint that is a child of this one.
                              11921                 :                :      *
                              11922                 :                :      * (This assumes that the recurse flag is forcibly set for partitioned
                              11923                 :                :      * tables, and not set for legacy inheritance, though we don't check for
                              11924                 :                :      * that here.)
                              11925                 :                :      */
 1075 alvherre@alvh.no-ip.    11926   [ +  +  +  + ]:            168 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
                              11927                 :             78 :         get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
                              11928                 :                :     {
                              11929                 :                :         ScanKeyData pkey;
                              11930                 :                :         SysScanDesc pscan;
                              11931                 :                :         HeapTuple   childtup;
                              11932                 :                : 
                              11933                 :             21 :         ScanKeyInit(&pkey,
                              11934                 :                :                     Anum_pg_constraint_conparentid,
                              11935                 :                :                     BTEqualStrategyNumber, F_OIDEQ,
                              11936                 :                :                     ObjectIdGetDatum(conoid));
                              11937                 :                : 
                              11938                 :             21 :         pscan = systable_beginscan(conrel, ConstraintParentIndexId,
                              11939                 :                :                                    true, NULL, 1, &pkey);
                              11940                 :                : 
                              11941         [ +  + ]:             54 :         while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
                              11942                 :                :         {
                              11943                 :             33 :             Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
                              11944                 :                :             Relation    childrel;
                              11945                 :                : 
                              11946                 :             33 :             childrel = table_open(childcon->conrelid, lockmode);
                              11947                 :             33 :             ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
                              11948                 :                :                                      otherrelids, lockmode);
                              11949                 :             33 :             table_close(childrel, NoLock);
                              11950                 :                :         }
                              11951                 :                : 
                              11952                 :             21 :         systable_endscan(pscan);
                              11953                 :                :     }
                              11954                 :                : 
                              11955                 :             90 :     return changed;
                              11956                 :                : }
                              11957                 :                : 
                              11958                 :                : /*
                              11959                 :                :  * ALTER TABLE VALIDATE CONSTRAINT
                              11960                 :                :  *
                              11961                 :                :  * XXX The reason we handle recursion here rather than at Phase 1 is because
                              11962                 :                :  * there's no good way to skip recursing when handling foreign keys: there is
                              11963                 :                :  * no need to lock children in that case, yet we wouldn't be able to avoid
                              11964                 :                :  * doing so at that level.
                              11965                 :                :  *
                              11966                 :                :  * Return value is the address of the validated constraint.  If the constraint
                              11967                 :                :  * was already validated, InvalidObjectAddress is returned.
                              11968                 :                :  */
                              11969                 :                : static ObjectAddress
 1370 drowley@postgresql.o    11970                 :            218 : ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
                              11971                 :                :                          bool recurse, bool recursing, LOCKMODE lockmode)
                              11972                 :                : {
                              11973                 :                :     Relation    conrel;
                              11974                 :                :     SysScanDesc scan;
                              11975                 :                :     ScanKeyData skey[3];
                              11976                 :                :     HeapTuple   tuple;
                              11977                 :                :     Form_pg_constraint con;
                              11978                 :                :     ObjectAddress address;
                              11979                 :                : 
 1910 andres@anarazel.de      11980                 :            218 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
                              11981                 :                : 
                              11982                 :                :     /*
                              11983                 :                :      * Find and check the target constraint
                              11984                 :                :      */
 2049 tgl@sss.pgh.pa.us       11985                 :            218 :     ScanKeyInit(&skey[0],
                              11986                 :                :                 Anum_pg_constraint_conrelid,
                              11987                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              11988                 :                :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                              11989                 :            218 :     ScanKeyInit(&skey[1],
                              11990                 :                :                 Anum_pg_constraint_contypid,
                              11991                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              11992                 :                :                 ObjectIdGetDatum(InvalidOid));
                              11993                 :            218 :     ScanKeyInit(&skey[2],
                              11994                 :                :                 Anum_pg_constraint_conname,
                              11995                 :                :                 BTEqualStrategyNumber, F_NAMEEQ,
                              11996                 :                :                 CStringGetDatum(constrName));
                              11997                 :            218 :     scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
                              11998                 :                :                               true, NULL, 3, skey);
                              11999                 :                : 
                              12000                 :                :     /* There can be at most one matching row */
                              12001         [ -  + ]:            218 :     if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
 4814 tgl@sss.pgh.pa.us       12002         [ #  # ]:UBC           0 :         ereport(ERROR,
                              12003                 :                :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              12004                 :                :                  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
                              12005                 :                :                         constrName, RelationGetRelationName(rel))));
                              12006                 :                : 
 2049 tgl@sss.pgh.pa.us       12007                 :CBC         218 :     con = (Form_pg_constraint) GETSTRUCT(tuple);
 4701 alvherre@alvh.no-ip.    12008         [ +  + ]:            218 :     if (con->contype != CONSTRAINT_FOREIGN &&
                              12009         [ -  + ]:             66 :         con->contype != CONSTRAINT_CHECK)
 4701 alvherre@alvh.no-ip.    12010         [ #  # ]:UBC           0 :         ereport(ERROR,
                              12011                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              12012                 :                :                  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
                              12013                 :                :                         constrName, RelationGetRelationName(rel))));
                              12014                 :                : 
 4814 tgl@sss.pgh.pa.us       12015         [ +  + ]:CBC         218 :     if (!con->convalidated)
                              12016                 :                :     {
                              12017                 :                :         AlteredTableInfo *tab;
                              12018                 :                :         HeapTuple   copyTuple;
                              12019                 :                :         Form_pg_constraint copy_con;
                              12020                 :                : 
 4701 alvherre@alvh.no-ip.    12021         [ +  + ]:            209 :         if (con->contype == CONSTRAINT_FOREIGN)
                              12022                 :                :         {
                              12023                 :                :             NewConstraint *newcon;
                              12024                 :                :             Constraint *fkconstraint;
                              12025                 :                : 
                              12026                 :                :             /* Queue validation for phase 3 */
 1370 drowley@postgresql.o    12027                 :            149 :             fkconstraint = makeNode(Constraint);
                              12028                 :                :             /* for now this is all we need */
                              12029                 :            149 :             fkconstraint->conname = constrName;
                              12030                 :                : 
                              12031                 :            149 :             newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
                              12032                 :            149 :             newcon->name = constrName;
                              12033                 :            149 :             newcon->contype = CONSTR_FOREIGN;
                              12034                 :            149 :             newcon->refrelid = con->confrelid;
                              12035                 :            149 :             newcon->refindid = con->conindid;
                              12036                 :            149 :             newcon->conid = con->oid;
                              12037                 :            149 :             newcon->qual = (Node *) fkconstraint;
                              12038                 :                : 
                              12039                 :                :             /* Find or create work queue entry for this table */
                              12040                 :            149 :             tab = ATGetQueueEntry(wqueue, rel);
                              12041                 :            149 :             tab->constraints = lappend(tab->constraints, newcon);
                              12042                 :                : 
                              12043                 :                :             /*
                              12044                 :                :              * We disallow creating invalid foreign keys to or from
                              12045                 :                :              * partitioned tables, so ignoring the recursion bit is okay.
                              12046                 :                :              */
                              12047                 :                :         }
 4701 alvherre@alvh.no-ip.    12048         [ +  - ]:             60 :         else if (con->contype == CONSTRAINT_CHECK)
                              12049                 :                :         {
                              12050                 :             60 :             List       *children = NIL;
                              12051                 :                :             ListCell   *child;
                              12052                 :                :             NewConstraint *newcon;
                              12053                 :                :             Datum       val;
                              12054                 :                :             char       *conbin;
                              12055                 :                : 
                              12056                 :                :             /*
                              12057                 :                :              * If we're recursing, the parent has already done this, so skip
                              12058                 :                :              * it.  Also, if the constraint is a NO INHERIT constraint, we
                              12059                 :                :              * shouldn't try to look for it in the children.
                              12060                 :                :              */
 2543 rhaas@postgresql.org    12061   [ +  +  +  + ]:             60 :             if (!recursing && !con->connoinherit)
 4701 alvherre@alvh.no-ip.    12062                 :             33 :                 children = find_all_inheritors(RelationGetRelid(rel),
                              12063                 :                :                                                lockmode, NULL);
                              12064                 :                : 
                              12065                 :                :             /*
                              12066                 :                :              * For CHECK constraints, we must ensure that we only mark the
                              12067                 :                :              * constraint as validated on the parent if it's already validated
                              12068                 :                :              * on the children.
                              12069                 :                :              *
                              12070                 :                :              * We recurse before validating on the parent, to reduce risk of
                              12071                 :                :              * deadlocks.
                              12072                 :                :              */
                              12073   [ +  +  +  +  :            117 :             foreach(child, children)
                                              +  + ]
                              12074                 :                :             {
 4326 bruce@momjian.us        12075                 :             57 :                 Oid         childoid = lfirst_oid(child);
                              12076                 :                :                 Relation    childrel;
                              12077                 :                : 
 4701 alvherre@alvh.no-ip.    12078         [ +  + ]:             57 :                 if (childoid == RelationGetRelid(rel))
                              12079                 :             33 :                     continue;
                              12080                 :                : 
                              12081                 :                :                 /*
                              12082                 :                :                  * If we are told not to recurse, there had better not be any
                              12083                 :                :                  * child tables, because we can't mark the constraint on the
                              12084                 :                :                  * parent valid unless it is valid for all child tables.
                              12085                 :                :                  */
                              12086         [ -  + ]:             24 :                 if (!recurse)
 4701 alvherre@alvh.no-ip.    12087         [ #  # ]:UBC           0 :                     ereport(ERROR,
                              12088                 :                :                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              12089                 :                :                              errmsg("constraint must be validated on child tables too")));
                              12090                 :                : 
                              12091                 :                :                 /* find_all_inheritors already got lock */
 1910 andres@anarazel.de      12092                 :CBC          24 :                 childrel = table_open(childoid, NoLock);
                              12093                 :                : 
 1370 drowley@postgresql.o    12094                 :             24 :                 ATExecValidateConstraint(wqueue, childrel, constrName, false,
                              12095                 :                :                                          true, lockmode);
 1910 andres@anarazel.de      12096                 :             24 :                 table_close(childrel, NoLock);
                              12097                 :                :             }
                              12098                 :                : 
                              12099                 :                :             /* Queue validation for phase 3 */
 1370 drowley@postgresql.o    12100                 :             60 :             newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
                              12101                 :             60 :             newcon->name = constrName;
                              12102                 :             60 :             newcon->contype = CONSTR_CHECK;
                              12103                 :             60 :             newcon->refrelid = InvalidOid;
                              12104                 :             60 :             newcon->refindid = InvalidOid;
                              12105                 :             60 :             newcon->conid = con->oid;
                              12106                 :                : 
  386 dgustafsson@postgres    12107                 :             60 :             val = SysCacheGetAttrNotNull(CONSTROID, tuple,
                              12108                 :                :                                          Anum_pg_constraint_conbin);
 1370 drowley@postgresql.o    12109                 :             60 :             conbin = TextDatumGetCString(val);
                              12110                 :             60 :             newcon->qual = (Node *) stringToNode(conbin);
                              12111                 :                : 
                              12112                 :                :             /* Find or create work queue entry for this table */
                              12113                 :             60 :             tab = ATGetQueueEntry(wqueue, rel);
                              12114                 :             60 :             tab->constraints = lappend(tab->constraints, newcon);
                              12115                 :                : 
                              12116                 :                :             /*
                              12117                 :                :              * Invalidate relcache so that others see the new validated
                              12118                 :                :              * constraint.
                              12119                 :                :              */
 4701 alvherre@alvh.no-ip.    12120                 :             60 :             CacheInvalidateRelcache(rel);
                              12121                 :                :         }
                              12122                 :                : 
                              12123                 :                :         /*
                              12124                 :                :          * Now update the catalog, while we have the door open.
                              12125                 :                :          */
                              12126                 :            209 :         copyTuple = heap_copytuple(tuple);
                              12127                 :            209 :         copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
 4814 simon@2ndQuadrant.co    12128                 :            209 :         copy_con->convalidated = true;
 2630 alvherre@alvh.no-ip.    12129                 :            209 :         CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
                              12130                 :                : 
 1972 andres@anarazel.de      12131         [ -  + ]:            209 :         InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
                              12132                 :                : 
 4814 simon@2ndQuadrant.co    12133                 :            209 :         heap_freetuple(copyTuple);
                              12134                 :                : 
 1972 andres@anarazel.de      12135                 :            209 :         ObjectAddressSet(address, ConstraintRelationId, con->oid);
                              12136                 :                :     }
                              12137                 :                :     else
 3249 bruce@momjian.us        12138                 :              9 :         address = InvalidObjectAddress; /* already validated */
                              12139                 :                : 
 4814 simon@2ndQuadrant.co    12140                 :            218 :     systable_endscan(scan);
                              12141                 :                : 
 1910 andres@anarazel.de      12142                 :            218 :     table_close(conrel, RowExclusiveLock);
                              12143                 :                : 
 3308 alvherre@alvh.no-ip.    12144                 :            218 :     return address;
                              12145                 :                : }
                              12146                 :                : 
                              12147                 :                : 
                              12148                 :                : /*
                              12149                 :                :  * transformColumnNameList - transform list of column names
                              12150                 :                :  *
                              12151                 :                :  * Lookup each name and return its attnum and, optionally, type OID
                              12152                 :                :  *
                              12153                 :                :  * Note: the name of this function suggests that it's general-purpose,
                              12154                 :                :  * but actually it's only used to look up names appearing in foreign-key
                              12155                 :                :  * clauses.  The error messages would need work to use it in other cases,
                              12156                 :                :  * and perhaps the validity checks as well.
                              12157                 :                :  */
                              12158                 :                : static int
 7875 tgl@sss.pgh.pa.us       12159                 :           3080 : transformColumnNameList(Oid relId, List *colList,
                              12160                 :                :                         int16 *attnums, Oid *atttypids)
                              12161                 :                : {
                              12162                 :                :     ListCell   *l;
                              12163                 :                :     int         attnum;
                              12164                 :                : 
                              12165                 :           3080 :     attnum = 0;
                              12166   [ +  +  +  +  :           5631 :     foreach(l, colList)
                                              +  + ]
                              12167                 :                :     {
                              12168                 :           2584 :         char       *attname = strVal(lfirst(l));
                              12169                 :                :         HeapTuple   atttuple;
                              12170                 :                :         Form_pg_attribute attform;
                              12171                 :                : 
                              12172                 :           2584 :         atttuple = SearchSysCacheAttName(relId, attname);
                              12173         [ +  + ]:           2584 :         if (!HeapTupleIsValid(atttuple))
 7574                         12174         [ +  - ]:             27 :             ereport(ERROR,
                              12175                 :                :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
                              12176                 :                :                      errmsg("column \"%s\" referenced in foreign key constraint does not exist",
                              12177                 :                :                             attname)));
  380                         12178                 :           2557 :         attform = (Form_pg_attribute) GETSTRUCT(atttuple);
                              12179         [ +  + ]:           2557 :         if (attform->attnum < 0)
                              12180         [ +  - ]:              6 :             ereport(ERROR,
                              12181                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              12182                 :                :                      errmsg("system columns cannot be used in foreign keys")));
 7875                         12183         [ -  + ]:           2551 :         if (attnum >= INDEX_MAX_KEYS)
 7574 tgl@sss.pgh.pa.us       12184         [ #  # ]:UBC           0 :             ereport(ERROR,
                              12185                 :                :                     (errcode(ERRCODE_TOO_MANY_COLUMNS),
                              12186                 :                :                      errmsg("cannot have more than %d keys in a foreign key",
                              12187                 :                :                             INDEX_MAX_KEYS)));
  380 tgl@sss.pgh.pa.us       12188                 :CBC        2551 :         attnums[attnum] = attform->attnum;
  858 peter@eisentraut.org    12189         [ +  + ]:           2551 :         if (atttypids != NULL)
  380 tgl@sss.pgh.pa.us       12190                 :           2536 :             atttypids[attnum] = attform->atttypid;
 7875                         12191                 :           2551 :         ReleaseSysCache(atttuple);
                              12192                 :           2551 :         attnum++;
                              12193                 :                :     }
                              12194                 :                : 
                              12195                 :           3047 :     return attnum;
                              12196                 :                : }
                              12197                 :                : 
                              12198                 :                : /*
                              12199                 :                :  * transformFkeyGetPrimaryKey -
                              12200                 :                :  *
                              12201                 :                :  *  Look up the names, attnums, and types of the primary key attributes
                              12202                 :                :  *  for the pkrel.  Also return the index OID and index opclasses of the
                              12203                 :                :  *  index supporting the primary key.  Also return whether the index has
                              12204                 :                :  *  WITHOUT OVERLAPS.
                              12205                 :                :  *
                              12206                 :                :  *  All parameters except pkrel are output parameters.  Also, the function
                              12207                 :                :  *  return value is the number of attributes in the primary key.
                              12208                 :                :  *
                              12209                 :                :  *  Used when the column list in the REFERENCES specification is omitted.
                              12210                 :                :  */
                              12211                 :                : static int
                              12212                 :            535 : transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
                              12213                 :                :                            List **attnamelist,
                              12214                 :                :                            int16 *attnums, Oid *atttypids,
                              12215                 :                :                            Oid *opclasses, bool *pk_has_without_overlaps)
                              12216                 :                : {
                              12217                 :                :     List       *indexoidlist;
                              12218                 :                :     ListCell   *indexoidscan;
                              12219                 :            535 :     HeapTuple   indexTuple = NULL;
                              12220                 :            535 :     Form_pg_index indexStruct = NULL;
                              12221                 :                :     Datum       indclassDatum;
                              12222                 :                :     oidvector  *indclass;
                              12223                 :                :     int         i;
                              12224                 :                : 
                              12225                 :                :     /*
                              12226                 :                :      * Get the list of index OIDs for the table from the relcache, and look up
                              12227                 :                :      * each one in the pg_index syscache until we find one marked primary key
                              12228                 :                :      * (hopefully there isn't more than one such).  Insist it's valid, too.
                              12229                 :                :      */
 6777                         12230                 :            535 :     *indexOid = InvalidOid;
                              12231                 :                : 
 7875                         12232                 :            535 :     indexoidlist = RelationGetIndexList(pkrel);
                              12233                 :                : 
                              12234   [ +  -  +  -  :            538 :     foreach(indexoidscan, indexoidlist)
                                              +  - ]
                              12235                 :                :     {
 7263 neilc@samurai.com       12236                 :            538 :         Oid         indexoid = lfirst_oid(indexoidscan);
                              12237                 :                : 
 5173 rhaas@postgresql.org    12238                 :            538 :         indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
 7875 tgl@sss.pgh.pa.us       12239         [ -  + ]:            538 :         if (!HeapTupleIsValid(indexTuple))
 7574 tgl@sss.pgh.pa.us       12240         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for index %u", indexoid);
 7875 tgl@sss.pgh.pa.us       12241                 :CBC         538 :         indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 1935 peter_e@gmx.net         12242   [ +  +  +  - ]:            538 :         if (indexStruct->indisprimary && indexStruct->indisvalid)
                              12243                 :                :         {
                              12244                 :                :             /*
                              12245                 :                :              * Refuse to use a deferrable primary key.  This is per SQL spec,
                              12246                 :                :              * and there would be a lot of interesting semantic problems if we
                              12247                 :                :              * tried to allow it.
                              12248                 :                :              */
 5373 tgl@sss.pgh.pa.us       12249         [ -  + ]:            535 :             if (!indexStruct->indimmediate)
 5373 tgl@sss.pgh.pa.us       12250         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              12251                 :                :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              12252                 :                :                          errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
                              12253                 :                :                                 RelationGetRelationName(pkrel))));
                              12254                 :                : 
 7875 tgl@sss.pgh.pa.us       12255                 :CBC         535 :             *indexOid = indexoid;
                              12256                 :            535 :             break;
                              12257                 :                :         }
                              12258                 :              3 :         ReleaseSysCache(indexTuple);
                              12259                 :                :     }
                              12260                 :                : 
 7263 neilc@samurai.com       12261                 :            535 :     list_free(indexoidlist);
                              12262                 :                : 
                              12263                 :                :     /*
                              12264                 :                :      * Check that we found it
                              12265                 :                :      */
 6777 tgl@sss.pgh.pa.us       12266         [ -  + ]:            535 :     if (!OidIsValid(*indexOid))
 7574 tgl@sss.pgh.pa.us       12267         [ #  # ]:UBC           0 :         ereport(ERROR,
                              12268                 :                :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              12269                 :                :                  errmsg("there is no primary key for referenced table \"%s\"",
                              12270                 :                :                         RelationGetRelationName(pkrel))));
                              12271                 :                : 
                              12272                 :                :     /* Must get indclass the hard way */
  386 dgustafsson@postgres    12273                 :CBC         535 :     indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
                              12274                 :                :                                            Anum_pg_index_indclass);
 6956 tgl@sss.pgh.pa.us       12275                 :            535 :     indclass = (oidvector *) DatumGetPointer(indclassDatum);
                              12276                 :                : 
                              12277                 :                :     /*
                              12278                 :                :      * Now build the list of PK attributes from the indkey definition (we
                              12279                 :                :      * assume a primary key cannot have expressional elements)
                              12280                 :                :      */
 7875                         12281                 :            535 :     *attnamelist = NIL;
 2199 teodor@sigaev.ru        12282         [ +  + ]:           1252 :     for (i = 0; i < indexStruct->indnkeyatts; i++)
                              12283                 :                :     {
 6956 tgl@sss.pgh.pa.us       12284                 :            717 :         int         pkattno = indexStruct->indkey.values[i];
                              12285                 :                : 
 7875                         12286                 :            717 :         attnums[i] = pkattno;
                              12287                 :            717 :         atttypids[i] = attnumTypeId(pkrel, pkattno);
 6956                         12288                 :            717 :         opclasses[i] = indclass->values[i];
 7875                         12289                 :            717 :         *attnamelist = lappend(*attnamelist,
 2489                         12290                 :            717 :                                makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
                              12291                 :                :     }
                              12292                 :                : 
   21 peter@eisentraut.org    12293                 :GNC         535 :     *pk_has_without_overlaps = indexStruct->indisexclusion;
                              12294                 :                : 
 7875 tgl@sss.pgh.pa.us       12295                 :CBC         535 :     ReleaseSysCache(indexTuple);
                              12296                 :                : 
                              12297                 :            535 :     return i;
                              12298                 :                : }
                              12299                 :                : 
                              12300                 :                : /*
                              12301                 :                :  * transformFkeyCheckAttrs -
                              12302                 :                :  *
                              12303                 :                :  *  Validate that the 'attnums' columns in the 'pkrel' relation are valid to
                              12304                 :                :  *  reference as part of a foreign key constraint.
                              12305                 :                :  *
                              12306                 :                :  *  Returns the OID of the unique index supporting the constraint and
                              12307                 :                :  *  populates the caller-provided 'opclasses' array with the opclasses
                              12308                 :                :  *  associated with the index columns.  Also sets whether the index
                              12309                 :                :  *  uses WITHOUT OVERLAPS.
                              12310                 :                :  *
                              12311                 :                :  *  Raises an ERROR on validation failure.
                              12312                 :                :  */
                              12313                 :                : static Oid
                              12314                 :            630 : transformFkeyCheckAttrs(Relation pkrel,
                              12315                 :                :                         int numattrs, int16 *attnums,
                              12316                 :                :                         bool with_period, Oid *opclasses,
                              12317                 :                :                         bool *pk_has_without_overlaps)
                              12318                 :                : {
                              12319                 :            630 :     Oid         indexoid = InvalidOid;
                              12320                 :            630 :     bool        found = false;
 5359                         12321                 :            630 :     bool        found_deferrable = false;
                              12322                 :                :     List       *indexoidlist;
                              12323                 :                :     ListCell   *indexoidscan;
                              12324                 :                :     int         i,
                              12325                 :                :                 j;
                              12326                 :                : 
                              12327                 :                :     /*
                              12328                 :                :      * Reject duplicate appearances of columns in the referenced-columns list.
                              12329                 :                :      * Such a case is forbidden by the SQL standard, and even if we thought it
                              12330                 :                :      * useful to allow it, there would be ambiguity about how to match the
                              12331                 :                :      * list to unique indexes (in particular, it'd be unclear which index
                              12332                 :                :      * opclass goes with which FK column).
                              12333                 :                :      */
 3536                         12334         [ +  + ]:           1475 :     for (i = 0; i < numattrs; i++)
                              12335                 :                :     {
                              12336         [ +  + ]:           1119 :         for (j = i + 1; j < numattrs; j++)
                              12337                 :                :         {
                              12338         [ +  + ]:            274 :             if (attnums[i] == attnums[j])
 3536 tgl@sss.pgh.pa.us       12339         [ +  - ]:GBC          12 :                 ereport(ERROR,
                              12340                 :                :                         (errcode(ERRCODE_INVALID_FOREIGN_KEY),
                              12341                 :                :                          errmsg("foreign key referenced-columns list must not contain duplicates")));
                              12342                 :                :         }
                              12343                 :                :     }
                              12344                 :                : 
                              12345                 :                :     /*
                              12346                 :                :      * Get the list of index OIDs for the table from the relcache, and look up
                              12347                 :                :      * each one in the pg_index syscache, and match unique indexes to the list
                              12348                 :                :      * of attnums we are given.
                              12349                 :                :      */
 7875 tgl@sss.pgh.pa.us       12350                 :CBC         618 :     indexoidlist = RelationGetIndexList(pkrel);
                              12351                 :                : 
                              12352   [ +  -  +  +  :            708 :     foreach(indexoidscan, indexoidlist)
                                              +  + ]
                              12353                 :                :     {
                              12354                 :                :         HeapTuple   indexTuple;
                              12355                 :                :         Form_pg_index indexStruct;
                              12356                 :                : 
 7263 neilc@samurai.com       12357                 :            702 :         indexoid = lfirst_oid(indexoidscan);
 5173 rhaas@postgresql.org    12358                 :            702 :         indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
 7875 tgl@sss.pgh.pa.us       12359         [ -  + ]:            702 :         if (!HeapTupleIsValid(indexTuple))
 7574 tgl@sss.pgh.pa.us       12360         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for index %u", indexoid);
 7875 tgl@sss.pgh.pa.us       12361                 :CBC         702 :         indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
                              12362                 :                : 
                              12363                 :                :         /*
                              12364                 :                :          * Must have the right number of columns; must be unique (or if
                              12365                 :                :          * temporal then exclusion instead) and not a partial index; forget it
                              12366                 :                :          * if there are any expressions, too. Invalid indexes are out as well.
                              12367                 :                :          */
 2199 teodor@sigaev.ru        12368   [ +  +  +  +  :           1350 :         if (indexStruct->indnkeyatts == numattrs &&
                                              +  + ]
   21 peter@eisentraut.org    12369                 :GNC         648 :             (with_period ? indexStruct->indisexclusion : indexStruct->indisunique) &&
 1935 peter_e@gmx.net         12370   [ +  -  +  - ]:CBC        1282 :             indexStruct->indisvalid &&
 2209 andrew@dunslane.net     12371         [ +  - ]:           1282 :             heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
                              12372                 :            641 :             heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
                              12373                 :                :         {
                              12374                 :                :             Datum       indclassDatum;
                              12375                 :                :             oidvector  *indclass;
                              12376                 :                : 
                              12377                 :                :             /* Must get indclass the hard way */
  386 dgustafsson@postgres    12378                 :            641 :             indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
                              12379                 :                :                                                    Anum_pg_index_indclass);
 6956 tgl@sss.pgh.pa.us       12380                 :            641 :             indclass = (oidvector *) DatumGetPointer(indclassDatum);
                              12381                 :                : 
                              12382                 :                :             /*
                              12383                 :                :              * The given attnum list may match the index columns in any order.
                              12384                 :                :              * Check for a match, and extract the appropriate opclasses while
                              12385                 :                :              * we're at it.
                              12386                 :                :              *
                              12387                 :                :              * We know that attnums[] is duplicate-free per the test at the
                              12388                 :                :              * start of this function, and we checked above that the number of
                              12389                 :                :              * index columns agrees, so if we find a match for each attnums[]
                              12390                 :                :              * entry then we must have a one-to-one match in some order.
                              12391                 :                :              */
 7627                         12392         [ +  + ]:           1480 :             for (i = 0; i < numattrs; i++)
                              12393                 :                :             {
                              12394                 :            868 :                 found = false;
                              12395         [ +  + ]:           1159 :                 for (j = 0; j < numattrs; j++)
                              12396                 :                :                 {
 6956                         12397         [ +  + ]:           1130 :                     if (attnums[i] == indexStruct->indkey.values[j])
                              12398                 :                :                     {
 3536                         12399                 :            839 :                         opclasses[i] = indclass->values[j];
 7627                         12400                 :            839 :                         found = true;
                              12401                 :            839 :                         break;
                              12402                 :                :                     }
                              12403                 :                :                 }
                              12404         [ +  + ]:            868 :                 if (!found)
                              12405                 :             29 :                     break;
                              12406                 :                :             }
                              12407                 :                :             /* The last attribute in the index must be the PERIOD FK part */
   21 peter@eisentraut.org    12408   [ +  +  +  + ]:GNC         641 :             if (found && with_period)
                              12409                 :                :             {
                              12410                 :             65 :                 int16       periodattnum = attnums[numattrs - 1];
                              12411                 :                : 
                              12412                 :             65 :                 found = (periodattnum == indexStruct->indkey.values[numattrs - 1]);
                              12413                 :                :             }
                              12414                 :                : 
                              12415                 :                :             /*
                              12416                 :                :              * Refuse to use a deferrable unique/primary key.  This is per SQL
                              12417                 :                :              * spec, and there would be a lot of interesting semantic problems
                              12418                 :                :              * if we tried to allow it.
                              12419                 :                :              */
 5359 tgl@sss.pgh.pa.us       12420   [ +  +  -  + ]:CBC         641 :             if (found && !indexStruct->indimmediate)
                              12421                 :                :             {
                              12422                 :                :                 /*
                              12423                 :                :                  * Remember that we found an otherwise matching index, so that
                              12424                 :                :                  * we can generate a more appropriate error message.
                              12425                 :                :                  */
 5359 tgl@sss.pgh.pa.us       12426                 :UBC           0 :                 found_deferrable = true;
                              12427                 :              0 :                 found = false;
                              12428                 :                :             }
                              12429                 :                : 
                              12430                 :                :             /* We need to know whether the index has WITHOUT OVERLAPS */
   21 peter@eisentraut.org    12431         [ +  + ]:GNC         641 :             if (found)
                              12432                 :            612 :                 *pk_has_without_overlaps = indexStruct->indisexclusion;
                              12433                 :                :         }
 7875 tgl@sss.pgh.pa.us       12434                 :CBC         702 :         ReleaseSysCache(indexTuple);
                              12435         [ +  + ]:            702 :         if (found)
                              12436                 :            612 :             break;
                              12437                 :                :     }
                              12438                 :                : 
                              12439         [ +  + ]:            618 :     if (!found)
                              12440                 :                :     {
 5359                         12441         [ -  + ]:              6 :         if (found_deferrable)
 5359 tgl@sss.pgh.pa.us       12442         [ #  # ]:UBC           0 :             ereport(ERROR,
                              12443                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              12444                 :                :                      errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
                              12445                 :                :                             RelationGetRelationName(pkrel))));
                              12446                 :                :         else
 5359 tgl@sss.pgh.pa.us       12447         [ +  - ]:CBC           6 :             ereport(ERROR,
                              12448                 :                :                     (errcode(ERRCODE_INVALID_FOREIGN_KEY),
                              12449                 :                :                      errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
                              12450                 :                :                             RelationGetRelationName(pkrel))));
                              12451                 :                :     }
                              12452                 :                : 
 7263 neilc@samurai.com       12453                 :            612 :     list_free(indexoidlist);
                              12454                 :                : 
 7875 tgl@sss.pgh.pa.us       12455                 :            612 :     return indexoid;
                              12456                 :                : }
                              12457                 :                : 
                              12458                 :                : /*
                              12459                 :                :  * findFkeyCast -
                              12460                 :                :  *
                              12461                 :                :  *  Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
                              12462                 :                :  *  Caller has equal regard for binary coercibility and for an exact match.
                              12463                 :                : */
                              12464                 :                : static CoercionPathType
 4430 alvherre@alvh.no-ip.    12465                 :              6 : findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
                              12466                 :                : {
                              12467                 :                :     CoercionPathType ret;
                              12468                 :                : 
                              12469         [ +  - ]:              6 :     if (targetTypeId == sourceTypeId)
                              12470                 :                :     {
                              12471                 :              6 :         ret = COERCION_PATH_RELABELTYPE;
                              12472                 :              6 :         *funcid = InvalidOid;
                              12473                 :                :     }
                              12474                 :                :     else
                              12475                 :                :     {
 4430 alvherre@alvh.no-ip.    12476                 :UBC           0 :         ret = find_coercion_pathway(targetTypeId, sourceTypeId,
                              12477                 :                :                                     COERCION_IMPLICIT, funcid);
                              12478         [ #  # ]:              0 :         if (ret == COERCION_PATH_NONE)
                              12479                 :                :             /* A previously-relied-upon cast is now gone. */
                              12480         [ #  # ]:              0 :             elog(ERROR, "could not find cast from %u to %u",
                              12481                 :                :                  sourceTypeId, targetTypeId);
                              12482                 :                :     }
                              12483                 :                : 
 4430 alvherre@alvh.no-ip.    12484                 :CBC           6 :     return ret;
                              12485                 :                : }
                              12486                 :                : 
                              12487                 :                : /*
                              12488                 :                :  * Permissions checks on the referenced table for ADD FOREIGN KEY
                              12489                 :                :  *
                              12490                 :                :  * Note: we have already checked that the user owns the referencing table,
                              12491                 :                :  * else we'd have failed much earlier; no additional checks are needed for it.
                              12492                 :                :  */
                              12493                 :                : static void
 5561 tgl@sss.pgh.pa.us       12494                 :           1129 : checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
                              12495                 :                : {
                              12496                 :           1129 :     Oid         roleid = GetUserId();
                              12497                 :                :     AclResult   aclresult;
                              12498                 :                :     int         i;
                              12499                 :                : 
                              12500                 :                :     /* Okay if we have relation-level REFERENCES permission */
                              12501                 :           1129 :     aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
                              12502                 :                :                                   ACL_REFERENCES);
                              12503         [ +  - ]:           1129 :     if (aclresult == ACLCHECK_OK)
                              12504                 :           1129 :         return;
                              12505                 :                :     /* Else we must have REFERENCES on each column */
 5561 tgl@sss.pgh.pa.us       12506         [ #  # ]:UBC           0 :     for (i = 0; i < natts; i++)
                              12507                 :                :     {
                              12508                 :              0 :         aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
                              12509                 :                :                                           roleid, ACL_REFERENCES);
                              12510         [ #  # ]:              0 :         if (aclresult != ACLCHECK_OK)
 2325 peter_e@gmx.net         12511                 :              0 :             aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
 5561 tgl@sss.pgh.pa.us       12512                 :              0 :                            RelationGetRelationName(rel));
                              12513                 :                :     }
                              12514                 :                : }
                              12515                 :                : 
                              12516                 :                : /*
                              12517                 :                :  * Scan the existing rows in a table to verify they meet a proposed FK
                              12518                 :                :  * constraint.
                              12519                 :                :  *
                              12520                 :                :  * Caller must have opened and locked both relations appropriately.
                              12521                 :                :  */
                              12522                 :                : static void
 4814 simon@2ndQuadrant.co    12523                 :CBC         542 : validateForeignKeyConstraint(char *conname,
                              12524                 :                :                              Relation rel,
                              12525                 :                :                              Relation pkrel,
                              12526                 :                :                              Oid pkindOid,
                              12527                 :                :                              Oid constraintOid,
                              12528                 :                :                              bool hasperiod)
                              12529                 :                : {
                              12530                 :                :     TupleTableSlot *slot;
                              12531                 :                :     TableScanDesc scan;
  638 peter@eisentraut.org    12532                 :            542 :     Trigger     trig = {0};
                              12533                 :                :     Snapshot    snapshot;
                              12534                 :                :     MemoryContext oldcxt;
                              12535                 :                :     MemoryContext perTupCxt;
                              12536                 :                : 
 4810 rhaas@postgresql.org    12537         [ -  + ]:            542 :     ereport(DEBUG1,
                              12538                 :                :             (errmsg_internal("validating foreign key constraint \"%s\"", conname)));
                              12539                 :                : 
                              12540                 :                :     /*
                              12541                 :                :      * Build a trigger call structure; we'll need it either way.
                              12542                 :                :      */
 7947 tgl@sss.pgh.pa.us       12543                 :            542 :     trig.tgoid = InvalidOid;
 4814 simon@2ndQuadrant.co    12544                 :            542 :     trig.tgname = conname;
 6236 JanWieck@Yahoo.com      12545                 :            542 :     trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
 2433 peter_e@gmx.net         12546                 :            542 :     trig.tgisinternal = true;
 7947 tgl@sss.pgh.pa.us       12547                 :            542 :     trig.tgconstrrelid = RelationGetRelid(pkrel);
 5374                         12548                 :            542 :     trig.tgconstrindid = pkindOid;
 6269                         12549                 :            542 :     trig.tgconstraint = constraintOid;
 2433 peter_e@gmx.net         12550                 :            542 :     trig.tgdeferrable = false;
                              12551                 :            542 :     trig.tginitdeferred = false;
                              12552                 :                :     /* we needn't fill in remaining fields */
                              12553                 :                : 
                              12554                 :                :     /*
                              12555                 :                :      * See if we can do it with a single LEFT JOIN query.  A false result
                              12556                 :                :      * indicates we must proceed with the fire-the-trigger method. We can't do
                              12557                 :                :      * a LEFT JOIN for temporal FKs yet, but we can once we support temporal
                              12558                 :                :      * left joins.
                              12559                 :                :      */
   21 peter@eisentraut.org    12560   [ +  +  +  + ]:GNC         542 :     if (!hasperiod && RI_Initial_Check(&trig, rel, pkrel))
 6269 tgl@sss.pgh.pa.us       12561                 :CBC         438 :         return;
                              12562                 :                : 
                              12563                 :                :     /*
                              12564                 :                :      * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
                              12565                 :                :      * if that tuple had just been inserted.  If any of those fail, it should
                              12566                 :                :      * ereport(ERROR) and that's that.
                              12567                 :                :      */
 3939 rhaas@postgresql.org    12568                 :             73 :     snapshot = RegisterSnapshot(GetLatestSnapshot());
 1861 andres@anarazel.de      12569                 :             73 :     slot = table_slot_create(rel, NULL);
                              12570                 :             73 :     scan = table_beginscan(rel, snapshot, 0, NULL);
                              12571                 :                : 
 1834                         12572                 :             73 :     perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
                              12573                 :                :                                       "validateForeignKeyConstraint",
                              12574                 :                :                                       ALLOCSET_SMALL_SIZES);
                              12575                 :             73 :     oldcxt = MemoryContextSwitchTo(perTupCxt);
                              12576                 :                : 
 1861                         12577         [ +  + ]:            115 :     while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
                              12578                 :                :     {
 1905                         12579                 :             51 :         LOCAL_FCINFO(fcinfo, 0);
 1511 peter@eisentraut.org    12580                 :             51 :         TriggerData trigdata = {0};
                              12581                 :                : 
 1834 andres@anarazel.de      12582         [ -  + ]:             51 :         CHECK_FOR_INTERRUPTS();
                              12583                 :                : 
                              12584                 :                :         /*
                              12585                 :                :          * Make a call to the trigger function
                              12586                 :                :          *
                              12587                 :                :          * No parameters are passed, but we do set a context
                              12588                 :                :          */
 1905                         12589   [ +  -  +  -  :            255 :         MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
                                     +  -  +  -  +  
                                                 + ]
                              12590                 :                : 
                              12591                 :                :         /*
                              12592                 :                :          * We assume RI_FKey_check_ins won't look at flinfo...
                              12593                 :                :          */
 7489 bruce@momjian.us        12594                 :             51 :         trigdata.type = T_TriggerData;
                              12595                 :             51 :         trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
                              12596                 :             51 :         trigdata.tg_relation = rel;
 1835 tgl@sss.pgh.pa.us       12597                 :             51 :         trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
 1861 andres@anarazel.de      12598                 :             51 :         trigdata.tg_trigslot = slot;
 7489 bruce@momjian.us        12599                 :             51 :         trigdata.tg_trigger = &trig;
                              12600                 :                : 
 1905 andres@anarazel.de      12601                 :             51 :         fcinfo->context = (Node *) &trigdata;
                              12602                 :                : 
                              12603                 :             51 :         RI_FKey_check_ins(fcinfo);
                              12604                 :                : 
 1834                         12605                 :             42 :         MemoryContextReset(perTupCxt);
                              12606                 :                :     }
                              12607                 :                : 
                              12608                 :             64 :     MemoryContextSwitchTo(oldcxt);
                              12609                 :             64 :     MemoryContextDelete(perTupCxt);
 1861                         12610                 :             64 :     table_endscan(scan);
 3939 rhaas@postgresql.org    12611                 :             64 :     UnregisterSnapshot(snapshot);
 1861 andres@anarazel.de      12612                 :             64 :     ExecDropSingleTupleTableSlot(slot);
                              12613                 :                : }
                              12614                 :                : 
                              12615                 :                : /*
                              12616                 :                :  * CreateFKCheckTrigger
                              12617                 :                :  *      Creates the insert (on_insert=true) or update "check" trigger that
                              12618                 :                :  *      implements a given foreign key
                              12619                 :                :  *
                              12620                 :                :  * Returns the OID of the so created trigger.
                              12621                 :                :  */
                              12622                 :                : static Oid
 3709 rhaas@postgresql.org    12623                 :           2746 : CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
                              12624                 :                :                      Oid constraintOid, Oid indexOid, Oid parentTrigOid,
                              12625                 :                :                      bool on_insert)
                              12626                 :                : {
                              12627                 :                :     ObjectAddress trigAddress;
                              12628                 :                :     CreateTrigStmt *fk_trigger;
                              12629                 :                : 
                              12630                 :                :     /*
                              12631                 :                :      * Note: for a self-referential FK (referencing and referenced tables are
                              12632                 :                :      * the same), it is important that the ON UPDATE action fires before the
                              12633                 :                :      * CHECK action, since both triggers will fire on the same row during an
                              12634                 :                :      * UPDATE event; otherwise the CHECK trigger will be checking a non-final
                              12635                 :                :      * state of the row.  Triggers fire in name order, so we ensure this by
                              12636                 :                :      * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
                              12637                 :                :      * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
                              12638                 :                :      */
 7947 tgl@sss.pgh.pa.us       12639                 :           2746 :     fk_trigger = makeNode(CreateTrigStmt);
 1247                         12640                 :           2746 :     fk_trigger->replace = false;
                              12641                 :           2746 :     fk_trigger->isconstraint = true;
 4554                         12642                 :           2746 :     fk_trigger->trigname = "RI_ConstraintTrigger_c";
 3709 rhaas@postgresql.org    12643                 :           2746 :     fk_trigger->relation = NULL;
                              12644                 :                : 
                              12645                 :                :     /* Either ON INSERT or ON UPDATE */
 6894 neilc@samurai.com       12646         [ +  + ]:           2746 :     if (on_insert)
                              12647                 :                :     {
                              12648                 :           1373 :         fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
 5414 tgl@sss.pgh.pa.us       12649                 :           1373 :         fk_trigger->events = TRIGGER_TYPE_INSERT;
                              12650                 :                :     }
                              12651                 :                :     else
                              12652                 :                :     {
 6894 neilc@samurai.com       12653                 :           1373 :         fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
 5414 tgl@sss.pgh.pa.us       12654                 :           1373 :         fk_trigger->events = TRIGGER_TYPE_UPDATE;
                              12655                 :                :     }
                              12656                 :                : 
 1247                         12657                 :           2746 :     fk_trigger->args = NIL;
                              12658                 :           2746 :     fk_trigger->row = true;
                              12659                 :           2746 :     fk_trigger->timing = TRIGGER_TYPE_AFTER;
 5296                         12660                 :           2746 :     fk_trigger->columns = NIL;
 5259                         12661                 :           2746 :     fk_trigger->whenClause = NULL;
 1247                         12662                 :           2746 :     fk_trigger->transitionRels = NIL;
 7947                         12663                 :           2746 :     fk_trigger->deferrable = fkconstraint->deferrable;
                              12664                 :           2746 :     fk_trigger->initdeferred = fkconstraint->initdeferred;
 3709 rhaas@postgresql.org    12665                 :           2746 :     fk_trigger->constrrel = NULL;
                              12666                 :                : 
  830 alvherre@alvh.no-ip.    12667                 :           2746 :     trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid,
                              12668                 :                :                                 constraintOid, indexOid, InvalidOid,
                              12669                 :                :                                 parentTrigOid, NULL, true, false);
                              12670                 :                : 
                              12671                 :                :     /* Make changes-so-far visible */
 6894 neilc@samurai.com       12672                 :           2746 :     CommandCounterIncrement();
                              12673                 :                : 
  830 alvherre@alvh.no-ip.    12674                 :           2746 :     return trigAddress.objectId;
                              12675                 :                : }
                              12676                 :                : 
                              12677                 :                : /*
                              12678                 :                :  * createForeignKeyActionTriggers
                              12679                 :                :  *      Create the referenced-side "action" triggers that implement a foreign
                              12680                 :                :  *      key.
                              12681                 :                :  *
                              12682                 :                :  * Returns the OIDs of the so created triggers in *deleteTrigOid and
                              12683                 :                :  * *updateTrigOid.
                              12684                 :                :  */
                              12685                 :                : static void
 2202                         12686                 :           1381 : createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint,
                              12687                 :                :                                Oid constraintOid, Oid indexOid,
                              12688                 :                :                                Oid parentDelTrigger, Oid parentUpdTrigger,
                              12689                 :                :                                Oid *deleteTrigOid, Oid *updateTrigOid)
                              12690                 :                : {
                              12691                 :                :     CreateTrigStmt *fk_trigger;
                              12692                 :                :     ObjectAddress trigAddress;
                              12693                 :                : 
                              12694                 :                :     /*
                              12695                 :                :      * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
                              12696                 :                :      * DELETE action on the referenced table.
                              12697                 :                :      */
 7284 tgl@sss.pgh.pa.us       12698                 :           1381 :     fk_trigger = makeNode(CreateTrigStmt);
 1247                         12699                 :           1381 :     fk_trigger->replace = false;
                              12700                 :           1381 :     fk_trigger->isconstraint = true;
 4554                         12701                 :           1381 :     fk_trigger->trigname = "RI_ConstraintTrigger_a";
 3709 rhaas@postgresql.org    12702                 :           1381 :     fk_trigger->relation = NULL;
 1247 tgl@sss.pgh.pa.us       12703                 :           1381 :     fk_trigger->args = NIL;
 7284                         12704                 :           1381 :     fk_trigger->row = true;
 4935                         12705                 :           1381 :     fk_trigger->timing = TRIGGER_TYPE_AFTER;
 5414                         12706                 :           1381 :     fk_trigger->events = TRIGGER_TYPE_DELETE;
 5296                         12707                 :           1381 :     fk_trigger->columns = NIL;
 5259                         12708                 :           1381 :     fk_trigger->whenClause = NULL;
 1247                         12709                 :           1381 :     fk_trigger->transitionRels = NIL;
 3709 rhaas@postgresql.org    12710                 :           1381 :     fk_trigger->constrrel = NULL;
                              12711                 :                : 
 7284 tgl@sss.pgh.pa.us       12712   [ +  +  +  +  :           1381 :     switch (fkconstraint->fk_del_action)
                                              +  - ]
                              12713                 :                :     {
                              12714                 :           1050 :         case FKCONSTR_ACTION_NOACTION:
 7115                         12715                 :           1050 :             fk_trigger->deferrable = fkconstraint->deferrable;
                              12716                 :           1050 :             fk_trigger->initdeferred = fkconstraint->initdeferred;
 7284                         12717                 :           1050 :             fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
                              12718                 :           1050 :             break;
                              12719                 :             32 :         case FKCONSTR_ACTION_RESTRICT:
                              12720                 :             32 :             fk_trigger->deferrable = false;
                              12721                 :             32 :             fk_trigger->initdeferred = false;
                              12722                 :             32 :             fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
                              12723                 :             32 :             break;
                              12724                 :            220 :         case FKCONSTR_ACTION_CASCADE:
 7115                         12725                 :            220 :             fk_trigger->deferrable = false;
                              12726                 :            220 :             fk_trigger->initdeferred = false;
 7284                         12727                 :            220 :             fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
                              12728                 :            220 :             break;
                              12729                 :             49 :         case FKCONSTR_ACTION_SETNULL:
 7115                         12730                 :             49 :             fk_trigger->deferrable = false;
                              12731                 :             49 :             fk_trigger->initdeferred = false;
 7284                         12732                 :             49 :             fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
                              12733                 :             49 :             break;
                              12734                 :             30 :         case FKCONSTR_ACTION_SETDEFAULT:
 7115                         12735                 :             30 :             fk_trigger->deferrable = false;
                              12736                 :             30 :             fk_trigger->initdeferred = false;
 7284                         12737                 :             30 :             fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
                              12738                 :             30 :             break;
 7284 tgl@sss.pgh.pa.us       12739                 :UBC           0 :         default:
                              12740         [ #  # ]:              0 :             elog(ERROR, "unrecognized FK action type: %d",
                              12741                 :                :                  (int) fkconstraint->fk_del_action);
                              12742                 :                :             break;
                              12743                 :                :     }
                              12744                 :                : 
  830 alvherre@alvh.no-ip.    12745                 :CBC        1381 :     trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
                              12746                 :                :                                 RelationGetRelid(rel),
                              12747                 :                :                                 constraintOid, indexOid, InvalidOid,
                              12748                 :                :                                 parentDelTrigger, NULL, true, false);
                              12749         [ +  + ]:           1381 :     if (deleteTrigOid)
                              12750                 :           1348 :         *deleteTrigOid = trigAddress.objectId;
                              12751                 :                : 
                              12752                 :                :     /* Make changes-so-far visible */
 7284 tgl@sss.pgh.pa.us       12753                 :           1381 :     CommandCounterIncrement();
                              12754                 :                : 
                              12755                 :                :     /*
                              12756                 :                :      * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
                              12757                 :                :      * UPDATE action on the referenced table.
                              12758                 :                :      */
                              12759                 :           1381 :     fk_trigger = makeNode(CreateTrigStmt);
 1247                         12760                 :           1381 :     fk_trigger->replace = false;
                              12761                 :           1381 :     fk_trigger->isconstraint = true;
 4554                         12762                 :           1381 :     fk_trigger->trigname = "RI_ConstraintTrigger_a";
 3709 rhaas@postgresql.org    12763                 :           1381 :     fk_trigger->relation = NULL;
 1247 tgl@sss.pgh.pa.us       12764                 :           1381 :     fk_trigger->args = NIL;
 7284                         12765                 :           1381 :     fk_trigger->row = true;
 4935                         12766                 :           1381 :     fk_trigger->timing = TRIGGER_TYPE_AFTER;
 5414                         12767                 :           1381 :     fk_trigger->events = TRIGGER_TYPE_UPDATE;
 5296                         12768                 :           1381 :     fk_trigger->columns = NIL;
 5259                         12769                 :           1381 :     fk_trigger->whenClause = NULL;
 1247                         12770                 :           1381 :     fk_trigger->transitionRels = NIL;
 3709 rhaas@postgresql.org    12771                 :           1381 :     fk_trigger->constrrel = NULL;
                              12772                 :                : 
 7284 tgl@sss.pgh.pa.us       12773   [ +  +  +  +  :           1381 :     switch (fkconstraint->fk_upd_action)
                                              +  - ]
                              12774                 :                :     {
                              12775                 :           1164 :         case FKCONSTR_ACTION_NOACTION:
 7115                         12776                 :           1164 :             fk_trigger->deferrable = fkconstraint->deferrable;
                              12777                 :           1164 :             fk_trigger->initdeferred = fkconstraint->initdeferred;
 7284                         12778                 :           1164 :             fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
                              12779                 :           1164 :             break;
                              12780                 :             21 :         case FKCONSTR_ACTION_RESTRICT:
                              12781                 :             21 :             fk_trigger->deferrable = false;
                              12782                 :             21 :             fk_trigger->initdeferred = false;
                              12783                 :             21 :             fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
                              12784                 :             21 :             break;
                              12785                 :            144 :         case FKCONSTR_ACTION_CASCADE:
 7115                         12786                 :            144 :             fk_trigger->deferrable = false;
                              12787                 :            144 :             fk_trigger->initdeferred = false;
 7284                         12788                 :            144 :             fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
                              12789                 :            144 :             break;
                              12790                 :             31 :         case FKCONSTR_ACTION_SETNULL:
 7115                         12791                 :             31 :             fk_trigger->deferrable = false;
                              12792                 :             31 :             fk_trigger->initdeferred = false;
 7284                         12793                 :             31 :             fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
                              12794                 :             31 :             break;
                              12795                 :             21 :         case FKCONSTR_ACTION_SETDEFAULT:
 7115                         12796                 :             21 :             fk_trigger->deferrable = false;
                              12797                 :             21 :             fk_trigger->initdeferred = false;
 7284                         12798                 :             21 :             fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
                              12799                 :             21 :             break;
 7284 tgl@sss.pgh.pa.us       12800                 :UBC           0 :         default:
                              12801         [ #  # ]:              0 :             elog(ERROR, "unrecognized FK action type: %d",
                              12802                 :                :                  (int) fkconstraint->fk_upd_action);
                              12803                 :                :             break;
                              12804                 :                :     }
                              12805                 :                : 
  830 alvherre@alvh.no-ip.    12806                 :CBC        1381 :     trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
                              12807                 :                :                                 RelationGetRelid(rel),
                              12808                 :                :                                 constraintOid, indexOid, InvalidOid,
                              12809                 :                :                                 parentUpdTrigger, NULL, true, false);
                              12810         [ +  + ]:           1381 :     if (updateTrigOid)
                              12811                 :           1348 :         *updateTrigOid = trigAddress.objectId;
 2202                         12812                 :           1381 : }
                              12813                 :                : 
                              12814                 :                : /*
                              12815                 :                :  * createForeignKeyCheckTriggers
                              12816                 :                :  *      Create the referencing-side "check" triggers that implement a foreign
                              12817                 :                :  *      key.
                              12818                 :                :  *
                              12819                 :                :  * Returns the OIDs of the so created triggers in *insertTrigOid and
                              12820                 :                :  * *updateTrigOid.
                              12821                 :                :  */
                              12822                 :                : static void
                              12823                 :           1373 : createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
                              12824                 :                :                               Constraint *fkconstraint, Oid constraintOid,
                              12825                 :                :                               Oid indexOid,
                              12826                 :                :                               Oid parentInsTrigger, Oid parentUpdTrigger,
                              12827                 :                :                               Oid *insertTrigOid, Oid *updateTrigOid)
                              12828                 :                : {
  830                         12829                 :           1373 :     *insertTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
                              12830                 :                :                                           constraintOid, indexOid,
                              12831                 :                :                                           parentInsTrigger, true);
                              12832                 :           1373 :     *updateTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
                              12833                 :                :                                           constraintOid, indexOid,
                              12834                 :                :                                           parentUpdTrigger, false);
 7284 tgl@sss.pgh.pa.us       12835                 :           1373 : }
                              12836                 :                : 
                              12837                 :                : /*
                              12838                 :                :  * ALTER TABLE DROP CONSTRAINT
                              12839                 :                :  *
                              12840                 :                :  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
                              12841                 :                :  */
                              12842                 :                : static void
 5819                         12843                 :            470 : ATExecDropConstraint(Relation rel, const char *constrName,
                              12844                 :                :                      DropBehavior behavior, bool recurse,
                              12845                 :                :                      bool missing_ok, LOCKMODE lockmode)
                              12846                 :                : {
                              12847                 :                :     Relation    conrel;
                              12848                 :                :     SysScanDesc scan;
                              12849                 :                :     ScanKeyData skey[3];
                              12850                 :                :     HeapTuple   tuple;
                              12851                 :            470 :     bool        found = false;
                              12852                 :                : 
 1910 andres@anarazel.de      12853                 :            470 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
                              12854                 :                : 
                              12855                 :                :     /*
                              12856                 :                :      * Find and drop the target constraint
                              12857                 :                :      */
 2049 tgl@sss.pgh.pa.us       12858                 :            470 :     ScanKeyInit(&skey[0],
                              12859                 :                :                 Anum_pg_constraint_conrelid,
                              12860                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              12861                 :                :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                              12862                 :            470 :     ScanKeyInit(&skey[1],
                              12863                 :                :                 Anum_pg_constraint_contypid,
                              12864                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              12865                 :                :                 ObjectIdGetDatum(InvalidOid));
                              12866                 :            470 :     ScanKeyInit(&skey[2],
                              12867                 :                :                 Anum_pg_constraint_conname,
                              12868                 :                :                 BTEqualStrategyNumber, F_NAMEEQ,
                              12869                 :                :                 CStringGetDatum(constrName));
                              12870                 :            470 :     scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
                              12871                 :                :                               true, NULL, 3, skey);
                              12872                 :                : 
                              12873                 :                :     /* There can be at most one matching row */
                              12874         [ +  + ]:            470 :     if (HeapTupleIsValid(tuple = systable_getnext(scan)))
                              12875                 :                :     {
  233 alvherre@alvh.no-ip.    12876                 :GNC         452 :         List       *readyRels = NIL;
                              12877                 :                : 
  220                         12878                 :            452 :         dropconstraint_internal(rel, tuple, behavior, recurse, false,
                              12879                 :                :                                 missing_ok, &readyRels, lockmode);
  233 alvherre@alvh.no-ip.    12880                 :CBC         365 :         found = true;
                              12881                 :                :     }
                              12882                 :                : 
                              12883                 :            383 :     systable_endscan(scan);
                              12884                 :                : 
                              12885         [ +  + ]:            383 :     if (!found)
                              12886                 :                :     {
                              12887         [ +  + ]:             18 :         if (!missing_ok)
 5819 tgl@sss.pgh.pa.us       12888         [ +  - ]:             12 :             ereport(ERROR,
                              12889                 :                :                     errcode(ERRCODE_UNDEFINED_OBJECT),
                              12890                 :                :                     errmsg("constraint \"%s\" of relation \"%s\" does not exist",
                              12891                 :                :                            constrName, RelationGetRelationName(rel)));
                              12892                 :                :         else
  233 alvherre@alvh.no-ip.    12893         [ +  - ]:              6 :             ereport(NOTICE,
                              12894                 :                :                     errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
                              12895                 :                :                            constrName, RelationGetRelationName(rel)));
                              12896                 :                :     }
                              12897                 :                : 
  233 alvherre@alvh.no-ip.    12898                 :GNC         371 :     table_close(conrel, RowExclusiveLock);
                              12899                 :            371 : }
                              12900                 :                : 
                              12901                 :                : /*
                              12902                 :                :  * Remove a constraint, using its pg_constraint tuple
                              12903                 :                :  *
                              12904                 :                :  * Implementation for ALTER TABLE DROP CONSTRAINT and ALTER TABLE ALTER COLUMN
                              12905                 :                :  * DROP NOT NULL.
                              12906                 :                :  *
                              12907                 :                :  * Returns the address of the constraint being removed.
                              12908                 :                :  */
                              12909                 :                : static ObjectAddress
                              12910                 :            643 : dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior behavior,
                              12911                 :                :                         bool recurse, bool recursing, bool missing_ok, List **readyRels,
                              12912                 :                :                         LOCKMODE lockmode)
                              12913                 :                : {
                              12914                 :                :     Relation    conrel;
                              12915                 :                :     Form_pg_constraint con;
                              12916                 :                :     ObjectAddress conobj;
                              12917                 :                :     List       *children;
                              12918                 :                :     ListCell   *child;
                              12919                 :            643 :     bool        is_no_inherit_constraint = false;
                              12920                 :            643 :     bool        dropping_pk = false;
                              12921                 :                :     char       *constrName;
                              12922                 :            643 :     List       *unconstrained_cols = NIL;
                              12923                 :                :     char       *colname;
                              12924                 :                : 
                              12925         [ -  + ]:            643 :     if (list_member_oid(*readyRels, RelationGetRelid(rel)))
  233 alvherre@alvh.no-ip.    12926                 :UNC           0 :         return InvalidObjectAddress;
  233 alvherre@alvh.no-ip.    12927                 :GNC         643 :     *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
                              12928                 :                : 
                              12929                 :                :     /* Guard against stack overflow due to overly deep inheritance tree. */
  158                         12930                 :            643 :     check_stack_depth();
                              12931                 :                : 
                              12932                 :                :     /* At top level, permission check was done in ATPrepCmd, else do it */
  220                         12933         [ +  + ]:            643 :     if (recursing)
                              12934                 :            111 :         ATSimplePermissions(AT_DropConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                              12935                 :                : 
  233                         12936                 :            640 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
                              12937                 :                : 
                              12938                 :            640 :     con = (Form_pg_constraint) GETSTRUCT(constraintTup);
                              12939                 :            640 :     constrName = NameStr(con->conname);
                              12940                 :                : 
                              12941                 :                :     /* Don't allow drop of inherited constraints */
                              12942   [ +  +  +  + ]:            640 :     if (con->coninhcount > 0 && !recursing)
                              12943         [ +  - ]:             69 :         ereport(ERROR,
                              12944                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              12945                 :                :                  errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
                              12946                 :                :                         constrName, RelationGetRelationName(rel))));
                              12947                 :                : 
                              12948                 :                :     /*
                              12949                 :                :      * See if we have a not-null constraint or a PRIMARY KEY.  If so, we have
                              12950                 :                :      * more checks and actions below, so obtain the list of columns that are
                              12951                 :                :      * constrained by the constraint being dropped.
                              12952                 :                :      */
                              12953         [ +  + ]:            571 :     if (con->contype == CONSTRAINT_NOTNULL)
                              12954                 :                :     {
                              12955                 :            216 :         AttrNumber  colnum = extractNotNullColumn(constraintTup);
                              12956                 :                : 
                              12957         [ +  - ]:            216 :         if (colnum != InvalidAttrNumber)
                              12958                 :            216 :             unconstrained_cols = list_make1_int(colnum);
                              12959                 :                :     }
                              12960         [ +  + ]:            355 :     else if (con->contype == CONSTRAINT_PRIMARY)
                              12961                 :                :     {
                              12962                 :                :         Datum       adatum;
                              12963                 :                :         ArrayType  *arr;
                              12964                 :                :         int         numkeys;
                              12965                 :                :         bool        isNull;
                              12966                 :                :         int16      *attnums;
                              12967                 :                : 
                              12968                 :             70 :         dropping_pk = true;
                              12969                 :                : 
                              12970                 :             70 :         adatum = heap_getattr(constraintTup, Anum_pg_constraint_conkey,
                              12971                 :                :                               RelationGetDescr(conrel), &isNull);
                              12972         [ -  + ]:             70 :         if (isNull)
  233 alvherre@alvh.no-ip.    12973         [ #  # ]:UNC           0 :             elog(ERROR, "null conkey for constraint %u", con->oid);
  233 alvherre@alvh.no-ip.    12974                 :GNC          70 :         arr = DatumGetArrayTypeP(adatum);   /* ensure not toasted */
                              12975                 :             70 :         numkeys = ARR_DIMS(arr)[0];
                              12976   [ +  -  +  - ]:             70 :         if (ARR_NDIM(arr) != 1 ||
                              12977                 :             70 :             numkeys < 0 ||
                              12978         [ +  - ]:             70 :             ARR_HASNULL(arr) ||
                              12979         [ -  + ]:             70 :             ARR_ELEMTYPE(arr) != INT2OID)
  233 alvherre@alvh.no-ip.    12980         [ #  # ]:UNC           0 :             elog(ERROR, "conkey is not a 1-D smallint array");
  233 alvherre@alvh.no-ip.    12981         [ -  + ]:GNC          70 :         attnums = (int16 *) ARR_DATA_PTR(arr);
                              12982                 :                : 
                              12983         [ +  + ]:            159 :         for (int i = 0; i < numkeys; i++)
                              12984                 :             89 :             unconstrained_cols = lappend_int(unconstrained_cols, attnums[i]);
                              12985                 :                :     }
                              12986                 :                : 
                              12987                 :            571 :     is_no_inherit_constraint = con->connoinherit;
                              12988                 :                : 
                              12989                 :                :     /*
                              12990                 :                :      * If it's a foreign-key constraint, we'd better lock the referenced table
                              12991                 :                :      * and check that that's not in use, just as we've already done for the
                              12992                 :                :      * constrained table (else we might, eg, be dropping a trigger that has
                              12993                 :                :      * unfired events).  But we can/must skip that in the self-referential
                              12994                 :                :      * case.
                              12995                 :                :      */
                              12996         [ +  + ]:            571 :     if (con->contype == CONSTRAINT_FOREIGN &&
                              12997         [ +  - ]:             96 :         con->confrelid != RelationGetRelid(rel))
                              12998                 :                :     {
                              12999                 :                :         Relation    frel;
                              13000                 :                : 
                              13001                 :                :         /* Must match lock taken by RemoveTriggerById: */
                              13002                 :             96 :         frel = table_open(con->confrelid, AccessExclusiveLock);
                              13003                 :             96 :         CheckTableNotInUse(frel, "ALTER TABLE");
                              13004                 :             93 :         table_close(frel, NoLock);
                              13005                 :                :     }
                              13006                 :                : 
                              13007                 :                :     /*
                              13008                 :                :      * Perform the actual constraint deletion
                              13009                 :                :      */
                              13010                 :            568 :     ObjectAddressSet(conobj, ConstraintRelationId, con->oid);
                              13011                 :            568 :     performDeletion(&conobj, behavior, 0);
                              13012                 :                : 
                              13013                 :                :     /*
                              13014                 :                :      * If this was a NOT NULL or the primary key, the constrained columns must
                              13015                 :                :      * have had pg_attribute.attnotnull set.  See if we need to reset it, and
                              13016                 :                :      * do so.
                              13017                 :                :      */
                              13018         [ +  + ]:            550 :     if (unconstrained_cols)
                              13019                 :                :     {
                              13020                 :                :         Relation    attrel;
                              13021                 :                :         Bitmapset  *pkcols;
                              13022                 :                :         Bitmapset  *ircols;
                              13023                 :                :         ListCell   *lc;
                              13024                 :                : 
                              13025                 :                :         /* Make the above deletion visible */
                              13026                 :            268 :         CommandCounterIncrement();
                              13027                 :                : 
                              13028                 :            268 :         attrel = table_open(AttributeRelationId, RowExclusiveLock);
                              13029                 :                : 
                              13030                 :                :         /*
                              13031                 :                :          * We want to test columns for their presence in the primary key, but
                              13032                 :                :          * only if we're not dropping it.
                              13033                 :                :          */
                              13034         [ +  + ]:            268 :         pkcols = dropping_pk ? NULL :
                              13035                 :            216 :             RelationGetIndexAttrBitmap(rel,
                              13036                 :                :                                        INDEX_ATTR_BITMAP_PRIMARY_KEY);
                              13037                 :            268 :         ircols = RelationGetIndexAttrBitmap(rel, INDEX_ATTR_BITMAP_IDENTITY_KEY);
                              13038                 :                : 
                              13039   [ +  -  +  +  :            540 :         foreach(lc, unconstrained_cols)
                                              +  + ]
                              13040                 :                :         {
                              13041                 :            281 :             AttrNumber  attnum = lfirst_int(lc);
                              13042                 :                :             HeapTuple   atttup;
                              13043                 :                :             HeapTuple   contup;
                              13044                 :                :             Form_pg_attribute attForm;
                              13045                 :                : 
                              13046                 :                :             /*
                              13047                 :                :              * Obtain pg_attribute tuple and verify conditions on it.  We use
                              13048                 :                :              * a copy we can scribble on.
                              13049                 :                :              */
                              13050                 :            281 :             atttup = SearchSysCacheCopyAttNum(RelationGetRelid(rel), attnum);
                              13051         [ -  + ]:            281 :             if (!HeapTupleIsValid(atttup))
  233 alvherre@alvh.no-ip.    13052         [ #  # ]:UNC           0 :                 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
                              13053                 :                :                      attnum, RelationGetRelid(rel));
  233 alvherre@alvh.no-ip.    13054                 :GNC         281 :             attForm = (Form_pg_attribute) GETSTRUCT(atttup);
                              13055                 :                : 
                              13056                 :                :             /*
                              13057                 :                :              * Since the above deletion has been made visible, we can now
                              13058                 :                :              * search for any remaining constraints on this column (or these
                              13059                 :                :              * columns, in the case we're dropping a multicol primary key.)
                              13060                 :                :              * Then, verify whether any further NOT NULL or primary key
                              13061                 :                :              * exists, and reset attnotnull if none.
                              13062                 :                :              *
                              13063                 :                :              * However, if this is a generated identity column, abort the
                              13064                 :                :              * whole thing with a specific error message, because the
                              13065                 :                :              * constraint is required in that case.
                              13066                 :                :              */
                              13067                 :            281 :             contup = findNotNullConstraintAttnum(RelationGetRelid(rel), attnum);
                              13068   [ +  +  +  + ]:            553 :             if (contup ||
                              13069                 :            272 :                 bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
                              13070                 :                :                               pkcols))
                              13071                 :            119 :                 continue;
                              13072                 :                : 
                              13073                 :                :             /*
                              13074                 :                :              * It's not valid to drop the not-null constraint for a GENERATED
                              13075                 :                :              * AS IDENTITY column.
                              13076                 :                :              */
                              13077         [ -  + ]:            162 :             if (attForm->attidentity)
  233 alvherre@alvh.no-ip.    13078         [ #  # ]:UNC           0 :                 ereport(ERROR,
                              13079                 :                :                         errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              13080                 :                :                         errmsg("column \"%s\" of relation \"%s\" is an identity column",
                              13081                 :                :                                get_attname(RelationGetRelid(rel), attnum,
                              13082                 :                :                                            false),
                              13083                 :                :                                RelationGetRelationName(rel)));
                              13084                 :                : 
                              13085                 :                :             /*
                              13086                 :                :              * It's not valid to drop the not-null constraint for a column in
                              13087                 :                :              * the replica identity index, either. (FULL is not affected.)
                              13088                 :                :              */
  233 alvherre@alvh.no-ip.    13089         [ +  + ]:GNC         162 :             if (bms_is_member(lfirst_int(lc) - FirstLowInvalidHeapAttributeNumber, ircols))
                              13090         [ +  - ]:              9 :                 ereport(ERROR,
                              13091                 :                :                         errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              13092                 :                :                         errmsg("column \"%s\" is in index used as replica identity",
                              13093                 :                :                                get_attname(RelationGetRelid(rel), lfirst_int(lc), false)));
                              13094                 :                : 
                              13095                 :                :             /* Reset attnotnull */
                              13096         [ +  - ]:            153 :             if (attForm->attnotnull)
                              13097                 :                :             {
                              13098                 :            153 :                 attForm->attnotnull = false;
                              13099                 :            153 :                 CatalogTupleUpdate(attrel, &atttup->t_self, atttup);
                              13100                 :                :             }
                              13101                 :                :         }
                              13102                 :            259 :         table_close(attrel, RowExclusiveLock);
                              13103                 :                :     }
                              13104                 :                : 
                              13105                 :                :     /*
                              13106                 :                :      * For partitioned tables, non-CHECK, non-NOT-NULL inherited constraints
                              13107                 :                :      * are dropped via the dependency mechanism, so we're done here.
                              13108                 :                :      */
                              13109         [ +  + ]:            541 :     if (con->contype != CONSTRAINT_CHECK &&
                              13110         [ +  + ]:            379 :         con->contype != CONSTRAINT_NOTNULL &&
 1907 alvherre@alvh.no-ip.    13111         [ +  + ]:CBC         169 :         rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              13112                 :                :     {
                              13113                 :             33 :         table_close(conrel, RowExclusiveLock);
  233 alvherre@alvh.no-ip.    13114                 :GNC          33 :         return conobj;
                              13115                 :                :     }
                              13116                 :                : 
                              13117                 :                :     /*
                              13118                 :                :      * Propagate to children as appropriate.  Unlike most other ALTER
                              13119                 :                :      * routines, we have to do this one level of recursion at a time; we can't
                              13120                 :                :      * use find_all_inheritors to do it in one pass.
                              13121                 :                :      */
 4377 alvherre@alvh.no-ip.    13122         [ +  + ]:CBC         508 :     if (!is_no_inherit_constraint)
 1082                         13123                 :            268 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
                              13124                 :                :     else
 5819 tgl@sss.pgh.pa.us       13125                 :            240 :         children = NIL;
                              13126                 :                : 
                              13127                 :                :     /*
                              13128                 :                :      * For a partitioned table, if partitions exist and we are told not to
                              13129                 :                :      * recurse, it's a user error.  It doesn't make sense to have a constraint
                              13130                 :                :      * be defined only on the parent, especially if it's a partitioned table.
                              13131                 :                :      */
 2546 sfrost@snowman.net      13132   [ +  +  +  + ]:            508 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
                              13133         [ +  + ]:             31 :         children != NIL && !recurse)
                              13134         [ +  - ]:              3 :         ereport(ERROR,
                              13135                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              13136                 :                :                  errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
                              13137                 :                :                  errhint("Do not specify the ONLY keyword.")));
                              13138                 :                : 
                              13139                 :                :     /* For not-null constraints we recurse by column name */
  233 alvherre@alvh.no-ip.    13140         [ +  + ]:GNC         505 :     if (con->contype == CONSTRAINT_NOTNULL)
                              13141                 :            210 :         colname = NameStr(TupleDescAttr(RelationGetDescr(rel),
                              13142                 :                :                                         linitial_int(unconstrained_cols) - 1)->attname);
                              13143                 :                :     else
                              13144                 :            295 :         colname = NULL;         /* keep compiler quiet */
                              13145                 :                : 
 5819 tgl@sss.pgh.pa.us       13146   [ +  +  +  +  :CBC         646 :     foreach(child, children)
                                              +  + ]
                              13147                 :                :     {
                              13148                 :            144 :         Oid         childrelid = lfirst_oid(child);
                              13149                 :                :         Relation    childrel;
                              13150                 :                :         HeapTuple   tuple;
                              13151                 :                :         Form_pg_constraint childcon;
                              13152                 :                : 
  233 alvherre@alvh.no-ip.    13153         [ +  + ]:GNC         144 :         if (list_member_oid(*readyRels, childrelid))
                              13154                 :              3 :             continue;           /* child already processed */
                              13155                 :                : 
                              13156                 :                :         /* find_inheritance_children already got lock */
 1910 andres@anarazel.de      13157                 :CBC         141 :         childrel = table_open(childrelid, NoLock);
 5819 tgl@sss.pgh.pa.us       13158                 :            141 :         CheckTableNotInUse(childrel, "ALTER TABLE");
                              13159                 :                : 
                              13160                 :                :         /*
                              13161                 :                :          * We search for not-null constraint by column number, and other
                              13162                 :                :          * constraints by name.
                              13163                 :                :          */
  233 alvherre@alvh.no-ip.    13164         [ +  + ]:GNC         141 :         if (con->contype == CONSTRAINT_NOTNULL)
                              13165                 :                :         {
                              13166                 :             41 :             tuple = findNotNullConstraint(childrelid, colname);
                              13167         [ -  + ]:             41 :             if (!HeapTupleIsValid(tuple))
  233 alvherre@alvh.no-ip.    13168         [ #  # ]:UNC           0 :                 elog(ERROR, "cache lookup failed for not-null constraint on column \"%s\" of relation %u",
                              13169                 :                :                      colname, RelationGetRelid(childrel));
                              13170                 :                :         }
                              13171                 :                :         else
                              13172                 :                :         {
                              13173                 :                :             SysScanDesc scan;
                              13174                 :                :             ScanKeyData skey[3];
                              13175                 :                : 
  233 alvherre@alvh.no-ip.    13176                 :GNC         100 :             ScanKeyInit(&skey[0],
                              13177                 :                :                         Anum_pg_constraint_conrelid,
                              13178                 :                :                         BTEqualStrategyNumber, F_OIDEQ,
                              13179                 :                :                         ObjectIdGetDatum(childrelid));
                              13180                 :            100 :             ScanKeyInit(&skey[1],
                              13181                 :                :                         Anum_pg_constraint_contypid,
                              13182                 :                :                         BTEqualStrategyNumber, F_OIDEQ,
                              13183                 :                :                         ObjectIdGetDatum(InvalidOid));
                              13184                 :            100 :             ScanKeyInit(&skey[2],
                              13185                 :                :                         Anum_pg_constraint_conname,
                              13186                 :                :                         BTEqualStrategyNumber, F_NAMEEQ,
                              13187                 :                :                         CStringGetDatum(constrName));
                              13188                 :            100 :             scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
                              13189                 :                :                                       true, NULL, 3, skey);
                              13190                 :                :             /* There can only be one, so no need to loop */
                              13191                 :            100 :             tuple = systable_getnext(scan);
                              13192         [ -  + ]:            100 :             if (!HeapTupleIsValid(tuple))
  233 alvherre@alvh.no-ip.    13193         [ #  # ]:UNC           0 :                 ereport(ERROR,
                              13194                 :                :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
                              13195                 :                :                          errmsg("constraint \"%s\" of relation \"%s\" does not exist",
                              13196                 :                :                                 constrName,
                              13197                 :                :                                 RelationGetRelationName(childrel))));
  233 alvherre@alvh.no-ip.    13198                 :GNC         100 :             tuple = heap_copytuple(tuple);
                              13199                 :            100 :             systable_endscan(scan);
                              13200                 :                :         }
                              13201                 :                : 
                              13202                 :            141 :         childcon = (Form_pg_constraint) GETSTRUCT(tuple);
                              13203                 :                : 
                              13204                 :                :         /* Right now only CHECK and not-null constraints can be inherited */
                              13205         [ +  + ]:            141 :         if (childcon->contype != CONSTRAINT_CHECK &&
                              13206         [ -  + ]:             41 :             childcon->contype != CONSTRAINT_NOTNULL)
  233 alvherre@alvh.no-ip.    13207         [ #  # ]:UNC           0 :             elog(ERROR, "inherited constraint is not a CHECK or not-null constraint");
                              13208                 :                : 
  233 alvherre@alvh.no-ip.    13209         [ -  + ]:GNC         141 :         if (childcon->coninhcount <= 0) /* shouldn't happen */
 4571 rhaas@postgresql.org    13210         [ #  # ]:UBC           0 :             elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
                              13211                 :                :                  childrelid, NameStr(childcon->conname));
                              13212                 :                : 
 4571 rhaas@postgresql.org    13213         [ +  + ]:CBC         141 :         if (recurse)
                              13214                 :                :         {
                              13215                 :                :             /*
                              13216                 :                :              * If the child constraint has other definition sources, just
                              13217                 :                :              * decrement its inheritance count; if not, recurse to delete it.
                              13218                 :                :              */
  233 alvherre@alvh.no-ip.    13219   [ +  +  +  + ]:GNC         138 :             if (childcon->coninhcount == 1 && !childcon->conislocal)
                              13220                 :                :             {
                              13221                 :                :                 /* Time to delete this child constraint, too */
                              13222                 :             99 :                 dropconstraint_internal(childrel, tuple, behavior,
                              13223                 :                :                                         recurse, true, missing_ok, readyRels,
                              13224                 :                :                                         lockmode);
                              13225                 :                :             }
                              13226                 :                :             else
                              13227                 :                :             {
                              13228                 :                :                 /* Child constraint must survive my deletion */
                              13229                 :             39 :                 childcon->coninhcount--;
                              13230                 :             39 :                 CatalogTupleUpdate(conrel, &tuple->t_self, tuple);
                              13231                 :                : 
                              13232                 :                :                 /* Make update visible */
 5819 tgl@sss.pgh.pa.us       13233                 :CBC          39 :                 CommandCounterIncrement();
                              13234                 :                :             }
                              13235                 :                :         }
                              13236                 :                :         else
                              13237                 :                :         {
                              13238                 :                :             /*
                              13239                 :                :              * If we were told to drop ONLY in this table (no recursion) and
                              13240                 :                :              * there are no further parents for this constraint, we need to
                              13241                 :                :              * mark the inheritors' constraints as locally defined rather than
                              13242                 :                :              * inherited.
                              13243                 :                :              */
  233 alvherre@alvh.no-ip.    13244                 :GNC           3 :             childcon->coninhcount--;
                              13245         [ +  - ]:              3 :             if (childcon->coninhcount == 0)
                              13246                 :              3 :                 childcon->conislocal = true;
                              13247                 :                : 
                              13248                 :              3 :             CatalogTupleUpdate(conrel, &tuple->t_self, tuple);
                              13249                 :                : 
                              13250                 :                :             /* Make update visible */
 4571 rhaas@postgresql.org    13251                 :CBC           3 :             CommandCounterIncrement();
                              13252                 :                :         }
                              13253                 :                : 
  233 alvherre@alvh.no-ip.    13254                 :GNC         138 :         heap_freetuple(tuple);
                              13255                 :                : 
 1910 andres@anarazel.de      13256                 :CBC         138 :         table_close(childrel, NoLock);
                              13257                 :                :     }
                              13258                 :                : 
                              13259                 :                :     /*
                              13260                 :                :      * In addition, when dropping a primary key from a legacy-inheritance
                              13261                 :                :      * parent table, we must recurse to children to mark the corresponding NOT
                              13262                 :                :      * NULL constraint as no longer inherited, or drop it if this its last
                              13263                 :                :      * reference.
                              13264                 :                :      */
  233 alvherre@alvh.no-ip.    13265         [ +  + ]:GNC         502 :     if (con->contype == CONSTRAINT_PRIMARY &&
                              13266         [ +  - ]:             46 :         rel->rd_rel->relkind == RELKIND_RELATION &&
                              13267         [ +  + ]:             46 :         rel->rd_rel->relhassubclass)
                              13268                 :                :     {
                              13269                 :              6 :         List       *colnames = NIL;
                              13270                 :                :         ListCell   *lc;
                              13271                 :              6 :         List       *pkready = NIL;
                              13272                 :                : 
                              13273                 :                :         /*
                              13274                 :                :          * Because primary keys are always marked as NO INHERIT, we don't have
                              13275                 :                :          * a list of children yet, so obtain one now.
                              13276                 :                :          */
                              13277                 :              6 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
                              13278                 :                : 
                              13279                 :                :         /*
                              13280                 :                :          * Find out the list of column names to process.  Fortunately, we
                              13281                 :                :          * already have the list of column numbers.
                              13282                 :                :          */
                              13283   [ +  -  +  +  :             12 :         foreach(lc, unconstrained_cols)
                                              +  + ]
                              13284                 :                :         {
                              13285                 :              6 :             colnames = lappend(colnames, get_attname(RelationGetRelid(rel),
                              13286                 :              6 :                                                      lfirst_int(lc), false));
                              13287                 :                :         }
                              13288                 :                : 
                              13289   [ +  -  +  +  :             18 :         foreach(child, children)
                                              +  + ]
                              13290                 :                :         {
                              13291                 :             12 :             Oid         childrelid = lfirst_oid(child);
                              13292                 :                :             Relation    childrel;
                              13293                 :                : 
                              13294         [ -  + ]:             12 :             if (list_member_oid(pkready, childrelid))
  233 alvherre@alvh.no-ip.    13295                 :UNC           0 :                 continue;       /* child already processed */
                              13296                 :                : 
                              13297                 :                :             /* find_inheritance_children already got lock */
  233 alvherre@alvh.no-ip.    13298                 :GNC          12 :             childrel = table_open(childrelid, NoLock);
                              13299                 :             12 :             CheckTableNotInUse(childrel, "ALTER TABLE");
                              13300                 :                : 
                              13301   [ +  -  +  +  :             24 :             foreach(lc, colnames)
                                              +  + ]
                              13302                 :                :             {
                              13303                 :                :                 HeapTuple   contup;
                              13304                 :             12 :                 char       *colName = lfirst(lc);
                              13305                 :                : 
                              13306                 :             12 :                 contup = findNotNullConstraint(childrelid, colName);
                              13307         [ -  + ]:             12 :                 if (contup == NULL)
  233 alvherre@alvh.no-ip.    13308         [ #  # ]:UNC           0 :                     elog(ERROR, "cache lookup failed for not-null constraint on column \"%s\", relation \"%s\"",
                              13309                 :                :                          colName, RelationGetRelationName(childrel));
                              13310                 :                : 
  233 alvherre@alvh.no-ip.    13311                 :GNC          12 :                 dropconstraint_internal(childrel, contup,
                              13312                 :                :                                         DROP_RESTRICT, true, true,
                              13313                 :                :                                         false, &pkready,
                              13314                 :                :                                         lockmode);
                              13315                 :             12 :                 pkready = NIL;
                              13316                 :                :             }
                              13317                 :                : 
                              13318                 :             12 :             table_close(childrel, NoLock);
                              13319                 :                : 
                              13320                 :             12 :             pkready = lappend_oid(pkready, childrelid);
                              13321                 :                :         }
                              13322                 :                :     }
                              13323                 :                : 
 1910 andres@anarazel.de      13324                 :CBC         502 :     table_close(conrel, RowExclusiveLock);
                              13325                 :                : 
  233 alvherre@alvh.no-ip.    13326                 :GNC         502 :     return conobj;
                              13327                 :                : }
                              13328                 :                : 
                              13329                 :                : /*
                              13330                 :                :  * ALTER COLUMN TYPE
                              13331                 :                :  *
                              13332                 :                :  * Unlike other subcommand types, we do parse transformation for ALTER COLUMN
                              13333                 :                :  * TYPE during phase 1 --- the AlterTableCmd passed in here is already
                              13334                 :                :  * transformed (and must be, because we rely on some transformed fields).
                              13335                 :                :  *
                              13336                 :                :  * The point of this is that the execution of all ALTER COLUMN TYPEs for a
                              13337                 :                :  * table will be done "in parallel" during phase 3, so all the USING
                              13338                 :                :  * expressions should be parsed assuming the original column types.  Also,
                              13339                 :                :  * this allows a USING expression to refer to a field that will be dropped.
                              13340                 :                :  *
                              13341                 :                :  * To make this work safely, AT_PASS_DROP then AT_PASS_ALTER_TYPE must be
                              13342                 :                :  * the first two execution steps in phase 2; they must not see the effects
                              13343                 :                :  * of any other subcommand types, since the USING expressions are parsed
                              13344                 :                :  * against the unmodified table's state.
                              13345                 :                :  */
                              13346                 :                : static void
 7284 tgl@sss.pgh.pa.us       13347                 :CBC         559 : ATPrepAlterColumnType(List **wqueue,
                              13348                 :                :                       AlteredTableInfo *tab, Relation rel,
                              13349                 :                :                       bool recurse, bool recursing,
                              13350                 :                :                       AlterTableCmd *cmd, LOCKMODE lockmode,
                              13351                 :                :                       AlterTableUtilityContext *context)
                              13352                 :                : {
                              13353                 :            559 :     char       *colName = cmd->name;
 4785                         13354                 :            559 :     ColumnDef  *def = (ColumnDef *) cmd->def;
                              13355                 :            559 :     TypeName   *typeName = def->typeName;
 3299 alvherre@alvh.no-ip.    13356                 :            559 :     Node       *transform = def->cooked_default;
                              13357                 :                :     HeapTuple   tuple;
                              13358                 :                :     Form_pg_attribute attTup;
                              13359                 :                :     AttrNumber  attnum;
                              13360                 :                :     Oid         targettype;
                              13361                 :                :     int32       targettypmod;
                              13362                 :                :     Oid         targetcollid;
                              13363                 :                :     NewColumnValue *newval;
 7284 tgl@sss.pgh.pa.us       13364                 :            559 :     ParseState *pstate = make_parsestate(NULL);
                              13365                 :                :     AclResult   aclresult;
                              13366                 :                :     bool        is_expr;
                              13367                 :                : 
 4891 peter_e@gmx.net         13368   [ +  +  +  + ]:            559 :     if (rel->rd_rel->reloftype && !recursing)
 5014                         13369         [ +  - ]:              3 :         ereport(ERROR,
                              13370                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              13371                 :                :                  errmsg("cannot alter column type of typed table")));
                              13372                 :                : 
                              13373                 :                :     /* lookup the attribute so we can check inheritance status */
 7284 tgl@sss.pgh.pa.us       13374                 :            556 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
                              13375         [ -  + ]:            556 :     if (!HeapTupleIsValid(tuple))
 7284 tgl@sss.pgh.pa.us       13376         [ #  # ]:UBC           0 :         ereport(ERROR,
                              13377                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                              13378                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                              13379                 :                :                         colName, RelationGetRelationName(rel))));
 7284 tgl@sss.pgh.pa.us       13380                 :CBC         556 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
                              13381                 :            556 :     attnum = attTup->attnum;
                              13382                 :                : 
                              13383                 :                :     /* Can't alter a system attribute */
                              13384         [ -  + ]:            556 :     if (attnum <= 0)
 7284 tgl@sss.pgh.pa.us       13385         [ #  # ]:UBC           0 :         ereport(ERROR,
                              13386                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              13387                 :                :                  errmsg("cannot alter system column \"%s\"",
                              13388                 :                :                         colName)));
                              13389                 :                : 
                              13390                 :                :     /*
                              13391                 :                :      * Don't alter inherited columns.  At outer level, there had better not be
                              13392                 :                :      * any inherited definition; when recursing, we assume this was checked at
                              13393                 :                :      * the parent level (see below).
                              13394                 :                :      */
 7284 tgl@sss.pgh.pa.us       13395   [ +  +  +  + ]:CBC         556 :     if (attTup->attinhcount > 0 && !recursing)
                              13396         [ +  - ]:              3 :         ereport(ERROR,
                              13397                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              13398                 :                :                  errmsg("cannot alter inherited column \"%s\"",
                              13399                 :                :                         colName)));
                              13400                 :                : 
                              13401                 :                :     /* Don't alter columns used in the partition key */
 2292 rhaas@postgresql.org    13402         [ +  + ]:            553 :     if (has_partition_attrs(rel,
                              13403                 :                :                             bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
                              13404                 :                :                             &is_expr))
 1728 tgl@sss.pgh.pa.us       13405         [ +  - ]:              9 :         ereport(ERROR,
                              13406                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              13407                 :                :                  errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
                              13408                 :                :                         colName, RelationGetRelationName(rel))));
                              13409                 :                : 
                              13410                 :                :     /* Look up the target type */
 4785                         13411                 :            544 :     typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
                              13412                 :                : 
  518 peter@eisentraut.org    13413                 :            544 :     aclresult = object_aclcheck(TypeRelationId, targettype, GetUserId(), ACL_USAGE);
 4499 peter_e@gmx.net         13414         [ +  + ]:            544 :     if (aclresult != ACLCHECK_OK)
 4321                         13415                 :              6 :         aclcheck_error_type(aclresult, targettype);
                              13416                 :                : 
                              13417                 :                :     /* And the collation */
 4785 tgl@sss.pgh.pa.us       13418                 :            538 :     targetcollid = GetColumnDefCollation(NULL, def, targettype);
                              13419                 :                : 
                              13420                 :                :     /* make sure datatype is legal for a column */
 4766                         13421                 :            538 :     CheckAttributeType(colName, targettype, targetcollid,
                              13422                 :            538 :                        list_make1_oid(rel->rd_rel->reltype),
                              13423                 :                :                        0);
                              13424                 :                : 
 2685 rhaas@postgresql.org    13425         [ +  + ]:            535 :     if (tab->relkind == RELKIND_RELATION ||
                              13426         [ +  + ]:             95 :         tab->relkind == RELKIND_PARTITIONED_TABLE)
                              13427                 :                :     {
                              13428                 :                :         /*
                              13429                 :                :          * Set up an expression to transform the old data value to the new
                              13430                 :                :          * type. If a USING option was given, use the expression as
                              13431                 :                :          * transformed by transformAlterTableStmt, else just take the old
                              13432                 :                :          * value and try to coerce it.  We do this first so that type
                              13433                 :                :          * incompatibility can be detected before we waste effort, and because
                              13434                 :                :          * we need the expression to be parsed against the original table row
                              13435                 :                :          * type.
                              13436                 :                :          */
 3299 alvherre@alvh.no-ip.    13437         [ +  + ]:            467 :         if (!transform)
                              13438                 :                :         {
 4949 peter_e@gmx.net         13439                 :            356 :             transform = (Node *) makeVar(1, attnum,
                              13440                 :                :                                          attTup->atttypid, attTup->atttypmod,
                              13441                 :                :                                          attTup->attcollation,
                              13442                 :                :                                          0);
                              13443                 :                :         }
                              13444                 :                : 
                              13445                 :            467 :         transform = coerce_to_target_type(pstate,
                              13446                 :                :                                           transform, exprType(transform),
                              13447                 :                :                                           targettype, targettypmod,
                              13448                 :                :                                           COERCION_ASSIGNMENT,
                              13449                 :                :                                           COERCE_IMPLICIT_CAST,
                              13450                 :                :                                           -1);
                              13451         [ +  + ]:            467 :         if (transform == NULL)
                              13452                 :                :         {
                              13453                 :                :             /* error text depends on whether USING was specified or not */
 3229 tgl@sss.pgh.pa.us       13454         [ +  + ]:             12 :             if (def->cooked_default != NULL)
                              13455         [ +  - ]:              3 :                 ereport(ERROR,
                              13456                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              13457                 :                :                          errmsg("result of USING clause for column \"%s\""
                              13458                 :                :                                 " cannot be cast automatically to type %s",
                              13459                 :                :                                 colName, format_type_be(targettype)),
                              13460                 :                :                          errhint("You might need to add an explicit cast.")));
                              13461                 :                :             else
                              13462         [ +  - ]:              9 :                 ereport(ERROR,
                              13463                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              13464                 :                :                          errmsg("column \"%s\" cannot be cast automatically to type %s",
                              13465                 :                :                                 colName, format_type_be(targettype)),
                              13466                 :                :                 /* translator: USING is SQL, don't translate it */
                              13467                 :                :                          errhint("You might need to specify \"USING %s::%s\".",
                              13468                 :                :                                  quote_identifier(colName),
                              13469                 :                :                                  format_type_with_typemod(targettype,
                              13470                 :                :                                                           targettypmod))));
                              13471                 :                :         }
                              13472                 :                : 
                              13473                 :                :         /* Fix collations after all else */
 4775                         13474                 :            455 :         assign_expr_collations(pstate, transform);
                              13475                 :                : 
                              13476                 :                :         /* Plan the expr now so we can accurately assess the need to rewrite. */
 4681 rhaas@postgresql.org    13477                 :            455 :         transform = (Node *) expression_planner((Expr *) transform);
                              13478                 :                : 
                              13479                 :                :         /*
                              13480                 :                :          * Add a work queue item to make ATRewriteTable update the column
                              13481                 :                :          * contents.
                              13482                 :                :          */
 4949 peter_e@gmx.net         13483                 :            455 :         newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
                              13484                 :            455 :         newval->attnum = attnum;
                              13485                 :            455 :         newval->expr = (Expr *) transform;
 1558 tgl@sss.pgh.pa.us       13486                 :            455 :         newval->is_generated = false;
                              13487                 :                : 
 4949 peter_e@gmx.net         13488                 :            455 :         tab->newvals = lappend(tab->newvals, newval);
 4810 rhaas@postgresql.org    13489         [ +  + ]:            828 :         if (ATColumnChangeRequiresRewrite(transform, attnum))
 3415 simon@2ndQuadrant.co    13490                 :            373 :             tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
                              13491                 :                :     }
 4785 tgl@sss.pgh.pa.us       13492         [ +  + ]:             68 :     else if (transform)
                              13493         [ +  - ]:              6 :         ereport(ERROR,
                              13494                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              13495                 :                :                  errmsg("\"%s\" is not a table",
                              13496                 :                :                         RelationGetRelationName(rel))));
                              13497                 :                : 
  829                         13498   [ +  +  +  -  :            517 :     if (!RELKIND_HAS_STORAGE(tab->relkind))
                                     +  -  +  -  +  
                                                 - ]
                              13499                 :                :     {
                              13500                 :                :         /*
                              13501                 :                :          * For relations without storage, do this check now.  Regular tables
                              13502                 :                :          * will check it later when the table is being rewritten.
                              13503                 :                :          */
 4811 rhaas@postgresql.org    13504                 :             89 :         find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
                              13505                 :                :     }
                              13506                 :                : 
 7284 tgl@sss.pgh.pa.us       13507                 :            502 :     ReleaseSysCache(tuple);
                              13508                 :                : 
                              13509                 :                :     /*
                              13510                 :                :      * Recurse manually by queueing a new command for each child, if
                              13511                 :                :      * necessary. We cannot apply ATSimpleRecursion here because we need to
                              13512                 :                :      * remap attribute numbers in the USING expression, if any.
                              13513                 :                :      *
                              13514                 :                :      * If we are told not to recurse, there had better not be any child
                              13515                 :                :      * tables; else the alter would put them out of step.
                              13516                 :                :      */
                              13517         [ +  + ]:            502 :     if (recurse)
                              13518                 :                :     {
 2652 alvherre@alvh.no-ip.    13519                 :            382 :         Oid         relid = RelationGetRelid(rel);
                              13520                 :                :         List       *child_oids,
                              13521                 :                :                    *child_numparents;
                              13522                 :                :         ListCell   *lo,
                              13523                 :                :                    *li;
                              13524                 :                : 
 1701 tgl@sss.pgh.pa.us       13525                 :            382 :         child_oids = find_all_inheritors(relid, lockmode,
                              13526                 :                :                                          &child_numparents);
                              13527                 :                : 
                              13528                 :                :         /*
                              13529                 :                :          * find_all_inheritors does the recursive search of the inheritance
                              13530                 :                :          * hierarchy, so all we have to do is process all of the relids in the
                              13531                 :                :          * list that it returns.
                              13532                 :                :          */
                              13533   [ +  -  +  +  :            859 :         forboth(lo, child_oids, li, child_numparents)
                                     +  -  +  +  +  
                                        +  +  -  +  
                                                 + ]
                              13534                 :                :         {
                              13535                 :            489 :             Oid         childrelid = lfirst_oid(lo);
                              13536                 :            489 :             int         numparents = lfirst_int(li);
                              13537                 :                :             Relation    childrel;
                              13538                 :                :             HeapTuple   childtuple;
                              13539                 :                :             Form_pg_attribute childattTup;
                              13540                 :                : 
 2652 alvherre@alvh.no-ip.    13541         [ +  + ]:            489 :             if (childrelid == relid)
                              13542                 :            382 :                 continue;
                              13543                 :                : 
                              13544                 :                :             /* find_all_inheritors already got lock */
                              13545                 :            107 :             childrel = relation_open(childrelid, NoLock);
                              13546                 :            107 :             CheckTableNotInUse(childrel, "ALTER TABLE");
                              13547                 :                : 
                              13548                 :                :             /*
                              13549                 :                :              * Verify that the child doesn't have any inherited definitions of
                              13550                 :                :              * this column that came from outside this inheritance hierarchy.
                              13551                 :                :              * (renameatt makes a similar test, though in a different way
                              13552                 :                :              * because of its different recursion mechanism.)
                              13553                 :                :              */
 1701 tgl@sss.pgh.pa.us       13554                 :            107 :             childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
                              13555                 :                :                                                colName);
                              13556         [ -  + ]:            107 :             if (!HeapTupleIsValid(childtuple))
 1701 tgl@sss.pgh.pa.us       13557         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              13558                 :                :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
                              13559                 :                :                          errmsg("column \"%s\" of relation \"%s\" does not exist",
                              13560                 :                :                                 colName, RelationGetRelationName(childrel))));
 1701 tgl@sss.pgh.pa.us       13561                 :CBC         107 :             childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
                              13562                 :                : 
                              13563         [ +  + ]:            107 :             if (childattTup->attinhcount > numparents)
                              13564         [ +  - ]:              3 :                 ereport(ERROR,
                              13565                 :                :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              13566                 :                :                          errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
                              13567                 :                :                                 colName, RelationGetRelationName(childrel))));
                              13568                 :                : 
                              13569                 :            104 :             ReleaseSysCache(childtuple);
                              13570                 :                : 
                              13571                 :                :             /*
                              13572                 :                :              * Remap the attribute numbers.  If no USING expression was
                              13573                 :                :              * specified, there is no need for this step.
                              13574                 :                :              */
 2652 alvherre@alvh.no-ip.    13575         [ +  + ]:            104 :             if (def->cooked_default)
                              13576                 :                :             {
                              13577                 :                :                 AttrMap    *attmap;
                              13578                 :                :                 bool        found_whole_row;
                              13579                 :                : 
                              13580                 :                :                 /* create a copy to scribble on */
                              13581                 :             36 :                 cmd = copyObject(cmd);
                              13582                 :                : 
 1579 michael@paquier.xyz     13583                 :             36 :                 attmap = build_attrmap_by_name(RelationGetDescr(childrel),
                              13584                 :                :                                                RelationGetDescr(rel),
                              13585                 :                :                                                false);
 2652 alvherre@alvh.no-ip.    13586                 :             72 :                 ((ColumnDef *) cmd->def)->cooked_default =
                              13587                 :             36 :                     map_variable_attnos(def->cooked_default,
                              13588                 :                :                                         1, 0,
                              13589                 :                :                                         attmap,
                              13590                 :                :                                         InvalidOid, &found_whole_row);
                              13591         [ +  + ]:             36 :                 if (found_whole_row)
                              13592         [ +  - ]:              3 :                     ereport(ERROR,
                              13593                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              13594                 :                :                              errmsg("cannot convert whole-row table reference"),
                              13595                 :                :                              errdetail("USING expression contains a whole-row table reference.")));
                              13596                 :             33 :                 pfree(attmap);
                              13597                 :                :             }
 1551 tgl@sss.pgh.pa.us       13598                 :            101 :             ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
 2652 alvherre@alvh.no-ip.    13599                 :             95 :             relation_close(childrel, NoLock);
                              13600                 :                :         }
                              13601                 :                :     }
 7284 tgl@sss.pgh.pa.us       13602   [ +  +  -  + ]:            145 :     else if (!recursing &&
 1082 alvherre@alvh.no-ip.    13603                 :             25 :              find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
 7284 tgl@sss.pgh.pa.us       13604         [ #  # ]:UBC           0 :         ereport(ERROR,
                              13605                 :                :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              13606                 :                :                  errmsg("type of inherited column \"%s\" must be changed in child tables too",
                              13607                 :                :                         colName)));
                              13608                 :                : 
 4891 peter_e@gmx.net         13609         [ +  + ]:CBC         490 :     if (tab->relkind == RELKIND_COMPOSITE_TYPE)
 1551 tgl@sss.pgh.pa.us       13610                 :             25 :         ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
 7284                         13611                 :            487 : }
                              13612                 :                : 
                              13613                 :                : /*
                              13614                 :                :  * When the data type of a column is changed, a rewrite might not be required
                              13615                 :                :  * if the new type is sufficiently identical to the old one, and the USING
                              13616                 :                :  * clause isn't trying to insert some other value.  It's safe to skip the
                              13617                 :                :  * rewrite in these cases:
                              13618                 :                :  *
                              13619                 :                :  * - the old type is binary coercible to the new type
                              13620                 :                :  * - the new type is an unconstrained domain over the old type
                              13621                 :                :  * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
                              13622                 :                :  *
                              13623                 :                :  * In the case of a constrained domain, we could get by with scanning the
                              13624                 :                :  * table and checking the constraint rather than actually rewriting it, but we
                              13625                 :                :  * don't currently try to do that.
                              13626                 :                :  */
                              13627                 :                : static bool
 4810 rhaas@postgresql.org    13628                 :            455 : ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
                              13629                 :                : {
                              13630         [ +  - ]:            455 :     Assert(expr != NULL);
                              13631                 :                : 
                              13632                 :                :     for (;;)
                              13633                 :                :     {
                              13634                 :                :         /* only one varno, so no need to check that */
 1429 tgl@sss.pgh.pa.us       13635   [ +  +  +  - ]:            507 :         if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
 4810 rhaas@postgresql.org    13636                 :             82 :             return false;
                              13637         [ +  + ]:            425 :         else if (IsA(expr, RelabelType))
                              13638                 :             46 :             expr = (Node *) ((RelabelType *) expr)->arg;
 4808                         13639         [ -  + ]:            379 :         else if (IsA(expr, CoerceToDomain))
                              13640                 :                :         {
 4808 rhaas@postgresql.org    13641                 :UBC           0 :             CoerceToDomain *d = (CoerceToDomain *) expr;
                              13642                 :                : 
 3332 tgl@sss.pgh.pa.us       13643         [ #  # ]:              0 :             if (DomainHasConstraints(d->resulttype))
 4808 rhaas@postgresql.org    13644                 :              0 :                 return true;
                              13645                 :              0 :             expr = (Node *) d->arg;
                              13646                 :                :         }
 1864 noah@leadboat.com       13647         [ +  + ]:CBC         379 :         else if (IsA(expr, FuncExpr))
                              13648                 :                :         {
                              13649                 :            279 :             FuncExpr   *f = (FuncExpr *) expr;
                              13650                 :                : 
                              13651         [ +  + ]:            279 :             switch (f->funcid)
                              13652                 :                :             {
                              13653                 :              9 :                 case F_TIMESTAMPTZ_TIMESTAMP:
                              13654                 :                :                 case F_TIMESTAMP_TIMESTAMPTZ:
                              13655         [ +  + ]:              9 :                     if (TimestampTimestampTzRequiresRewrite())
                              13656                 :              3 :                         return true;
                              13657                 :                :                     else
                              13658                 :              6 :                         expr = linitial(f->args);
                              13659                 :              6 :                     break;
                              13660                 :            270 :                 default:
                              13661                 :            270 :                     return true;
                              13662                 :                :             }
                              13663                 :                :         }
                              13664                 :                :         else
 4810 rhaas@postgresql.org    13665                 :            100 :             return true;
                              13666                 :                :     }
                              13667                 :                : }
                              13668                 :                : 
                              13669                 :                : /*
                              13670                 :                :  * ALTER COLUMN .. SET DATA TYPE
                              13671                 :                :  *
                              13672                 :                :  * Return the address of the modified column.
                              13673                 :                :  */
                              13674                 :                : static ObjectAddress
 7284 tgl@sss.pgh.pa.us       13675                 :            472 : ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                              13676                 :                :                       AlterTableCmd *cmd, LOCKMODE lockmode)
                              13677                 :                : {
 4785                         13678                 :            472 :     char       *colName = cmd->name;
                              13679                 :            472 :     ColumnDef  *def = (ColumnDef *) cmd->def;
                              13680                 :            472 :     TypeName   *typeName = def->typeName;
                              13681                 :                :     HeapTuple   heapTup;
                              13682                 :                :     Form_pg_attribute attTup,
                              13683                 :                :                 attOldTup;
                              13684                 :                :     AttrNumber  attnum;
                              13685                 :                :     HeapTuple   typeTuple;
                              13686                 :                :     Form_pg_type tform;
                              13687                 :                :     Oid         targettype;
                              13688                 :                :     int32       targettypmod;
                              13689                 :                :     Oid         targetcollid;
                              13690                 :                :     Node       *defaultexpr;
                              13691                 :                :     Relation    attrelation;
                              13692                 :                :     Relation    depRel;
                              13693                 :                :     ScanKeyData key[3];
                              13694                 :                :     SysScanDesc scan;
                              13695                 :                :     HeapTuple   depTup;
                              13696                 :                :     ObjectAddress address;
                              13697                 :                : 
                              13698                 :                :     /*
                              13699                 :                :      * Clear all the missing values if we're rewriting the table, since this
                              13700                 :                :      * renders them pointless.
                              13701                 :                :      */
 1921 andrew@dunslane.net     13702         [ +  + ]:            472 :     if (tab->rewrite)
                              13703                 :                :     {
                              13704                 :                :         Relation    newrel;
                              13705                 :                : 
 1910 andres@anarazel.de      13706                 :            346 :         newrel = table_open(RelationGetRelid(rel), NoLock);
 1921 andrew@dunslane.net     13707                 :            346 :         RelationClearMissing(newrel);
                              13708                 :            346 :         relation_close(newrel, NoLock);
                              13709                 :                :         /* make sure we don't conflict with later attribute modifications */
                              13710                 :            346 :         CommandCounterIncrement();
                              13711                 :                :     }
                              13712                 :                : 
 1910 andres@anarazel.de      13713                 :            472 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
                              13714                 :                : 
                              13715                 :                :     /* Look up the target column */
 7284 tgl@sss.pgh.pa.us       13716                 :            472 :     heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
 2489                         13717         [ -  + ]:            472 :     if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
 7284 tgl@sss.pgh.pa.us       13718         [ #  # ]:UBC           0 :         ereport(ERROR,
                              13719                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                              13720                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                              13721                 :                :                         colName, RelationGetRelationName(rel))));
 7284 tgl@sss.pgh.pa.us       13722                 :CBC         472 :     attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
                              13723                 :            472 :     attnum = attTup->attnum;
 2429 andres@anarazel.de      13724                 :            472 :     attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
                              13725                 :                : 
                              13726                 :                :     /* Check for multiple ALTER TYPE on same column --- can't cope */
                              13727         [ +  - ]:            472 :     if (attTup->atttypid != attOldTup->atttypid ||
                              13728         [ -  + ]:            472 :         attTup->atttypmod != attOldTup->atttypmod)
 7284 tgl@sss.pgh.pa.us       13729         [ #  # ]:UBC           0 :         ereport(ERROR,
                              13730                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              13731                 :                :                  errmsg("cannot alter type of column \"%s\" twice",
                              13732                 :                :                         colName)));
                              13733                 :                : 
                              13734                 :                :     /* Look up the target type (should not fail, since prep found it) */
 4785 tgl@sss.pgh.pa.us       13735                 :CBC         472 :     typeTuple = typenameType(NULL, typeName, &targettypmod);
 7284                         13736                 :            472 :     tform = (Form_pg_type) GETSTRUCT(typeTuple);
 1972 andres@anarazel.de      13737                 :            472 :     targettype = tform->oid;
                              13738                 :                :     /* And the collation */
 4785 tgl@sss.pgh.pa.us       13739                 :            472 :     targetcollid = GetColumnDefCollation(NULL, def, targettype);
                              13740                 :                : 
                              13741                 :                :     /*
                              13742                 :                :      * If there is a default expression for the column, get it and ensure we
                              13743                 :                :      * can coerce it to the new datatype.  (We must do this before changing
                              13744                 :                :      * the column type, because build_column_default itself will try to
                              13745                 :                :      * coerce, and will not issue the error message we want if it fails.)
                              13746                 :                :      *
                              13747                 :                :      * We remove any implicit coercion steps at the top level of the old
                              13748                 :                :      * default expression; this has been agreed to satisfy the principle of
                              13749                 :                :      * least surprise.  (The conversion to the new column type should act like
                              13750                 :                :      * it started from what the user sees as the stored expression, and the
                              13751                 :                :      * implicit coercions aren't going to be shown.)
                              13752                 :                :      */
 7284                         13753         [ +  + ]:            472 :     if (attTup->atthasdef)
                              13754                 :                :     {
                              13755                 :             31 :         defaultexpr = build_column_default(rel, attnum);
                              13756         [ -  + ]:             31 :         Assert(defaultexpr);
 7114                         13757                 :             31 :         defaultexpr = strip_implicit_coercions(defaultexpr);
 2489                         13758                 :             31 :         defaultexpr = coerce_to_target_type(NULL,   /* no UNKNOWN params */
                              13759                 :                :                                             defaultexpr, exprType(defaultexpr),
                              13760                 :                :                                             targettype, targettypmod,
                              13761                 :                :                                             COERCION_ASSIGNMENT,
                              13762                 :                :                                             COERCE_IMPLICIT_CAST,
                              13763                 :                :                                             -1);
 7284                         13764         [ +  + ]:             31 :         if (defaultexpr == NULL)
                              13765                 :                :         {
 1842 peter@eisentraut.org    13766         [ +  + ]:              6 :             if (attTup->attgenerated)
                              13767         [ +  - ]:              3 :                 ereport(ERROR,
                              13768                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              13769                 :                :                          errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
                              13770                 :                :                                 colName, format_type_be(targettype))));
                              13771                 :                :             else
                              13772         [ +  - ]:              3 :                 ereport(ERROR,
                              13773                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              13774                 :                :                          errmsg("default for column \"%s\" cannot be cast automatically to type %s",
                              13775                 :                :                                 colName, format_type_be(targettype))));
                              13776                 :                :         }
                              13777                 :                :     }
                              13778                 :                :     else
 7284 tgl@sss.pgh.pa.us       13779                 :            441 :         defaultexpr = NULL;
                              13780                 :                : 
                              13781                 :                :     /*
                              13782                 :                :      * Find everything that depends on the column (constraints, indexes, etc),
                              13783                 :                :      * and record enough information to let us recreate the objects.
                              13784                 :                :      *
                              13785                 :                :      * The actual recreation does not happen here, but only after we have
                              13786                 :                :      * performed all the individual ALTER TYPE operations.  We have to save
                              13787                 :                :      * the info before executing ALTER TYPE, though, else the deparser will
                              13788                 :                :      * get confused.
                              13789                 :                :      */
  101 peter@eisentraut.org    13790                 :GNC         466 :     RememberAllDependentForRebuilding(tab, AT_AlterColumnType, rel, attnum, colName);
                              13791                 :                : 
                              13792                 :                :     /*
                              13793                 :                :      * Now scan for dependencies of this column on other things.  The only
                              13794                 :                :      * things we should find are the dependency on the column datatype and
                              13795                 :                :      * possibly a collation dependency.  Those can be removed.
                              13796                 :                :      */
  102                         13797                 :            454 :     depRel = table_open(DependRelationId, RowExclusiveLock);
                              13798                 :                : 
  102 peter@eisentraut.org    13799                 :CBC         454 :     ScanKeyInit(&key[0],
                              13800                 :                :                 Anum_pg_depend_classid,
                              13801                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              13802                 :                :                 ObjectIdGetDatum(RelationRelationId));
                              13803                 :            454 :     ScanKeyInit(&key[1],
                              13804                 :                :                 Anum_pg_depend_objid,
                              13805                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              13806                 :                :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                              13807                 :            454 :     ScanKeyInit(&key[2],
                              13808                 :                :                 Anum_pg_depend_objsubid,
                              13809                 :                :                 BTEqualStrategyNumber, F_INT4EQ,
                              13810                 :                :                 Int32GetDatum((int32) attnum));
                              13811                 :                : 
                              13812                 :            454 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
                              13813                 :                :                               NULL, 3, key);
                              13814                 :                : 
                              13815         [ +  + ]:            456 :     while (HeapTupleIsValid(depTup = systable_getnext(scan)))
                              13816                 :                :     {
                              13817                 :              2 :         Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
                              13818                 :                :         ObjectAddress foundObject;
                              13819                 :                : 
                              13820                 :              2 :         foundObject.classId = foundDep->refclassid;
                              13821                 :              2 :         foundObject.objectId = foundDep->refobjid;
                              13822                 :              2 :         foundObject.objectSubId = foundDep->refobjsubid;
                              13823                 :                : 
                              13824         [ -  + ]:              2 :         if (foundDep->deptype != DEPENDENCY_NORMAL)
  102 peter@eisentraut.org    13825         [ #  # ]:UBC           0 :             elog(ERROR, "found unexpected dependency type '%c'",
                              13826                 :                :                  foundDep->deptype);
  102 peter@eisentraut.org    13827         [ +  - ]:CBC           2 :         if (!(foundDep->refclassid == TypeRelationId &&
                              13828         [ -  + ]:              2 :               foundDep->refobjid == attTup->atttypid) &&
  102 peter@eisentraut.org    13829         [ #  # ]:UBC           0 :             !(foundDep->refclassid == CollationRelationId &&
                              13830         [ #  # ]:              0 :               foundDep->refobjid == attTup->attcollation))
                              13831         [ #  # ]:              0 :             elog(ERROR, "found unexpected dependency for column: %s",
                              13832                 :                :                  getObjectDescription(&foundObject, false));
                              13833                 :                : 
  102 peter@eisentraut.org    13834                 :CBC           2 :         CatalogTupleDelete(depRel, &depTup->t_self);
                              13835                 :                :     }
                              13836                 :                : 
                              13837                 :            454 :     systable_endscan(scan);
                              13838                 :                : 
                              13839                 :            454 :     table_close(depRel, RowExclusiveLock);
                              13840                 :                : 
                              13841                 :                :     /*
                              13842                 :                :      * Here we go --- change the recorded column type and collation.  (Note
                              13843                 :                :      * heapTup is a copy of the syscache entry, so okay to scribble on.) First
                              13844                 :                :      * fix up the missing value if any.
                              13845                 :                :      */
                              13846         [ +  + ]:            454 :     if (attTup->atthasmissing)
                              13847                 :                :     {
                              13848                 :                :         Datum       missingval;
                              13849                 :                :         bool        missingNull;
                              13850                 :                : 
                              13851                 :                :         /* if rewrite is true the missing value should already be cleared */
                              13852         [ -  + ]:              3 :         Assert(tab->rewrite == 0);
                              13853                 :                : 
                              13854                 :                :         /* Get the missing value datum */
                              13855                 :              3 :         missingval = heap_getattr(heapTup,
                              13856                 :                :                                   Anum_pg_attribute_attmissingval,
                              13857                 :                :                                   attrelation->rd_att,
                              13858                 :                :                                   &missingNull);
                              13859                 :                : 
                              13860                 :                :         /* if it's a null array there is nothing to do */
                              13861                 :                : 
                              13862         [ +  - ]:              3 :         if (!missingNull)
                              13863                 :                :         {
                              13864                 :                :             /*
                              13865                 :                :              * Get the datum out of the array and repack it in a new array
                              13866                 :                :              * built with the new type data. We assume that since the table
                              13867                 :                :              * doesn't need rewriting, the actual Datum doesn't need to be
                              13868                 :                :              * changed, only the array metadata.
                              13869                 :                :              */
                              13870                 :                : 
                              13871                 :              3 :             int         one = 1;
                              13872                 :                :             bool        isNull;
                              13873                 :              3 :             Datum       valuesAtt[Natts_pg_attribute] = {0};
                              13874                 :              3 :             bool        nullsAtt[Natts_pg_attribute] = {0};
                              13875                 :              3 :             bool        replacesAtt[Natts_pg_attribute] = {0};
                              13876                 :                :             HeapTuple   newTup;
                              13877                 :                : 
                              13878                 :              6 :             missingval = array_get_element(missingval,
                              13879                 :                :                                            1,
                              13880                 :                :                                            &one,
                              13881                 :                :                                            0,
                              13882                 :              3 :                                            attTup->attlen,
                              13883                 :              3 :                                            attTup->attbyval,
                              13884                 :              3 :                                            attTup->attalign,
                              13885                 :                :                                            &isNull);
                              13886                 :              3 :             missingval = PointerGetDatum(construct_array(&missingval,
                              13887                 :                :                                                          1,
                              13888                 :                :                                                          targettype,
                              13889                 :              3 :                                                          tform->typlen,
                              13890                 :              3 :                                                          tform->typbyval,
                              13891                 :              3 :                                                          tform->typalign));
                              13892                 :                : 
                              13893                 :              3 :             valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
                              13894                 :              3 :             replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
                              13895                 :              3 :             nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
                              13896                 :                : 
                              13897                 :              3 :             newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
                              13898                 :                :                                        valuesAtt, nullsAtt, replacesAtt);
                              13899                 :              3 :             heap_freetuple(heapTup);
                              13900                 :              3 :             heapTup = newTup;
                              13901                 :              3 :             attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
                              13902                 :                :         }
                              13903                 :                :     }
                              13904                 :                : 
                              13905                 :            454 :     attTup->atttypid = targettype;
                              13906                 :            454 :     attTup->atttypmod = targettypmod;
                              13907                 :            454 :     attTup->attcollation = targetcollid;
                              13908         [ -  + ]:            454 :     if (list_length(typeName->arrayBounds) > PG_INT16_MAX)
  102 peter@eisentraut.org    13909         [ #  # ]:UBC           0 :         ereport(ERROR,
                              13910                 :                :                 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                              13911                 :                :                 errmsg("too many array dimensions"));
  102 peter@eisentraut.org    13912                 :CBC         454 :     attTup->attndims = list_length(typeName->arrayBounds);
                              13913                 :            454 :     attTup->attlen = tform->typlen;
                              13914                 :            454 :     attTup->attbyval = tform->typbyval;
                              13915                 :            454 :     attTup->attalign = tform->typalign;
                              13916                 :            454 :     attTup->attstorage = tform->typstorage;
                              13917                 :            454 :     attTup->attcompression = InvalidCompressionMethod;
                              13918                 :                : 
                              13919                 :            454 :     ReleaseSysCache(typeTuple);
                              13920                 :                : 
                              13921                 :            454 :     CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
                              13922                 :                : 
                              13923                 :            454 :     table_close(attrelation, RowExclusiveLock);
                              13924                 :                : 
                              13925                 :                :     /* Install dependencies on new datatype and collation */
                              13926                 :            454 :     add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
                              13927                 :            454 :     add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
                              13928                 :                : 
                              13929                 :                :     /*
                              13930                 :                :      * Drop any pg_statistic entry for the column, since it's now wrong type
                              13931                 :                :      */
                              13932                 :            454 :     RemoveStatistics(RelationGetRelid(rel), attnum);
                              13933                 :                : 
                              13934         [ -  + ]:            454 :     InvokeObjectPostAlterHook(RelationRelationId,
                              13935                 :                :                               RelationGetRelid(rel), attnum);
                              13936                 :                : 
                              13937                 :                :     /*
                              13938                 :                :      * Update the default, if present, by brute force --- remove and re-add
                              13939                 :                :      * the default.  Probably unsafe to take shortcuts, since the new version
                              13940                 :                :      * may well have additional dependencies.  (It's okay to do this now,
                              13941                 :                :      * rather than after other ALTER TYPE commands, since the default won't
                              13942                 :                :      * depend on other column types.)
                              13943                 :                :      */
                              13944         [ +  + ]:            454 :     if (defaultexpr)
                              13945                 :                :     {
                              13946                 :                :         /*
                              13947                 :                :          * If it's a GENERATED default, drop its dependency records, in
                              13948                 :                :          * particular its INTERNAL dependency on the column, which would
                              13949                 :                :          * otherwise cause dependency.c to refuse to perform the deletion.
                              13950                 :                :          */
                              13951         [ +  + ]:             25 :         if (attTup->attgenerated)
                              13952                 :                :         {
                              13953                 :              3 :             Oid         attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
                              13954                 :                : 
                              13955         [ -  + ]:              3 :             if (!OidIsValid(attrdefoid))
  102 peter@eisentraut.org    13956         [ #  # ]:UBC           0 :                 elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
                              13957                 :                :                      RelationGetRelid(rel), attnum);
  102 peter@eisentraut.org    13958                 :CBC           3 :             (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
                              13959                 :                :         }
                              13960                 :                : 
                              13961                 :                :         /*
                              13962                 :                :          * Make updates-so-far visible, particularly the new pg_attribute row
                              13963                 :                :          * which will be updated again.
                              13964                 :                :          */
                              13965                 :             25 :         CommandCounterIncrement();
                              13966                 :                : 
                              13967                 :                :         /*
                              13968                 :                :          * We use RESTRICT here for safety, but at present we do not expect
                              13969                 :                :          * anything to depend on the default.
                              13970                 :                :          */
                              13971                 :             25 :         RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
                              13972                 :                :                           true);
                              13973                 :                : 
                              13974                 :             25 :         StoreAttrDefault(rel, attnum, defaultexpr, true, false);
                              13975                 :                :     }
                              13976                 :                : 
                              13977                 :            454 :     ObjectAddressSubSet(address, RelationRelationId,
                              13978                 :                :                         RelationGetRelid(rel), attnum);
                              13979                 :                : 
                              13980                 :                :     /* Cleanup */
                              13981                 :            454 :     heap_freetuple(heapTup);
                              13982                 :                : 
                              13983                 :            454 :     return address;
                              13984                 :                : }
                              13985                 :                : 
                              13986                 :                : /*
                              13987                 :                :  * Subroutine for ATExecAlterColumnType and ATExecSetExpression: Find everything
                              13988                 :                :  * that depends on the column (constraints, indexes, etc), and record enough
                              13989                 :                :  * information to let us recreate the objects.
                              13990                 :                :  */
                              13991                 :                : static void
  101 peter@eisentraut.org    13992                 :GNC         505 : RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype,
                              13993                 :                :                                   Relation rel, AttrNumber attnum, const char *colName)
                              13994                 :                : {
                              13995                 :                :     Relation    depRel;
                              13996                 :                :     ScanKeyData key[3];
                              13997                 :                :     SysScanDesc scan;
                              13998                 :                :     HeapTuple   depTup;
                              13999                 :                : 
                              14000   [ +  +  -  + ]:            505 :     Assert(subtype == AT_AlterColumnType || subtype == AT_SetExpression);
                              14001                 :                : 
 1910 andres@anarazel.de      14002                 :            505 :     depRel = table_open(DependRelationId, RowExclusiveLock);
                              14003                 :                : 
 7284 tgl@sss.pgh.pa.us       14004                 :            505 :     ScanKeyInit(&key[0],
                              14005                 :                :                 Anum_pg_depend_refclassid,
                              14006                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              14007                 :                :                 ObjectIdGetDatum(RelationRelationId));
                              14008                 :            505 :     ScanKeyInit(&key[1],
                              14009                 :                :                 Anum_pg_depend_refobjid,
                              14010                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              14011                 :                :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                              14012                 :            505 :     ScanKeyInit(&key[2],
                              14013                 :                :                 Anum_pg_depend_refobjsubid,
                              14014                 :                :                 BTEqualStrategyNumber, F_INT4EQ,
                              14015                 :                :                 Int32GetDatum((int32) attnum));
                              14016                 :                : 
 6940                         14017                 :            505 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
                              14018                 :                :                               NULL, 3, key);
                              14019                 :                : 
 7284                         14020         [ +  + ]:            970 :     while (HeapTupleIsValid(depTup = systable_getnext(scan)))
                              14021                 :                :     {
 7168 bruce@momjian.us        14022                 :            477 :         Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
                              14023                 :                :         ObjectAddress foundObject;
                              14024                 :                : 
 7284 tgl@sss.pgh.pa.us       14025                 :            477 :         foundObject.classId = foundDep->classid;
                              14026                 :            477 :         foundObject.objectId = foundDep->objid;
                              14027                 :            477 :         foundObject.objectSubId = foundDep->objsubid;
                              14028                 :                : 
   19 peter@eisentraut.org    14029   [ +  +  +  -  :            477 :         switch (foundObject.classId)
                                        -  +  +  - ]
                              14030                 :                :         {
                              14031                 :            132 :             case RelationRelationId:
                              14032                 :                :                 {
 7168 bruce@momjian.us        14033                 :            132 :                     char        relKind = get_rel_relkind(foundObject.objectId);
                              14034                 :                : 
 2277 alvherre@alvh.no-ip.    14035   [ +  +  +  + ]:            132 :                     if (relKind == RELKIND_INDEX ||
                              14036                 :                :                         relKind == RELKIND_PARTITIONED_INDEX)
                              14037                 :                :                     {
 7168 bruce@momjian.us        14038         [ -  + ]:            116 :                         Assert(foundObject.objectSubId == 0);
 1756 tgl@sss.pgh.pa.us       14039                 :            116 :                         RememberIndexForRebuilding(foundObject.objectId, tab);
                              14040                 :                :                     }
 7168 bruce@momjian.us        14041         [ +  - ]:             16 :                     else if (relKind == RELKIND_SEQUENCE)
                              14042                 :                :                     {
                              14043                 :                :                         /*
                              14044                 :                :                          * This must be a SERIAL column's sequence.  We need
                              14045                 :                :                          * not do anything to it.
                              14046                 :                :                          */
                              14047         [ -  + ]:             16 :                         Assert(foundObject.objectSubId == 0);
                              14048                 :                :                     }
                              14049                 :                :                     else
                              14050                 :                :                     {
                              14051                 :                :                         /* Not expecting any other direct dependencies... */
 7168 bruce@momjian.us        14052         [ #  # ]:UNC           0 :                         elog(ERROR, "unexpected object depending on column: %s",
                              14053                 :                :                              getObjectDescription(&foundObject, false));
                              14054                 :                :                     }
 7168 bruce@momjian.us        14055                 :GNC         132 :                     break;
                              14056                 :                :                 }
                              14057                 :                : 
   19 peter@eisentraut.org    14058                 :            262 :             case ConstraintRelationId:
 7284 tgl@sss.pgh.pa.us       14059         [ -  + ]:            262 :                 Assert(foundObject.objectSubId == 0);
 1756                         14060                 :            262 :                 RememberConstraintForRebuilding(foundObject.objectId, tab);
 7284                         14061                 :            262 :                 break;
                              14062                 :                : 
   19 peter@eisentraut.org    14063                 :              6 :             case RewriteRelationId:
                              14064                 :                :                 /* XXX someday see if we can cope with revising views */
  101                         14065         [ +  - ]:              6 :                 if (subtype == AT_AlterColumnType)
                              14066         [ +  - ]:              6 :                     ereport(ERROR,
                              14067                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              14068                 :                :                              errmsg("cannot alter type of a column used by a view or rule"),
                              14069                 :                :                              errdetail("%s depends on column \"%s\"",
                              14070                 :                :                                        getObjectDescription(&foundObject, false),
                              14071                 :                :                                        colName)));
 7284 tgl@sss.pgh.pa.us       14072                 :UNC           0 :                 break;
                              14073                 :                : 
   19 peter@eisentraut.org    14074                 :              0 :             case TriggerRelationId:
                              14075                 :                : 
                              14076                 :                :                 /*
                              14077                 :                :                  * A trigger can depend on a column because the column is
                              14078                 :                :                  * specified as an update target, or because the column is
                              14079                 :                :                  * used in the trigger's WHEN condition.  The first case would
                              14080                 :                :                  * not require any extra work, but the second case would
                              14081                 :                :                  * require updating the WHEN expression, which will take a
                              14082                 :                :                  * significant amount of new code.  Since we can't easily tell
                              14083                 :                :                  * which case applies, we punt for both.  FIXME someday.
                              14084                 :                :                  */
  101                         14085         [ #  # ]:              0 :                 if (subtype == AT_AlterColumnType)
                              14086         [ #  # ]:              0 :                     ereport(ERROR,
                              14087                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              14088                 :                :                              errmsg("cannot alter type of a column used in a trigger definition"),
                              14089                 :                :                              errdetail("%s depends on column \"%s\"",
                              14090                 :                :                                        getObjectDescription(&foundObject, false),
                              14091                 :                :                                        colName)));
 4943 tgl@sss.pgh.pa.us       14092                 :              0 :                 break;
                              14093                 :                : 
   19 peter@eisentraut.org    14094                 :              0 :             case PolicyRelationId:
                              14095                 :                : 
                              14096                 :                :                 /*
                              14097                 :                :                  * A policy can depend on a column because the column is
                              14098                 :                :                  * specified in the policy's USING or WITH CHECK qual
                              14099                 :                :                  * expressions.  It might be possible to rewrite and recheck
                              14100                 :                :                  * the policy expression, but punt for now.  It's certainly
                              14101                 :                :                  * easy enough to remove and recreate the policy; still, FIXME
                              14102                 :                :                  * someday.
                              14103                 :                :                  */
  101                         14104         [ #  # ]:              0 :                 if (subtype == AT_AlterColumnType)
                              14105         [ #  # ]:              0 :                     ereport(ERROR,
                              14106                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              14107                 :                :                              errmsg("cannot alter type of a column used in a policy definition"),
                              14108                 :                :                              errdetail("%s depends on column \"%s\"",
                              14109                 :                :                                        getObjectDescription(&foundObject, false),
                              14110                 :                :                                        colName)));
 3426 sfrost@snowman.net      14111                 :              0 :                 break;
                              14112                 :                : 
   19 peter@eisentraut.org    14113                 :GNC          70 :             case AttrDefaultRelationId:
                              14114                 :                :                 {
  755 tgl@sss.pgh.pa.us       14115                 :             70 :                     ObjectAddress col = GetAttrDefaultColumnAddress(foundObject.objectId);
                              14116                 :                : 
                              14117         [ +  - ]:            134 :                     if (col.objectId == RelationGetRelid(rel) &&
                              14118         [ +  + ]:             70 :                         col.objectSubId == attnum)
                              14119                 :                :                     {
                              14120                 :                :                         /*
                              14121                 :                :                          * Ignore the column's own default expression.  The
                              14122                 :                :                          * caller deals with it.
                              14123                 :                :                          */
                              14124                 :                :                     }
                              14125                 :                :                     else
                              14126                 :                :                     {
                              14127                 :                :                         /*
                              14128                 :                :                          * This must be a reference from the expression of a
                              14129                 :                :                          * generated column elsewhere in the same table.
                              14130                 :                :                          * Changing the type/generated expression of a column
                              14131                 :                :                          * that is used by a generated column is not allowed
                              14132                 :                :                          * by SQL standard, so just punt for now.  It might be
                              14133                 :                :                          * doable with some thinking and effort.
                              14134                 :                :                          */
  101 peter@eisentraut.org    14135         [ +  - ]:              6 :                         if (subtype == AT_AlterColumnType)
                              14136         [ +  - ]:              6 :                             ereport(ERROR,
                              14137                 :                :                                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              14138                 :                :                                      errmsg("cannot alter type of a column used by a generated column"),
                              14139                 :                :                                      errdetail("Column \"%s\" is used by generated column \"%s\".",
                              14140                 :                :                                                colName,
                              14141                 :                :                                                get_attname(col.objectId,
                              14142                 :                :                                                            col.objectSubId,
                              14143                 :                :                                                            false))));
                              14144                 :                :                     }
  755 tgl@sss.pgh.pa.us       14145                 :             64 :                     break;
                              14146                 :                :                 }
                              14147                 :                : 
   19 peter@eisentraut.org    14148                 :              7 :             case StatisticExtRelationId:
                              14149                 :                : 
                              14150                 :                :                 /*
                              14151                 :                :                  * Give the extended-stats machinery a chance to fix anything
                              14152                 :                :                  * that this column type change would break.
                              14153                 :                :                  */
 1115 tomas.vondra@postgre    14154                 :              7 :                 RememberStatisticsForRebuilding(foundObject.objectId, tab);
 2527 tgl@sss.pgh.pa.us       14155                 :              7 :                 break;
                              14156                 :                : 
   19 peter@eisentraut.org    14157                 :UNC           0 :             default:
                              14158                 :                : 
                              14159                 :                :                 /*
                              14160                 :                :                  * We don't expect any other sorts of objects to depend on a
                              14161                 :                :                  * column.
                              14162                 :                :                  */
 7284 tgl@sss.pgh.pa.us       14163         [ #  # ]:              0 :                 elog(ERROR, "unexpected object depending on column: %s",
                              14164                 :                :                      getObjectDescription(&foundObject, false));
                              14165                 :                :                 break;
                              14166                 :                :         }
                              14167                 :                :     }
                              14168                 :                : 
 7284 tgl@sss.pgh.pa.us       14169                 :GNC         493 :     systable_endscan(scan);
  102 peter@eisentraut.org    14170                 :            493 :     table_close(depRel, NoLock);
 7947 tgl@sss.pgh.pa.us       14171                 :            493 : }
                              14172                 :                : 
                              14173                 :                : /*
                              14174                 :                :  * Subroutine for ATExecAlterColumnType: remember that a replica identity
                              14175                 :                :  * needs to be reset.
                              14176                 :                :  */
                              14177                 :                : static void
 1493 peter@eisentraut.org    14178                 :CBC         217 : RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
                              14179                 :                : {
                              14180         [ +  + ]:            217 :     if (!get_index_isreplident(indoid))
                              14181                 :            208 :         return;
                              14182                 :                : 
                              14183         [ -  + ]:              9 :     if (tab->replicaIdentityIndex)
 1493 peter@eisentraut.org    14184         [ #  # ]:UBC           0 :         elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
                              14185                 :                : 
 1493 peter@eisentraut.org    14186                 :CBC           9 :     tab->replicaIdentityIndex = get_rel_name(indoid);
                              14187                 :                : }
                              14188                 :                : 
                              14189                 :                : /*
                              14190                 :                :  * Subroutine for ATExecAlterColumnType: remember any clustered index.
                              14191                 :                :  */
                              14192                 :                : static void
 1469 michael@paquier.xyz     14193                 :            217 : RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
                              14194                 :                : {
                              14195         [ +  + ]:            217 :     if (!get_index_isclustered(indoid))
                              14196                 :            208 :         return;
                              14197                 :                : 
                              14198         [ -  + ]:              9 :     if (tab->clusterOnIndex)
 1469 michael@paquier.xyz     14199         [ #  # ]:UBC           0 :         elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
                              14200                 :                : 
 1469 michael@paquier.xyz     14201                 :CBC           9 :     tab->clusterOnIndex = get_rel_name(indoid);
                              14202                 :                : }
                              14203                 :                : 
                              14204                 :                : /*
                              14205                 :                :  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
                              14206                 :                :  * to be rebuilt (which we might already know).
                              14207                 :                :  */
                              14208                 :                : static void
 1756 tgl@sss.pgh.pa.us       14209                 :            268 : RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
                              14210                 :                : {
                              14211                 :                :     /*
                              14212                 :                :      * This de-duplication check is critical for two independent reasons: we
                              14213                 :                :      * mustn't try to recreate the same constraint twice, and if a constraint
                              14214                 :                :      * depends on more than one column whose type is to be altered, we must
                              14215                 :                :      * capture its definition string before applying any of the column type
                              14216                 :                :      * changes.  ruleutils.c will get confused if we ask again later.
                              14217                 :                :      */
                              14218         [ +  + ]:            268 :     if (!list_member_oid(tab->changedConstraintOids, conoid))
                              14219                 :                :     {
                              14220                 :                :         /* OK, capture the constraint's existing definition string */
                              14221                 :            223 :         char       *defstring = pg_get_constraintdef_command(conoid);
                              14222                 :                :         Oid         indoid;
                              14223                 :                : 
                              14224                 :            223 :         tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
                              14225                 :                :                                                  conoid);
                              14226                 :            223 :         tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
                              14227                 :                :                                              defstring);
                              14228                 :                : 
                              14229                 :                :         /*
                              14230                 :                :          * For the index of a constraint, if any, remember if it is used for
                              14231                 :                :          * the table's replica identity or if it is a clustered index, so that
                              14232                 :                :          * ATPostAlterTypeCleanup() can queue up commands necessary to restore
                              14233                 :                :          * those properties.
                              14234                 :                :          */
 1493 peter@eisentraut.org    14235                 :            223 :         indoid = get_constraint_index(conoid);
                              14236         [ +  + ]:            223 :         if (OidIsValid(indoid))
                              14237                 :                :         {
                              14238                 :            111 :             RememberReplicaIdentityForRebuilding(indoid, tab);
 1469 michael@paquier.xyz     14239                 :            111 :             RememberClusterOnForRebuilding(indoid, tab);
                              14240                 :                :         }
                              14241                 :                :     }
 1756 tgl@sss.pgh.pa.us       14242                 :            268 : }
                              14243                 :                : 
                              14244                 :                : /*
                              14245                 :                :  * Subroutine for ATExecAlterColumnType: remember that an index needs
                              14246                 :                :  * to be rebuilt (which we might already know).
                              14247                 :                :  */
                              14248                 :                : static void
                              14249                 :            116 : RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
                              14250                 :                : {
                              14251                 :                :     /*
                              14252                 :                :      * This de-duplication check is critical for two independent reasons: we
                              14253                 :                :      * mustn't try to recreate the same index twice, and if an index depends
                              14254                 :                :      * on more than one column whose type is to be altered, we must capture
                              14255                 :                :      * its definition string before applying any of the column type changes.
                              14256                 :                :      * ruleutils.c will get confused if we ask again later.
                              14257                 :                :      */
                              14258         [ +  + ]:            116 :     if (!list_member_oid(tab->changedIndexOids, indoid))
                              14259                 :                :     {
                              14260                 :                :         /*
                              14261                 :                :          * Before adding it as an index-to-rebuild, we'd better see if it
                              14262                 :                :          * belongs to a constraint, and if so rebuild the constraint instead.
                              14263                 :                :          * Typically this check fails, because constraint indexes normally
                              14264                 :                :          * have only dependencies on their constraint.  But it's possible for
                              14265                 :                :          * such an index to also have direct dependencies on table columns,
                              14266                 :                :          * for example with a partial exclusion constraint.
                              14267                 :                :          */
                              14268                 :            112 :         Oid         conoid = get_index_constraint(indoid);
                              14269                 :                : 
                              14270         [ +  + ]:            112 :         if (OidIsValid(conoid))
                              14271                 :                :         {
                              14272                 :              6 :             RememberConstraintForRebuilding(conoid, tab);
                              14273                 :                :         }
                              14274                 :                :         else
                              14275                 :                :         {
                              14276                 :                :             /* OK, capture the index's existing definition string */
                              14277                 :            106 :             char       *defstring = pg_get_indexdef_string(indoid);
                              14278                 :                : 
                              14279                 :            106 :             tab->changedIndexOids = lappend_oid(tab->changedIndexOids,
                              14280                 :                :                                                 indoid);
                              14281                 :            106 :             tab->changedIndexDefs = lappend(tab->changedIndexDefs,
                              14282                 :                :                                             defstring);
                              14283                 :                : 
                              14284                 :                :             /*
                              14285                 :                :              * Remember if this index is used for the table's replica identity
                              14286                 :                :              * or if it is a clustered index, so that ATPostAlterTypeCleanup()
                              14287                 :                :              * can queue up commands necessary to restore those properties.
                              14288                 :                :              */
 1493 peter@eisentraut.org    14289                 :            106 :             RememberReplicaIdentityForRebuilding(indoid, tab);
 1469 michael@paquier.xyz     14290                 :            106 :             RememberClusterOnForRebuilding(indoid, tab);
                              14291                 :                :         }
                              14292                 :                :     }
 1756 tgl@sss.pgh.pa.us       14293                 :            116 : }
                              14294                 :                : 
                              14295                 :                : /*
                              14296                 :                :  * Subroutine for ATExecAlterColumnType: remember that a statistics object
                              14297                 :                :  * needs to be rebuilt (which we might already know).
                              14298                 :                :  */
                              14299                 :                : static void
 1115 tomas.vondra@postgre    14300                 :              7 : RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab)
                              14301                 :                : {
                              14302                 :                :     /*
                              14303                 :                :      * This de-duplication check is critical for two independent reasons: we
                              14304                 :                :      * mustn't try to recreate the same statistics object twice, and if the
                              14305                 :                :      * statistics object depends on more than one column whose type is to be
                              14306                 :                :      * altered, we must capture its definition string before applying any of
                              14307                 :                :      * the type changes. ruleutils.c will get confused if we ask again later.
                              14308                 :                :      */
                              14309         [ +  - ]:              7 :     if (!list_member_oid(tab->changedStatisticsOids, stxoid))
                              14310                 :                :     {
                              14311                 :                :         /* OK, capture the statistics object's existing definition string */
                              14312                 :              7 :         char       *defstring = pg_get_statisticsobjdef_string(stxoid);
                              14313                 :                : 
                              14314                 :              7 :         tab->changedStatisticsOids = lappend_oid(tab->changedStatisticsOids,
                              14315                 :                :                                                  stxoid);
                              14316                 :              7 :         tab->changedStatisticsDefs = lappend(tab->changedStatisticsDefs,
                              14317                 :                :                                              defstring);
                              14318                 :                :     }
                              14319                 :              7 : }
                              14320                 :                : 
                              14321                 :                : /*
                              14322                 :                :  * Cleanup after we've finished all the ALTER TYPE or SET EXPRESSION
                              14323                 :                :  * operations for a particular relation.  We have to drop and recreate all the
                              14324                 :                :  * indexes and constraints that depend on the altered columns.  We do the
                              14325                 :                :  * actual dropping here, but re-creation is managed by adding work queue
                              14326                 :                :  * entries to do those steps later.
                              14327                 :                :  */
                              14328                 :                : static void
 5009 simon@2ndQuadrant.co    14329                 :            478 : ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
                              14330                 :                : {
                              14331                 :                :     ObjectAddress obj;
                              14332                 :                :     ObjectAddresses *objects;
                              14333                 :                :     ListCell   *def_item;
                              14334                 :                :     ListCell   *oid_item;
                              14335                 :                : 
                              14336                 :                :     /*
                              14337                 :                :      * Collect all the constraints and indexes to drop so we can process them
                              14338                 :                :      * in a single call.  That way we don't have to worry about dependencies
                              14339                 :                :      * among them.
                              14340                 :                :      */
 2039 alvherre@alvh.no-ip.    14341                 :            478 :     objects = new_object_addresses();
                              14342                 :                : 
                              14343                 :                :     /*
                              14344                 :                :      * Re-parse the index and constraint definitions, and attach them to the
                              14345                 :                :      * appropriate work queue entries.  We do this before dropping because in
                              14346                 :                :      * the case of a FOREIGN KEY constraint, we might not yet have exclusive
                              14347                 :                :      * lock on the table the constraint is attached to, and we need to get
                              14348                 :                :      * that before reparsing/dropping.
                              14349                 :                :      *
                              14350                 :                :      * We can't rely on the output of deparsing to tell us which relation to
                              14351                 :                :      * operate on, because concurrent activity might have made the name
                              14352                 :                :      * resolve differently.  Instead, we've got to use the OID of the
                              14353                 :                :      * constraint or index we're processing to figure out which relation to
                              14354                 :                :      * operate on.
                              14355                 :                :      */
 4654 rhaas@postgresql.org    14356   [ +  +  +  +  :            701 :     forboth(oid_item, tab->changedConstraintOids,
                                     +  +  +  +  +  
                                        +  +  -  +  
                                                 + ]
                              14357                 :                :             def_item, tab->changedConstraintDefs)
                              14358                 :                :     {
 3631 bruce@momjian.us        14359                 :            223 :         Oid         oldId = lfirst_oid(oid_item);
                              14360                 :                :         HeapTuple   tup;
                              14361                 :                :         Form_pg_constraint con;
                              14362                 :                :         Oid         relid;
                              14363                 :                :         Oid         confrelid;
                              14364                 :                :         char        contype;
                              14365                 :                :         bool        conislocal;
                              14366                 :                : 
 3068 tgl@sss.pgh.pa.us       14367                 :            223 :         tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
 2489                         14368         [ -  + ]:            223 :         if (!HeapTupleIsValid(tup)) /* should not happen */
 3068 tgl@sss.pgh.pa.us       14369         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for constraint %u", oldId);
 3068 tgl@sss.pgh.pa.us       14370                 :CBC         223 :         con = (Form_pg_constraint) GETSTRUCT(tup);
 2356                         14371         [ +  + ]:            223 :         if (OidIsValid(con->conrelid))
                              14372                 :            216 :             relid = con->conrelid;
                              14373                 :                :         else
                              14374                 :                :         {
                              14375                 :                :             /* must be a domain constraint */
                              14376                 :              7 :             relid = get_typ_typrelid(getBaseType(con->contypid));
                              14377         [ -  + ]:              7 :             if (!OidIsValid(relid))
 2356 tgl@sss.pgh.pa.us       14378         [ #  # ]:UBC           0 :                 elog(ERROR, "could not identify relation associated with constraint %u", oldId);
                              14379                 :                :         }
 3068 tgl@sss.pgh.pa.us       14380                 :CBC         223 :         confrelid = con->confrelid;
 2022                         14381                 :            223 :         contype = con->contype;
 3068                         14382                 :            223 :         conislocal = con->conislocal;
                              14383                 :            223 :         ReleaseSysCache(tup);
                              14384                 :                : 
 2022                         14385                 :            223 :         ObjectAddressSet(obj, ConstraintRelationId, oldId);
 2039 alvherre@alvh.no-ip.    14386                 :            223 :         add_exact_object_address(&obj, objects);
                              14387                 :                : 
                              14388                 :                :         /*
                              14389                 :                :          * If the constraint is inherited (only), we don't want to inject a
                              14390                 :                :          * new definition here; it'll get recreated when
                              14391                 :                :          * ATAddCheckNNConstraint recurses from adding the parent table's
                              14392                 :                :          * constraint.  But we had to carry the info this far so that we can
                              14393                 :                :          * drop the constraint below.
                              14394                 :                :          */
 3068 tgl@sss.pgh.pa.us       14395         [ +  + ]:            223 :         if (!conislocal)
                              14396                 :              8 :             continue;
                              14397                 :                : 
                              14398                 :                :         /*
                              14399                 :                :          * When rebuilding an FK constraint that references the table we're
                              14400                 :                :          * modifying, we might not yet have any lock on the FK's table, so get
                              14401                 :                :          * one now.  We'll need AccessExclusiveLock for the DROP CONSTRAINT
                              14402                 :                :          * step, so there's no value in asking for anything weaker.
                              14403                 :                :          */
 2022                         14404   [ +  +  +  - ]:            215 :         if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
                              14405                 :             18 :             LockRelationOid(relid, AccessExclusiveLock);
                              14406                 :                : 
 3709 rhaas@postgresql.org    14407                 :            215 :         ATPostAlterTypeParse(oldId, relid, confrelid,
                              14408                 :            215 :                              (char *) lfirst(def_item),
 4654                         14409                 :            215 :                              wqueue, lockmode, tab->rewrite);
                              14410                 :                :     }
                              14411   [ +  +  +  +  :            584 :     forboth(oid_item, tab->changedIndexOids,
                                     +  +  +  +  +  
                                        +  +  -  +  
                                                 + ]
                              14412                 :                :             def_item, tab->changedIndexDefs)
                              14413                 :                :     {
 3631 bruce@momjian.us        14414                 :            106 :         Oid         oldId = lfirst_oid(oid_item);
                              14415                 :                :         Oid         relid;
                              14416                 :                : 
 3709 rhaas@postgresql.org    14417                 :            106 :         relid = IndexGetRelation(oldId, false);
                              14418                 :            106 :         ATPostAlterTypeParse(oldId, relid, InvalidOid,
                              14419                 :            106 :                              (char *) lfirst(def_item),
 4654                         14420                 :            106 :                              wqueue, lockmode, tab->rewrite);
                              14421                 :                : 
 2022 tgl@sss.pgh.pa.us       14422                 :            106 :         ObjectAddressSet(obj, RelationRelationId, oldId);
 2039 alvherre@alvh.no-ip.    14423                 :            106 :         add_exact_object_address(&obj, objects);
                              14424                 :                :     }
                              14425                 :                : 
                              14426                 :                :     /* add dependencies for new statistics */
 1115 tomas.vondra@postgre    14427   [ +  +  +  +  :            485 :     forboth(oid_item, tab->changedStatisticsOids,
                                     +  +  +  +  +  
                                        +  +  -  +  
                                                 + ]
                              14428                 :                :             def_item, tab->changedStatisticsDefs)
                              14429                 :                :     {
                              14430                 :              7 :         Oid         oldId = lfirst_oid(oid_item);
                              14431                 :                :         Oid         relid;
                              14432                 :                : 
                              14433                 :              7 :         relid = StatisticsGetRelation(oldId, false);
                              14434                 :              7 :         ATPostAlterTypeParse(oldId, relid, InvalidOid,
                              14435                 :              7 :                              (char *) lfirst(def_item),
                              14436                 :              7 :                              wqueue, lockmode, tab->rewrite);
                              14437                 :                : 
                              14438                 :              7 :         ObjectAddressSet(obj, StatisticExtRelationId, oldId);
                              14439                 :              7 :         add_exact_object_address(&obj, objects);
                              14440                 :                :     }
                              14441                 :                : 
                              14442                 :                :     /*
                              14443                 :                :      * Queue up command to restore replica identity index marking
                              14444                 :                :      */
 1493 peter@eisentraut.org    14445         [ +  + ]:            478 :     if (tab->replicaIdentityIndex)
                              14446                 :                :     {
                              14447                 :              9 :         AlterTableCmd *cmd = makeNode(AlterTableCmd);
                              14448                 :              9 :         ReplicaIdentityStmt *subcmd = makeNode(ReplicaIdentityStmt);
                              14449                 :                : 
                              14450                 :              9 :         subcmd->identity_type = REPLICA_IDENTITY_INDEX;
                              14451                 :              9 :         subcmd->name = tab->replicaIdentityIndex;
                              14452                 :              9 :         cmd->subtype = AT_ReplicaIdentity;
                              14453                 :              9 :         cmd->def = (Node *) subcmd;
                              14454                 :                : 
                              14455                 :                :         /* do it after indexes and constraints */
                              14456                 :              9 :         tab->subcmds[AT_PASS_OLD_CONSTR] =
                              14457                 :              9 :             lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
                              14458                 :                :     }
                              14459                 :                : 
                              14460                 :                :     /*
                              14461                 :                :      * Queue up command to restore marking of index used for cluster.
                              14462                 :                :      */
 1469 michael@paquier.xyz     14463         [ +  + ]:            478 :     if (tab->clusterOnIndex)
                              14464                 :                :     {
                              14465                 :              9 :         AlterTableCmd *cmd = makeNode(AlterTableCmd);
                              14466                 :                : 
                              14467                 :              9 :         cmd->subtype = AT_ClusterOn;
                              14468                 :              9 :         cmd->name = tab->clusterOnIndex;
                              14469                 :                : 
                              14470                 :                :         /* do it after indexes and constraints */
                              14471                 :              9 :         tab->subcmds[AT_PASS_OLD_CONSTR] =
                              14472                 :              9 :             lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
                              14473                 :                :     }
                              14474                 :                : 
                              14475                 :                :     /*
                              14476                 :                :      * It should be okay to use DROP_RESTRICT here, since nothing else should
                              14477                 :                :      * be depending on these objects.
                              14478                 :                :      */
 2039 alvherre@alvh.no-ip.    14479                 :            478 :     performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
                              14480                 :                : 
                              14481                 :            478 :     free_object_addresses(objects);
                              14482                 :                : 
                              14483                 :                :     /*
                              14484                 :                :      * The objects will get recreated during subsequent passes over the work
                              14485                 :                :      * queue.
                              14486                 :                :      */
 7284 tgl@sss.pgh.pa.us       14487                 :            478 : }
                              14488                 :                : 
                              14489                 :                : /*
                              14490                 :                :  * Parse the previously-saved definition string for a constraint, index or
                              14491                 :                :  * statistics object against the newly-established column data type(s), and
                              14492                 :                :  * queue up the resulting command parsetrees for execution.
                              14493                 :                :  *
                              14494                 :                :  * This might fail if, for example, you have a WHERE clause that uses an
                              14495                 :                :  * operator that's not available for the new column type.
                              14496                 :                :  */
                              14497                 :                : static void
 3709 rhaas@postgresql.org    14498                 :            328 : ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
                              14499                 :                :                      List **wqueue, LOCKMODE lockmode, bool rewrite)
                              14500                 :                : {
                              14501                 :                :     List       *raw_parsetree_list;
                              14502                 :                :     List       *querytree_list;
                              14503                 :                :     ListCell   *list_item;
                              14504                 :                :     Relation    rel;
                              14505                 :                : 
                              14506                 :                :     /*
                              14507                 :                :      * We expect that we will get only ALTER TABLE and CREATE INDEX
                              14508                 :                :      * statements. Hence, there is no need to pass them through
                              14509                 :                :      * parse_analyze_*() or the rewriter, but instead we need to pass them
                              14510                 :                :      * through parse_utilcmd.c to make them ready for execution.
                              14511                 :                :      */
 1196 tgl@sss.pgh.pa.us       14512                 :            328 :     raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT);
 7284                         14513                 :            328 :     querytree_list = NIL;
                              14514   [ +  -  +  +  :            656 :     foreach(list_item, raw_parsetree_list)
                                              +  + ]
                              14515                 :                :     {
 2561                         14516                 :            328 :         RawStmt    *rs = lfirst_node(RawStmt, list_item);
 2647                         14517                 :            328 :         Node       *stmt = rs->stmt;
                              14518                 :                : 
 6140                         14519         [ +  + ]:            328 :         if (IsA(stmt, IndexStmt))
                              14520                 :            106 :             querytree_list = lappend(querytree_list,
 3709 rhaas@postgresql.org    14521                 :            106 :                                      transformIndexStmt(oldRelId,
                              14522                 :                :                                                         (IndexStmt *) stmt,
                              14523                 :                :                                                         cmd));
 6140 tgl@sss.pgh.pa.us       14524         [ +  + ]:            222 :         else if (IsA(stmt, AlterTableStmt))
                              14525                 :                :         {
                              14526                 :                :             List       *beforeStmts;
                              14527                 :                :             List       *afterStmts;
                              14528                 :                : 
 1551                         14529                 :            208 :             stmt = (Node *) transformAlterTableStmt(oldRelId,
                              14530                 :                :                                                     (AlterTableStmt *) stmt,
                              14531                 :                :                                                     cmd,
                              14532                 :                :                                                     &beforeStmts,
                              14533                 :                :                                                     &afterStmts);
                              14534                 :            208 :             querytree_list = list_concat(querytree_list, beforeStmts);
                              14535                 :            208 :             querytree_list = lappend(querytree_list, stmt);
                              14536                 :            208 :             querytree_list = list_concat(querytree_list, afterStmts);
                              14537                 :                :         }
 1115 tomas.vondra@postgre    14538         [ +  + ]:             14 :         else if (IsA(stmt, CreateStatsStmt))
                              14539                 :              7 :             querytree_list = lappend(querytree_list,
                              14540                 :              7 :                                      transformStatsStmt(oldRelId,
                              14541                 :                :                                                         (CreateStatsStmt *) stmt,
                              14542                 :                :                                                         cmd));
                              14543                 :                :         else
 6140 tgl@sss.pgh.pa.us       14544                 :              7 :             querytree_list = lappend(querytree_list, stmt);
                              14545                 :                :     }
                              14546                 :                : 
                              14547                 :                :     /* Caller should already have acquired whatever lock we need. */
 3709 rhaas@postgresql.org    14548                 :            328 :     rel = relation_open(oldRelId, NoLock);
                              14549                 :                : 
                              14550                 :                :     /*
                              14551                 :                :      * Attach each generated command to the proper place in the work queue.
                              14552                 :                :      * Note this could result in creation of entirely new work-queue entries.
                              14553                 :                :      *
                              14554                 :                :      * Also note that we have to tweak the command subtypes, because it turns
                              14555                 :                :      * out that re-creation of indexes and constraints has to act a bit
                              14556                 :                :      * differently from initial creation.
                              14557                 :                :      */
 7284 tgl@sss.pgh.pa.us       14558   [ +  -  +  +  :            656 :     foreach(list_item, querytree_list)
                                              +  + ]
                              14559                 :                :     {
 6140                         14560                 :            328 :         Node       *stm = (Node *) lfirst(list_item);
                              14561                 :                :         AlteredTableInfo *tab;
                              14562                 :                : 
 3197 heikki.linnakangas@i    14563                 :            328 :         tab = ATGetQueueEntry(wqueue, rel);
                              14564                 :                : 
                              14565         [ +  + ]:            328 :         if (IsA(stm, IndexStmt))
                              14566                 :                :         {
                              14567                 :            106 :             IndexStmt  *stmt = (IndexStmt *) stm;
                              14568                 :                :             AlterTableCmd *newcmd;
                              14569                 :                : 
                              14570         [ +  + ]:            106 :             if (!rewrite)
                              14571                 :             27 :                 TryReuseIndex(oldId, stmt);
 1816 alvherre@alvh.no-ip.    14572                 :            106 :             stmt->reset_default_tblspc = true;
                              14573                 :                :             /* keep the index's comment */
 3197 heikki.linnakangas@i    14574                 :            106 :             stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
                              14575                 :                : 
                              14576                 :            106 :             newcmd = makeNode(AlterTableCmd);
                              14577                 :            106 :             newcmd->subtype = AT_ReAddIndex;
                              14578                 :            106 :             newcmd->def = (Node *) stmt;
                              14579                 :            106 :             tab->subcmds[AT_PASS_OLD_INDEX] =
                              14580                 :            106 :                 lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
                              14581                 :                :         }
                              14582         [ +  + ]:            222 :         else if (IsA(stm, AlterTableStmt))
                              14583                 :                :         {
                              14584                 :            208 :             AlterTableStmt *stmt = (AlterTableStmt *) stm;
                              14585                 :                :             ListCell   *lcmd;
                              14586                 :                : 
                              14587   [ +  -  +  +  :            494 :             foreach(lcmd, stmt->cmds)
                                              +  + ]
                              14588                 :                :             {
 1000 peter@eisentraut.org    14589                 :            286 :                 AlterTableCmd *cmd = lfirst_node(AlterTableCmd, lcmd);
                              14590                 :                : 
 3197 heikki.linnakangas@i    14591         [ +  + ]:            286 :                 if (cmd->subtype == AT_AddIndex)
                              14592                 :                :                 {
                              14593                 :                :                     IndexStmt  *indstmt;
                              14594                 :                :                     Oid         indoid;
                              14595                 :                : 
 2635 andres@anarazel.de      14596                 :            111 :                     indstmt = castNode(IndexStmt, cmd->def);
 3197 heikki.linnakangas@i    14597                 :            111 :                     indoid = get_constraint_index(oldId);
                              14598                 :                : 
 4654 rhaas@postgresql.org    14599         [ +  + ]:            111 :                     if (!rewrite)
 3197 heikki.linnakangas@i    14600                 :             24 :                         TryReuseIndex(indoid, indstmt);
                              14601                 :                :                     /* keep any comment on the index */
                              14602                 :            111 :                     indstmt->idxcomment = GetComment(indoid,
                              14603                 :                :                                                      RelationRelationId, 0);
 1816 alvherre@alvh.no-ip.    14604                 :            111 :                     indstmt->reset_default_tblspc = true;
                              14605                 :                : 
 3197 heikki.linnakangas@i    14606                 :            111 :                     cmd->subtype = AT_ReAddIndex;
 7168 bruce@momjian.us        14607                 :            111 :                     tab->subcmds[AT_PASS_OLD_INDEX] =
 3197 heikki.linnakangas@i    14608                 :            111 :                         lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
                              14609                 :                : 
                              14610                 :                :                     /* recreate any comment on the constraint */
                              14611                 :            111 :                     RebuildConstraintComment(tab,
                              14612                 :                :                                              AT_PASS_OLD_INDEX,
                              14613                 :                :                                              oldId,
                              14614                 :                :                                              rel,
                              14615                 :                :                                              NIL,
 2356 tgl@sss.pgh.pa.us       14616                 :            111 :                                              indstmt->idxname);
                              14617                 :                :                 }
 3197 heikki.linnakangas@i    14618         [ +  + ]:            175 :                 else if (cmd->subtype == AT_AddConstraint)
                              14619                 :                :                 {
 2356 tgl@sss.pgh.pa.us       14620                 :             97 :                     Constraint *con = castNode(Constraint, cmd->def);
                              14621                 :                : 
 3197 heikki.linnakangas@i    14622                 :             97 :                     con->old_pktable_oid = refRelId;
                              14623                 :                :                     /* rewriting neither side of a FK */
                              14624         [ +  + ]:             97 :                     if (con->contype == CONSTR_FOREIGN &&
                              14625   [ +  +  +  - ]:             36 :                         !rewrite && tab->rewrite == 0)
                              14626                 :              3 :                         TryReuseForeignKey(oldId, con);
 1816 alvherre@alvh.no-ip.    14627                 :             97 :                     con->reset_default_tblspc = true;
 3197 heikki.linnakangas@i    14628                 :             97 :                     cmd->subtype = AT_ReAddConstraint;
                              14629                 :             97 :                     tab->subcmds[AT_PASS_OLD_CONSTR] =
                              14630                 :             97 :                         lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
                              14631                 :                : 
                              14632                 :                :                     /* recreate any comment on the constraint */
                              14633                 :             97 :                     RebuildConstraintComment(tab,
                              14634                 :                :                                              AT_PASS_OLD_CONSTR,
                              14635                 :                :                                              oldId,
                              14636                 :                :                                              rel,
                              14637                 :                :                                              NIL,
 2356 tgl@sss.pgh.pa.us       14638                 :             97 :                                              con->conname);
                              14639                 :                :                 }
  233 alvherre@alvh.no-ip.    14640         [ -  + ]:GNC          78 :                 else if (cmd->subtype == AT_SetAttNotNull)
                              14641                 :                :                 {
                              14642                 :                :                     /*
                              14643                 :                :                      * The parser will create AT_AttSetNotNull subcommands for
                              14644                 :                :                      * columns of PRIMARY KEY indexes/constraints, but we need
                              14645                 :                :                      * not do anything with them here, because the columns'
                              14646                 :                :                      * NOT NULL marks will already have been propagated into
                              14647                 :                :                      * the new table definition.
                              14648                 :                :                      */
                              14649                 :                :                 }
                              14650                 :                :                 else
 3068 tgl@sss.pgh.pa.us       14651         [ #  # ]:UBC           0 :                     elog(ERROR, "unexpected statement subtype: %d",
                              14652                 :                :                          (int) cmd->subtype);
                              14653                 :                :             }
                              14654                 :                :         }
 2356 tgl@sss.pgh.pa.us       14655         [ +  + ]:CBC          14 :         else if (IsA(stm, AlterDomainStmt))
                              14656                 :                :         {
                              14657                 :              7 :             AlterDomainStmt *stmt = (AlterDomainStmt *) stm;
                              14658                 :                : 
                              14659         [ +  - ]:              7 :             if (stmt->subtype == 'C')    /* ADD CONSTRAINT */
                              14660                 :                :             {
                              14661                 :              7 :                 Constraint *con = castNode(Constraint, stmt->def);
                              14662                 :              7 :                 AlterTableCmd *cmd = makeNode(AlterTableCmd);
                              14663                 :                : 
                              14664                 :              7 :                 cmd->subtype = AT_ReAddDomainConstraint;
                              14665                 :              7 :                 cmd->def = (Node *) stmt;
                              14666                 :              7 :                 tab->subcmds[AT_PASS_OLD_CONSTR] =
                              14667                 :              7 :                     lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
                              14668                 :                : 
                              14669                 :                :                 /* recreate any comment on the constraint */
                              14670                 :              7 :                 RebuildConstraintComment(tab,
                              14671                 :                :                                          AT_PASS_OLD_CONSTR,
                              14672                 :                :                                          oldId,
                              14673                 :                :                                          NULL,
                              14674                 :                :                                          stmt->typeName,
                              14675                 :              7 :                                          con->conname);
                              14676                 :                :             }
                              14677                 :                :             else
 2356 tgl@sss.pgh.pa.us       14678         [ #  # ]:UBC           0 :                 elog(ERROR, "unexpected statement subtype: %d",
                              14679                 :                :                      (int) stmt->subtype);
                              14680                 :                :         }
 1115 tomas.vondra@postgre    14681         [ +  - ]:CBC           7 :         else if (IsA(stm, CreateStatsStmt))
                              14682                 :                :         {
 1068 tgl@sss.pgh.pa.us       14683                 :              7 :             CreateStatsStmt *stmt = (CreateStatsStmt *) stm;
                              14684                 :                :             AlterTableCmd *newcmd;
                              14685                 :                : 
                              14686                 :                :             /* keep the statistics object's comment */
 1115 tomas.vondra@postgre    14687                 :              7 :             stmt->stxcomment = GetComment(oldId, StatisticExtRelationId, 0);
                              14688                 :                : 
                              14689                 :              7 :             newcmd = makeNode(AlterTableCmd);
                              14690                 :              7 :             newcmd->subtype = AT_ReAddStatistics;
                              14691                 :              7 :             newcmd->def = (Node *) stmt;
                              14692                 :              7 :             tab->subcmds[AT_PASS_MISC] =
                              14693                 :              7 :                 lappend(tab->subcmds[AT_PASS_MISC], newcmd);
                              14694                 :                :         }
                              14695                 :                :         else
 3197 heikki.linnakangas@i    14696         [ #  # ]:UBC           0 :             elog(ERROR, "unexpected statement type: %d",
                              14697                 :                :                  (int) nodeTag(stm));
                              14698                 :                :     }
                              14699                 :                : 
 3709 rhaas@postgresql.org    14700                 :CBC         328 :     relation_close(rel, NoLock);
 8024 tgl@sss.pgh.pa.us       14701                 :            328 : }
                              14702                 :                : 
                              14703                 :                : /*
                              14704                 :                :  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
                              14705                 :                :  * for a table or domain constraint that is being rebuilt.
                              14706                 :                :  *
                              14707                 :                :  * objid is the OID of the constraint.
                              14708                 :                :  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
                              14709                 :                :  * as a string list) for a domain constraint.
                              14710                 :                :  * (We could dig that info, as well as the conname, out of the pg_constraint
                              14711                 :                :  * entry; but callers already have them so might as well pass them.)
                              14712                 :                :  */
                              14713                 :                : static void
  104 peter@eisentraut.org    14714                 :GNC         215 : RebuildConstraintComment(AlteredTableInfo *tab, AlterTablePass pass, Oid objid,
                              14715                 :                :                          Relation rel, List *domname,
                              14716                 :                :                          const char *conname)
                              14717                 :                : {
                              14718                 :                :     CommentStmt *cmd;
                              14719                 :                :     char       *comment_str;
                              14720                 :                :     AlterTableCmd *newcmd;
                              14721                 :                : 
                              14722                 :                :     /* Look for comment for object wanted, and leave if none */
 3197 heikki.linnakangas@i    14723                 :CBC         215 :     comment_str = GetComment(objid, ConstraintRelationId, 0);
                              14724         [ +  + ]:            215 :     if (comment_str == NULL)
                              14725                 :            182 :         return;
                              14726                 :                : 
                              14727                 :                :     /* Build CommentStmt node, copying all input data for safety */
                              14728                 :             33 :     cmd = makeNode(CommentStmt);
 2356 tgl@sss.pgh.pa.us       14729         [ +  + ]:             33 :     if (rel)
                              14730                 :                :     {
                              14731                 :             27 :         cmd->objtype = OBJECT_TABCONSTRAINT;
                              14732                 :             27 :         cmd->object = (Node *)
                              14733                 :             27 :             list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
                              14734                 :                :                        makeString(pstrdup(RelationGetRelationName(rel))),
                              14735                 :                :                        makeString(pstrdup(conname)));
                              14736                 :                :     }
                              14737                 :                :     else
                              14738                 :                :     {
                              14739                 :              6 :         cmd->objtype = OBJECT_DOMCONSTRAINT;
                              14740                 :              6 :         cmd->object = (Node *)
                              14741                 :              6 :             list_make2(makeTypeNameFromNameList(copyObject(domname)),
                              14742                 :                :                        makeString(pstrdup(conname)));
                              14743                 :                :     }
 3197 heikki.linnakangas@i    14744                 :             33 :     cmd->comment = comment_str;
                              14745                 :                : 
                              14746                 :                :     /* Append it to list of commands */
                              14747                 :             33 :     newcmd = makeNode(AlterTableCmd);
                              14748                 :             33 :     newcmd->subtype = AT_ReAddComment;
                              14749                 :             33 :     newcmd->def = (Node *) cmd;
                              14750                 :             33 :     tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
                              14751                 :                : }
                              14752                 :                : 
                              14753                 :                : /*
                              14754                 :                :  * Subroutine for ATPostAlterTypeParse().  Calls out to CheckIndexCompatible()
                              14755                 :                :  * for the real analysis, then mutates the IndexStmt based on that verdict.
                              14756                 :                :  */
                              14757                 :                : static void
 4654 rhaas@postgresql.org    14758                 :             51 : TryReuseIndex(Oid oldId, IndexStmt *stmt)
                              14759                 :                : {
                              14760         [ +  - ]:             51 :     if (CheckIndexCompatible(oldId,
                              14761                 :             51 :                              stmt->accessMethod,
 4654 rhaas@postgresql.org    14762                 :GIC          51 :                              stmt->indexParams,
   81 peter@eisentraut.org    14763                 :GNC          51 :                              stmt->excludeOpNames,
                              14764                 :             51 :                              stmt->iswithoutoverlaps))
                              14765                 :                :     {
 4326 bruce@momjian.us        14766                 :CBC          51 :         Relation    irel = index_open(oldId, NoLock);
                              14767                 :                : 
                              14768                 :                :         /* If it's a partitioned index, there is no storage to share. */
 1815 tgl@sss.pgh.pa.us       14769         [ +  + ]:             51 :         if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
                              14770                 :                :         {
  648 rhaas@postgresql.org    14771                 :             36 :             stmt->oldNumber = irel->rd_locator.relNumber;
 1471 noah@leadboat.com       14772                 :             36 :             stmt->oldCreateSubid = irel->rd_createSubid;
  648 rhaas@postgresql.org    14773                 :             36 :             stmt->oldFirstRelfilelocatorSubid = irel->rd_firstRelfilelocatorSubid;
                              14774                 :                :         }
 4654                         14775                 :             51 :         index_close(irel, NoLock);
                              14776                 :                :     }
                              14777                 :             51 : }
                              14778                 :                : 
                              14779                 :                : /*
                              14780                 :                :  * Subroutine for ATPostAlterTypeParse().
                              14781                 :                :  *
                              14782                 :                :  * Stash the old P-F equality operator into the Constraint node, for possible
                              14783                 :                :  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
                              14784                 :                :  * this constraint can be skipped.
                              14785                 :                :  */
                              14786                 :                : static void
 4430 alvherre@alvh.no-ip.    14787                 :              3 : TryReuseForeignKey(Oid oldId, Constraint *con)
                              14788                 :                : {
                              14789                 :                :     HeapTuple   tup;
                              14790                 :                :     Datum       adatum;
                              14791                 :                :     ArrayType  *arr;
                              14792                 :                :     Oid        *rawarr;
                              14793                 :                :     int         numkeys;
                              14794                 :                :     int         i;
                              14795                 :                : 
                              14796         [ -  + ]:              3 :     Assert(con->contype == CONSTR_FOREIGN);
 4326 bruce@momjian.us        14797         [ -  + ]:              3 :     Assert(con->old_conpfeqop == NIL);   /* already prepared this node */
                              14798                 :                : 
 4430 alvherre@alvh.no-ip.    14799                 :              3 :     tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
                              14800         [ -  + ]:              3 :     if (!HeapTupleIsValid(tup)) /* should not happen */
 4430 alvherre@alvh.no-ip.    14801         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for constraint %u", oldId);
                              14802                 :                : 
  386 dgustafsson@postgres    14803                 :CBC           3 :     adatum = SysCacheGetAttrNotNull(CONSTROID, tup,
                              14804                 :                :                                     Anum_pg_constraint_conpfeqop);
 4430 alvherre@alvh.no-ip.    14805                 :              3 :     arr = DatumGetArrayTypeP(adatum);   /* ensure not toasted */
                              14806                 :              3 :     numkeys = ARR_DIMS(arr)[0];
                              14807                 :                :     /* test follows the one in ri_FetchConstraintInfo() */
                              14808         [ +  - ]:              3 :     if (ARR_NDIM(arr) != 1 ||
                              14809         [ +  - ]:              3 :         ARR_HASNULL(arr) ||
                              14810         [ -  + ]:              3 :         ARR_ELEMTYPE(arr) != OIDOID)
 4430 alvherre@alvh.no-ip.    14811         [ #  # ]:UBC           0 :         elog(ERROR, "conpfeqop is not a 1-D Oid array");
 4430 alvherre@alvh.no-ip.    14812         [ -  + ]:CBC           3 :     rawarr = (Oid *) ARR_DATA_PTR(arr);
                              14813                 :                : 
                              14814                 :                :     /* stash a List of the operator Oids in our Constraint node */
                              14815         [ +  + ]:              6 :     for (i = 0; i < numkeys; i++)
 1734 tgl@sss.pgh.pa.us       14816                 :              3 :         con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
                              14817                 :                : 
 4430 alvherre@alvh.no-ip.    14818                 :              3 :     ReleaseSysCache(tup);
                              14819                 :              3 : }
                              14820                 :                : 
                              14821                 :                : /*
                              14822                 :                :  * ALTER COLUMN .. OPTIONS ( ... )
                              14823                 :                :  *
                              14824                 :                :  * Returns the address of the modified column
                              14825                 :                :  */
                              14826                 :                : static ObjectAddress
 1756 tgl@sss.pgh.pa.us       14827                 :             82 : ATExecAlterColumnGenericOptions(Relation rel,
                              14828                 :                :                                 const char *colName,
                              14829                 :                :                                 List *options,
                              14830                 :                :                                 LOCKMODE lockmode)
                              14831                 :                : {
                              14832                 :                :     Relation    ftrel;
                              14833                 :                :     Relation    attrel;
                              14834                 :                :     ForeignServer *server;
                              14835                 :                :     ForeignDataWrapper *fdw;
                              14836                 :                :     HeapTuple   tuple;
                              14837                 :                :     HeapTuple   newtuple;
                              14838                 :                :     bool        isnull;
                              14839                 :                :     Datum       repl_val[Natts_pg_attribute];
                              14840                 :                :     bool        repl_null[Natts_pg_attribute];
                              14841                 :                :     bool        repl_repl[Natts_pg_attribute];
                              14842                 :                :     Datum       datum;
                              14843                 :                :     Form_pg_foreign_table fttableform;
                              14844                 :                :     Form_pg_attribute atttableform;
                              14845                 :                :     AttrNumber  attnum;
                              14846                 :                :     ObjectAddress address;
                              14847                 :                : 
                              14848         [ -  + ]:             82 :     if (options == NIL)
 1756 tgl@sss.pgh.pa.us       14849                 :UBC           0 :         return InvalidObjectAddress;
                              14850                 :                : 
                              14851                 :                :     /* First, determine FDW validator associated to the foreign table. */
 1756 tgl@sss.pgh.pa.us       14852                 :CBC          82 :     ftrel = table_open(ForeignTableRelationId, AccessShareLock);
  269 michael@paquier.xyz     14853                 :GNC          82 :     tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(rel->rd_id));
 1756 tgl@sss.pgh.pa.us       14854         [ -  + ]:CBC          82 :     if (!HeapTupleIsValid(tuple))
 1756 tgl@sss.pgh.pa.us       14855         [ #  # ]:UBC           0 :         ereport(ERROR,
                              14856                 :                :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              14857                 :                :                  errmsg("foreign table \"%s\" does not exist",
                              14858                 :                :                         RelationGetRelationName(rel))));
 1756 tgl@sss.pgh.pa.us       14859                 :CBC          82 :     fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
                              14860                 :             82 :     server = GetForeignServer(fttableform->ftserver);
                              14861                 :             82 :     fdw = GetForeignDataWrapper(server->fdwid);
                              14862                 :                : 
                              14863                 :             82 :     table_close(ftrel, AccessShareLock);
                              14864                 :             82 :     ReleaseSysCache(tuple);
                              14865                 :                : 
                              14866                 :             82 :     attrel = table_open(AttributeRelationId, RowExclusiveLock);
                              14867                 :             82 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
                              14868         [ -  + ]:             82 :     if (!HeapTupleIsValid(tuple))
 1756 tgl@sss.pgh.pa.us       14869         [ #  # ]:UBC           0 :         ereport(ERROR,
                              14870                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                              14871                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                              14872                 :                :                         colName, RelationGetRelationName(rel))));
                              14873                 :                : 
                              14874                 :                :     /* Prevent them from altering a system attribute */
 1756 tgl@sss.pgh.pa.us       14875                 :CBC          82 :     atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
                              14876                 :             82 :     attnum = atttableform->attnum;
                              14877         [ +  + ]:             82 :     if (attnum <= 0)
                              14878         [ +  - ]:              3 :         ereport(ERROR,
                              14879                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              14880                 :                :                  errmsg("cannot alter system column \"%s\"", colName)));
                              14881                 :                : 
                              14882                 :                : 
                              14883                 :                :     /* Initialize buffers for new tuple values */
                              14884                 :             79 :     memset(repl_val, 0, sizeof(repl_val));
                              14885                 :             79 :     memset(repl_null, false, sizeof(repl_null));
                              14886                 :             79 :     memset(repl_repl, false, sizeof(repl_repl));
                              14887                 :                : 
                              14888                 :                :     /* Extract the current options */
                              14889                 :             79 :     datum = SysCacheGetAttr(ATTNAME,
                              14890                 :                :                             tuple,
                              14891                 :                :                             Anum_pg_attribute_attfdwoptions,
                              14892                 :                :                             &isnull);
                              14893         [ +  + ]:             79 :     if (isnull)
                              14894                 :             74 :         datum = PointerGetDatum(NULL);
                              14895                 :                : 
                              14896                 :                :     /* Transform the options */
                              14897                 :             79 :     datum = transformGenericOptions(AttributeRelationId,
                              14898                 :                :                                     datum,
                              14899                 :                :                                     options,
                              14900                 :                :                                     fdw->fdwvalidator);
                              14901                 :                : 
                              14902         [ +  - ]:             79 :     if (PointerIsValid(DatumGetPointer(datum)))
                              14903                 :             79 :         repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
                              14904                 :                :     else
 1756 tgl@sss.pgh.pa.us       14905                 :UBC           0 :         repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
                              14906                 :                : 
 1756 tgl@sss.pgh.pa.us       14907                 :CBC          79 :     repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
                              14908                 :                : 
                              14909                 :                :     /* Everything looks good - update the tuple */
                              14910                 :                : 
                              14911                 :             79 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
                              14912                 :                :                                  repl_val, repl_null, repl_repl);
                              14913                 :                : 
                              14914                 :             79 :     CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
                              14915                 :                : 
                              14916         [ -  + ]:             79 :     InvokeObjectPostAlterHook(RelationRelationId,
                              14917                 :                :                               RelationGetRelid(rel),
                              14918                 :                :                               atttableform->attnum);
                              14919                 :             79 :     ObjectAddressSubSet(address, RelationRelationId,
                              14920                 :                :                         RelationGetRelid(rel), attnum);
                              14921                 :                : 
                              14922                 :             79 :     ReleaseSysCache(tuple);
                              14923                 :                : 
                              14924                 :             79 :     table_close(attrel, RowExclusiveLock);
                              14925                 :                : 
                              14926                 :             79 :     heap_freetuple(newtuple);
                              14927                 :                : 
                              14928                 :             79 :     return address;
                              14929                 :                : }
                              14930                 :                : 
                              14931                 :                : /*
                              14932                 :                :  * ALTER TABLE OWNER
                              14933                 :                :  *
                              14934                 :                :  * recursing is true if we are recursing from a table to its indexes,
                              14935                 :                :  * sequences, or toast table.  We don't allow the ownership of those things to
                              14936                 :                :  * be changed separately from the parent table.  Also, we can skip permission
                              14937                 :                :  * checks (this is necessary not just an optimization, else we'd fail to
                              14938                 :                :  * handle toast tables properly).
                              14939                 :                :  *
                              14940                 :                :  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
                              14941                 :                :  * free-standing composite type.
                              14942                 :                :  */
                              14943                 :                : void
 5009 simon@2ndQuadrant.co    14944                 :            989 : ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
                              14945                 :                : {
                              14946                 :                :     Relation    target_rel;
                              14947                 :                :     Relation    class_rel;
                              14948                 :                :     HeapTuple   tuple;
                              14949                 :                :     Form_pg_class tuple_class;
                              14950                 :                : 
                              14951                 :                :     /*
                              14952                 :                :      * Get exclusive lock till end of transaction on the target table. Use
                              14953                 :                :      * relation_open so that we can work on indexes and sequences.
                              14954                 :                :      */
                              14955                 :            989 :     target_rel = relation_open(relationOid, lockmode);
                              14956                 :                : 
                              14957                 :                :     /* Get its pg_class tuple, too */
 1910 andres@anarazel.de      14958                 :            989 :     class_rel = table_open(RelationRelationId, RowExclusiveLock);
                              14959                 :                : 
 5173 rhaas@postgresql.org    14960                 :            989 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
 8024 tgl@sss.pgh.pa.us       14961         [ -  + ]:            989 :     if (!HeapTupleIsValid(tuple))
 7574 tgl@sss.pgh.pa.us       14962         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relationOid);
 8024 tgl@sss.pgh.pa.us       14963                 :CBC         989 :     tuple_class = (Form_pg_class) GETSTRUCT(tuple);
                              14964                 :                : 
                              14965                 :                :     /* Can we change the ownership of this tuple? */
 7574                         14966   [ +  +  +  +  :            989 :     switch (tuple_class->relkind)
                                           +  +  - ]
                              14967                 :                :     {
                              14968                 :            870 :         case RELKIND_RELATION:
                              14969                 :                :         case RELKIND_VIEW:
                              14970                 :                :         case RELKIND_MATVIEW:
                              14971                 :                :         case RELKIND_FOREIGN_TABLE:
                              14972                 :                :         case RELKIND_PARTITIONED_TABLE:
                              14973                 :                :             /* ok to change owner */
                              14974                 :            870 :             break;
 6828                         14975                 :             42 :         case RELKIND_INDEX:
 6810                         14976         [ -  + ]:             42 :             if (!recursing)
                              14977                 :                :             {
                              14978                 :                :                 /*
                              14979                 :                :                  * Because ALTER INDEX OWNER used to be allowed, and in fact
                              14980                 :                :                  * is generated by old versions of pg_dump, we give a warning
                              14981                 :                :                  * and do nothing rather than erroring out.  Also, to avoid
                              14982                 :                :                  * unnecessary chatter while restoring those old dumps, say
                              14983                 :                :                  * nothing at all if the command would be a no-op anyway.
                              14984                 :                :                  */
 6810 tgl@sss.pgh.pa.us       14985         [ #  # ]:UBC           0 :                 if (tuple_class->relowner != newOwnerId)
                              14986         [ #  # ]:              0 :                     ereport(WARNING,
                              14987                 :                :                             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              14988                 :                :                              errmsg("cannot change owner of index \"%s\"",
                              14989                 :                :                                     NameStr(tuple_class->relname)),
                              14990                 :                :                              errhint("Change the ownership of the index's table instead.")));
                              14991                 :                :                 /* quick hack to exit via the no-op path */
                              14992                 :              0 :                 newOwnerId = tuple_class->relowner;
                              14993                 :                :             }
 6810 tgl@sss.pgh.pa.us       14994                 :CBC          42 :             break;
 2277 alvherre@alvh.no-ip.    14995                 :             10 :         case RELKIND_PARTITIONED_INDEX:
                              14996         [ +  - ]:             10 :             if (recursing)
                              14997                 :             10 :                 break;
 2277 alvherre@alvh.no-ip.    14998         [ #  # ]:UBC           0 :             ereport(ERROR,
                              14999                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15000                 :                :                      errmsg("cannot change owner of index \"%s\"",
                              15001                 :                :                             NameStr(tuple_class->relname)),
                              15002                 :                :                      errhint("Change the ownership of the index's table instead.")));
                              15003                 :                :             break;
 6446 tgl@sss.pgh.pa.us       15004                 :CBC          46 :         case RELKIND_SEQUENCE:
                              15005         [ +  + ]:             46 :             if (!recursing &&
                              15006         [ -  + ]:             31 :                 tuple_class->relowner != newOwnerId)
                              15007                 :                :             {
                              15008                 :                :                 /* if it's an owned sequence, disallow changing it by itself */
                              15009                 :                :                 Oid         tableId;
                              15010                 :                :                 int32       colId;
                              15011                 :                : 
 2565 peter_e@gmx.net         15012   [ #  #  #  # ]:UBC           0 :                 if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
                              15013                 :              0 :                     sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
 6446 tgl@sss.pgh.pa.us       15014         [ #  # ]:              0 :                     ereport(ERROR,
                              15015                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              15016                 :                :                              errmsg("cannot change owner of sequence \"%s\"",
                              15017                 :                :                                     NameStr(tuple_class->relname)),
                              15018                 :                :                              errdetail("Sequence \"%s\" is linked to table \"%s\".",
                              15019                 :                :                                        NameStr(tuple_class->relname),
                              15020                 :                :                                        get_rel_name(tableId))));
                              15021                 :                :             }
 6446 tgl@sss.pgh.pa.us       15022                 :CBC          46 :             break;
 6183                         15023                 :              3 :         case RELKIND_COMPOSITE_TYPE:
 6042                         15024         [ +  - ]:              3 :             if (recursing)
                              15025                 :              3 :                 break;
 6042 tgl@sss.pgh.pa.us       15026         [ #  # ]:UBC           0 :             ereport(ERROR,
                              15027                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15028                 :                :                      errmsg("\"%s\" is a composite type",
                              15029                 :                :                             NameStr(tuple_class->relname)),
                              15030                 :                :             /* translator: %s is an SQL ALTER command */
                              15031                 :                :                      errhint("Use %s instead.",
                              15032                 :                :                              "ALTER TYPE")));
                              15033                 :                :             break;
 6042 tgl@sss.pgh.pa.us       15034                 :CBC          18 :         case RELKIND_TOASTVALUE:
 6828                         15035         [ +  - ]:             18 :             if (recursing)
                              15036                 :             18 :                 break;
                              15037                 :                :             /* FALL THRU */
                              15038                 :                :         default:
 7574 tgl@sss.pgh.pa.us       15039         [ #  # ]:UBC           0 :             ereport(ERROR,
                              15040                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15041                 :                :                      errmsg("cannot change owner of relation \"%s\"",
                              15042                 :                :                             NameStr(tuple_class->relname)),
                              15043                 :                :                      errdetail_relkind_not_supported(tuple_class->relkind)));
                              15044                 :                :     }
                              15045                 :                : 
                              15046                 :                :     /*
                              15047                 :                :      * If the new owner is the same as the existing owner, consider the
                              15048                 :                :      * command to have succeeded.  This is for dump restoration purposes.
                              15049                 :                :      */
 6865 tgl@sss.pgh.pa.us       15050         [ +  + ]:CBC         989 :     if (tuple_class->relowner != newOwnerId)
                              15051                 :                :     {
                              15052                 :                :         Datum       repl_val[Natts_pg_class];
                              15053                 :                :         bool        repl_null[Natts_pg_class];
                              15054                 :                :         bool        repl_repl[Natts_pg_class];
                              15055                 :                :         Acl        *newAcl;
                              15056                 :                :         Datum       aclDatum;
                              15057                 :                :         bool        isNull;
                              15058                 :                :         HeapTuple   newtuple;
                              15059                 :                : 
                              15060                 :                :         /* skip permission checks when recursing to index or toast table */
 6828                         15061         [ +  + ]:            225 :         if (!recursing)
                              15062                 :                :         {
                              15063                 :                :             /* Superusers can always do it */
 6810                         15064         [ +  + ]:            137 :             if (!superuser())
                              15065                 :                :             {
 6756 bruce@momjian.us        15066                 :             21 :                 Oid         namespaceOid = tuple_class->relnamespace;
                              15067                 :                :                 AclResult   aclresult;
                              15068                 :                : 
                              15069                 :                :                 /* Otherwise, must be owner of the existing object */
  518 peter@eisentraut.org    15070         [ -  + ]:             21 :                 if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
 2325 peter_e@gmx.net         15071                 :UBC           0 :                     aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relationOid)),
 6810 tgl@sss.pgh.pa.us       15072                 :              0 :                                    RelationGetRelationName(target_rel));
                              15073                 :                : 
                              15074                 :                :                 /* Must be able to become new owner */
  513 rhaas@postgresql.org    15075                 :CBC          21 :                 check_can_set_role(GetUserId(), newOwnerId);
                              15076                 :                : 
                              15077                 :                :                 /* New owner must have CREATE privilege on namespace */
  518 peter@eisentraut.org    15078                 :             15 :                 aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
                              15079                 :                :                                             ACL_CREATE);
 6810 tgl@sss.pgh.pa.us       15080         [ -  + ]:             15 :                 if (aclresult != ACLCHECK_OK)
 2325 peter_e@gmx.net         15081                 :UBC           0 :                     aclcheck_error(aclresult, OBJECT_SCHEMA,
 6810 tgl@sss.pgh.pa.us       15082                 :              0 :                                    get_namespace_name(namespaceOid));
                              15083                 :                :             }
                              15084                 :                :         }
                              15085                 :                : 
 5642 tgl@sss.pgh.pa.us       15086                 :CBC         219 :         memset(repl_null, false, sizeof(repl_null));
                              15087                 :            219 :         memset(repl_repl, false, sizeof(repl_repl));
                              15088                 :                : 
                              15089                 :            219 :         repl_repl[Anum_pg_class_relowner - 1] = true;
 6865                         15090                 :            219 :         repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
                              15091                 :                : 
                              15092                 :                :         /*
                              15093                 :                :          * Determine the modified ACL for the new owner.  This is only
                              15094                 :                :          * necessary when the ACL is non-null.
                              15095                 :                :          */
 7196                         15096                 :            219 :         aclDatum = SysCacheGetAttr(RELOID, tuple,
                              15097                 :                :                                    Anum_pg_class_relacl,
                              15098                 :                :                                    &isNull);
                              15099         [ +  + ]:            219 :         if (!isNull)
                              15100                 :                :         {
                              15101                 :             16 :             newAcl = aclnewowner(DatumGetAclP(aclDatum),
                              15102                 :                :                                  tuple_class->relowner, newOwnerId);
 5642                         15103                 :             16 :             repl_repl[Anum_pg_class_relacl - 1] = true;
 7196                         15104                 :             16 :             repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
                              15105                 :                :         }
                              15106                 :                : 
 5642                         15107                 :            219 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
                              15108                 :                : 
 2630 alvherre@alvh.no-ip.    15109                 :            219 :         CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
                              15110                 :                : 
 7196 tgl@sss.pgh.pa.us       15111                 :            219 :         heap_freetuple(newtuple);
                              15112                 :                : 
                              15113                 :                :         /*
                              15114                 :                :          * We must similarly update any per-column ACLs to reflect the new
                              15115                 :                :          * owner; for neatness reasons that's split out as a subroutine.
                              15116                 :                :          */
 4498                         15117                 :            219 :         change_owner_fix_column_acls(relationOid,
                              15118                 :                :                                      tuple_class->relowner,
                              15119                 :                :                                      newOwnerId);
                              15120                 :                : 
                              15121                 :                :         /*
                              15122                 :                :          * Update owner dependency reference, if any.  A composite type has
                              15123                 :                :          * none, because it's tracked for the pg_type entry instead of here;
                              15124                 :                :          * indexes and TOAST tables don't have their own entries either.
                              15125                 :                :          */
 6183                         15126         [ +  + ]:            219 :         if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
 6180                         15127         [ +  + ]:            216 :             tuple_class->relkind != RELKIND_INDEX &&
 2277 alvherre@alvh.no-ip.    15128         [ +  + ]:            174 :             tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
 6180 tgl@sss.pgh.pa.us       15129         [ +  + ]:            164 :             tuple_class->relkind != RELKIND_TOASTVALUE)
 6183                         15130                 :            146 :             changeDependencyOnOwner(RelationRelationId, relationOid,
                              15131                 :                :                                     newOwnerId);
                              15132                 :                : 
                              15133                 :                :         /*
                              15134                 :                :          * Also change the ownership of the table's row type, if it has one
                              15135                 :                :          */
 1377                         15136         [ +  + ]:            219 :         if (OidIsValid(tuple_class->reltype))
 3041 alvherre@alvh.no-ip.    15137                 :            140 :             AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
                              15138                 :                : 
                              15139                 :                :         /*
                              15140                 :                :          * If we are operating on a table or materialized view, also change
                              15141                 :                :          * the ownership of any indexes and sequences that belong to the
                              15142                 :                :          * relation, as well as its toast table (if it has one).
                              15143                 :                :          */
 7233 tgl@sss.pgh.pa.us       15144         [ +  + ]:            219 :         if (tuple_class->relkind == RELKIND_RELATION ||
 2277 alvherre@alvh.no-ip.    15145         [ +  + ]:            113 :             tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
 4060 kgrittn@postgresql.o    15146         [ +  - ]:             94 :             tuple_class->relkind == RELKIND_MATVIEW ||
 7233 tgl@sss.pgh.pa.us       15147         [ +  + ]:             94 :             tuple_class->relkind == RELKIND_TOASTVALUE)
                              15148                 :                :         {
                              15149                 :                :             List       *index_oid_list;
                              15150                 :                :             ListCell   *i;
                              15151                 :                : 
                              15152                 :                :             /* Find all the indexes belonging to this relation */
                              15153                 :            143 :             index_oid_list = RelationGetIndexList(target_rel);
                              15154                 :                : 
                              15155                 :                :             /* For each index, recursively change its ownership */
                              15156   [ +  +  +  +  :            195 :             foreach(i, index_oid_list)
                                              +  + ]
 5009 simon@2ndQuadrant.co    15157                 :             52 :                 ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
                              15158                 :                : 
 7233 tgl@sss.pgh.pa.us       15159                 :            143 :             list_free(index_oid_list);
                              15160                 :                :         }
                              15161                 :                : 
                              15162                 :                :         /* If it has a toast table, recurse to change its ownership */
 2131 peter_e@gmx.net         15163         [ +  + ]:            219 :         if (tuple_class->reltoastrelid != InvalidOid)
                              15164                 :             18 :             ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
                              15165                 :                :                               true, lockmode);
                              15166                 :                : 
                              15167                 :                :         /* If it has dependent sequences, recurse to change them too */
                              15168                 :            219 :         change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
                              15169                 :                :     }
                              15170                 :                : 
 4046 rhaas@postgresql.org    15171         [ -  + ]:            983 :     InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
                              15172                 :                : 
 7196 tgl@sss.pgh.pa.us       15173                 :            983 :     ReleaseSysCache(tuple);
 1910 andres@anarazel.de      15174                 :            983 :     table_close(class_rel, RowExclusiveLock);
 7972 tgl@sss.pgh.pa.us       15175                 :            983 :     relation_close(target_rel, NoLock);
 8026 bruce@momjian.us        15176                 :            983 : }
                              15177                 :                : 
                              15178                 :                : /*
                              15179                 :                :  * change_owner_fix_column_acls
                              15180                 :                :  *
                              15181                 :                :  * Helper function for ATExecChangeOwner.  Scan the columns of the table
                              15182                 :                :  * and fix any non-null column ACLs to reflect the new owner.
                              15183                 :                :  */
                              15184                 :                : static void
 4498 tgl@sss.pgh.pa.us       15185                 :            219 : change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
                              15186                 :                : {
                              15187                 :                :     Relation    attRelation;
                              15188                 :                :     SysScanDesc scan;
                              15189                 :                :     ScanKeyData key[1];
                              15190                 :                :     HeapTuple   attributeTuple;
                              15191                 :                : 
 1910 andres@anarazel.de      15192                 :            219 :     attRelation = table_open(AttributeRelationId, RowExclusiveLock);
 4498 tgl@sss.pgh.pa.us       15193                 :            219 :     ScanKeyInit(&key[0],
                              15194                 :                :                 Anum_pg_attribute_attrelid,
                              15195                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              15196                 :                :                 ObjectIdGetDatum(relationOid));
                              15197                 :            219 :     scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
                              15198                 :                :                               true, NULL, 1, key);
                              15199         [ +  + ]:           1506 :     while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
                              15200                 :                :     {
                              15201                 :           1287 :         Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
                              15202                 :                :         Datum       repl_val[Natts_pg_attribute];
                              15203                 :                :         bool        repl_null[Natts_pg_attribute];
                              15204                 :                :         bool        repl_repl[Natts_pg_attribute];
                              15205                 :                :         Acl        *newAcl;
                              15206                 :                :         Datum       aclDatum;
                              15207                 :                :         bool        isNull;
                              15208                 :                :         HeapTuple   newtuple;
                              15209                 :                : 
                              15210                 :                :         /* Ignore dropped columns */
                              15211         [ -  + ]:           1287 :         if (att->attisdropped)
 4498 tgl@sss.pgh.pa.us       15212                 :UBC           0 :             continue;
                              15213                 :                : 
 4498 tgl@sss.pgh.pa.us       15214                 :CBC        1287 :         aclDatum = heap_getattr(attributeTuple,
                              15215                 :                :                                 Anum_pg_attribute_attacl,
                              15216                 :                :                                 RelationGetDescr(attRelation),
                              15217                 :                :                                 &isNull);
                              15218                 :                :         /* Null ACLs do not require changes */
                              15219         [ +  - ]:           1287 :         if (isNull)
                              15220                 :           1287 :             continue;
                              15221                 :                : 
 4498 tgl@sss.pgh.pa.us       15222                 :UBC           0 :         memset(repl_null, false, sizeof(repl_null));
                              15223                 :              0 :         memset(repl_repl, false, sizeof(repl_repl));
                              15224                 :                : 
                              15225                 :              0 :         newAcl = aclnewowner(DatumGetAclP(aclDatum),
                              15226                 :                :                              oldOwnerId, newOwnerId);
                              15227                 :              0 :         repl_repl[Anum_pg_attribute_attacl - 1] = true;
                              15228                 :              0 :         repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
                              15229                 :                : 
                              15230                 :              0 :         newtuple = heap_modify_tuple(attributeTuple,
                              15231                 :                :                                      RelationGetDescr(attRelation),
                              15232                 :                :                                      repl_val, repl_null, repl_repl);
                              15233                 :                : 
 2630 alvherre@alvh.no-ip.    15234                 :              0 :         CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
                              15235                 :                : 
 4498 tgl@sss.pgh.pa.us       15236                 :              0 :         heap_freetuple(newtuple);
                              15237                 :                :     }
 4498 tgl@sss.pgh.pa.us       15238                 :CBC         219 :     systable_endscan(scan);
 1910 andres@anarazel.de      15239                 :            219 :     table_close(attRelation, RowExclusiveLock);
 4498 tgl@sss.pgh.pa.us       15240                 :            219 : }
                              15241                 :                : 
                              15242                 :                : /*
                              15243                 :                :  * change_owner_recurse_to_sequences
                              15244                 :                :  *
                              15245                 :                :  * Helper function for ATExecChangeOwner.  Examines pg_depend searching
                              15246                 :                :  * for sequences that are dependent on serial columns, and changes their
                              15247                 :                :  * ownership.
                              15248                 :                :  */
                              15249                 :                : static void
 5009 simon@2ndQuadrant.co    15250                 :            219 : change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
                              15251                 :                : {
                              15252                 :                :     Relation    depRel;
                              15253                 :                :     SysScanDesc scan;
                              15254                 :                :     ScanKeyData key[2];
                              15255                 :                :     HeapTuple   tup;
                              15256                 :                : 
                              15257                 :                :     /*
                              15258                 :                :      * SERIAL sequences are those having an auto dependency on one of the
                              15259                 :                :      * table's columns (we don't care *which* column, exactly).
                              15260                 :                :      */
 1910 andres@anarazel.de      15261                 :            219 :     depRel = table_open(DependRelationId, AccessShareLock);
                              15262                 :                : 
 7143 tgl@sss.pgh.pa.us       15263                 :            219 :     ScanKeyInit(&key[0],
                              15264                 :                :                 Anum_pg_depend_refclassid,
                              15265                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              15266                 :                :                 ObjectIdGetDatum(RelationRelationId));
                              15267                 :            219 :     ScanKeyInit(&key[1],
                              15268                 :                :                 Anum_pg_depend_refobjid,
                              15269                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              15270                 :                :                 ObjectIdGetDatum(relationOid));
                              15271                 :                :     /* we leave refobjsubid unspecified */
                              15272                 :                : 
 6940                         15273                 :            219 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
                              15274                 :                :                               NULL, 2, key);
                              15275                 :                : 
 7143                         15276         [ +  + ]:            608 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
                              15277                 :                :     {
                              15278                 :            389 :         Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
                              15279                 :                :         Relation    seqRel;
                              15280                 :                : 
                              15281                 :                :         /* skip dependencies other than auto dependencies on columns */
                              15282         [ +  + ]:            389 :         if (depForm->refobjsubid == 0 ||
 6940                         15283         [ +  + ]:            134 :             depForm->classid != RelationRelationId ||
 7143                         15284         [ +  - ]:             61 :             depForm->objsubid != 0 ||
 2565 peter_e@gmx.net         15285   [ -  +  -  - ]:             61 :             !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
 7143 tgl@sss.pgh.pa.us       15286                 :            328 :             continue;
                              15287                 :                : 
                              15288                 :                :         /* Use relation_open just in case it's an index */
 5009 simon@2ndQuadrant.co    15289                 :             61 :         seqRel = relation_open(depForm->objid, lockmode);
                              15290                 :                : 
                              15291                 :                :         /* skip non-sequence relations */
 7143 tgl@sss.pgh.pa.us       15292         [ +  + ]:             61 :         if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
                              15293                 :                :         {
                              15294                 :                :             /* No need to keep the lock */
 5009 simon@2ndQuadrant.co    15295                 :             52 :             relation_close(seqRel, lockmode);
 7143 tgl@sss.pgh.pa.us       15296                 :             52 :             continue;
                              15297                 :                :         }
                              15298                 :                : 
                              15299                 :                :         /* We don't need to close the sequence while we alter it. */
 5009 simon@2ndQuadrant.co    15300                 :              9 :         ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
                              15301                 :                : 
                              15302                 :                :         /* Now we can close it.  Keep the lock till end of transaction. */
 7143 tgl@sss.pgh.pa.us       15303                 :              9 :         relation_close(seqRel, NoLock);
                              15304                 :                :     }
                              15305                 :                : 
                              15306                 :            219 :     systable_endscan(scan);
                              15307                 :                : 
 6960                         15308                 :            219 :     relation_close(depRel, AccessShareLock);
 7143                         15309                 :            219 : }
                              15310                 :                : 
                              15311                 :                : /*
                              15312                 :                :  * ALTER TABLE CLUSTER ON
                              15313                 :                :  *
                              15314                 :                :  * The only thing we have to do is to change the indisclustered bits.
                              15315                 :                :  *
                              15316                 :                :  * Return the address of the new clustering index.
                              15317                 :                :  */
                              15318                 :                : static ObjectAddress
 5009 simon@2ndQuadrant.co    15319                 :             32 : ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
                              15320                 :                : {
                              15321                 :                :     Oid         indexOid;
                              15322                 :                :     ObjectAddress address;
                              15323                 :                : 
 7696 bruce@momjian.us        15324                 :             32 :     indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
                              15325                 :                : 
                              15326         [ -  + ]:             32 :     if (!OidIsValid(indexOid))
 7574 tgl@sss.pgh.pa.us       15327         [ #  # ]:UBC           0 :         ereport(ERROR,
                              15328                 :                :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              15329                 :                :                  errmsg("index \"%s\" for table \"%s\" does not exist",
                              15330                 :                :                         indexName, RelationGetRelationName(rel))));
                              15331                 :                : 
                              15332                 :                :     /* Check index is valid to cluster on */
  732 michael@paquier.xyz     15333                 :CBC          32 :     check_index_is_clusterable(rel, indexOid, lockmode);
                              15334                 :                : 
                              15335                 :                :     /* And do the work */
 4046 rhaas@postgresql.org    15336                 :             32 :     mark_index_clustered(rel, indexOid, false);
                              15337                 :                : 
 3308 alvherre@alvh.no-ip.    15338                 :             29 :     ObjectAddressSet(address,
                              15339                 :                :                      RelationRelationId, indexOid);
                              15340                 :                : 
                              15341                 :             29 :     return address;
                              15342                 :                : }
                              15343                 :                : 
                              15344                 :                : /*
                              15345                 :                :  * ALTER TABLE SET WITHOUT CLUSTER
                              15346                 :                :  *
                              15347                 :                :  * We have to find any indexes on the table that have indisclustered bit
                              15348                 :                :  * set and turn it off.
                              15349                 :                :  */
                              15350                 :                : static void
 5009 simon@2ndQuadrant.co    15351                 :              9 : ATExecDropCluster(Relation rel, LOCKMODE lockmode)
                              15352                 :                : {
 4046 rhaas@postgresql.org    15353                 :              9 :     mark_index_clustered(rel, InvalidOid, false);
 7256 bruce@momjian.us        15354                 :              6 : }
                              15355                 :                : 
                              15356                 :                : /*
                              15357                 :                :  * Preparation phase for SET ACCESS METHOD
                              15358                 :                :  *
                              15359                 :                :  * Check that the access method exists and determine whether a change is
                              15360                 :                :  * actually needed.
                              15361                 :                :  */
                              15362                 :                : static void
  991 michael@paquier.xyz     15363                 :             55 : ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
                              15364                 :                : {
                              15365                 :                :     Oid         amoid;
                              15366                 :                : 
                              15367                 :                :     /*
                              15368                 :                :      * Look up the access method name and check that it differs from the
                              15369                 :                :      * table's current AM.  If DEFAULT was specified for a partitioned table
                              15370                 :                :      * (amname is NULL), set it to InvalidOid to reset the catalogued AM.
                              15371                 :                :      */
   20 alvherre@alvh.no-ip.    15372         [ +  + ]:GNC          55 :     if (amname != NULL)
                              15373                 :             37 :         amoid = get_table_am_oid(amname, false);
                              15374         [ +  + ]:             18 :     else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              15375                 :              9 :         amoid = InvalidOid;
                              15376                 :                :     else
                              15377                 :              9 :         amoid = get_table_am_oid(default_table_access_method, false);
                              15378                 :                : 
                              15379                 :                :     /* if it's a match, phase 3 doesn't need to do anything */
  991 michael@paquier.xyz     15380         [ +  + ]:CBC          55 :     if (rel->rd_rel->relam == amoid)
  991 michael@paquier.xyz     15381                 :GBC           6 :         return;
                              15382                 :                : 
                              15383                 :                :     /* Save info for Phase 3 to do the real work */
  991 michael@paquier.xyz     15384                 :CBC          49 :     tab->rewrite |= AT_REWRITE_ACCESS_METHOD;
                              15385                 :             49 :     tab->newAccessMethod = amoid;
   20 alvherre@alvh.no-ip.    15386                 :GNC          49 :     tab->chgAccessMethod = true;
                              15387                 :                : }
                              15388                 :                : 
                              15389                 :                : /*
                              15390                 :                :  * Special handling of ALTER TABLE SET ACCESS METHOD for relations with no
                              15391                 :                :  * storage that have an interest in preserving AM.
                              15392                 :                :  *
                              15393                 :                :  * Since these have no storage, setting the access method is a catalog only
                              15394                 :                :  * operation.
                              15395                 :                :  */
                              15396                 :                : static void
                              15397                 :             22 : ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId)
                              15398                 :                : {
                              15399                 :                :     Relation    pg_class;
                              15400                 :                :     Oid         oldAccessMethodId;
                              15401                 :                :     HeapTuple   tuple;
                              15402                 :                :     Form_pg_class rd_rel;
                              15403                 :             22 :     Oid         reloid = RelationGetRelid(rel);
                              15404                 :                : 
                              15405                 :                :     /*
                              15406                 :                :      * Shouldn't be called on relations having storage; these are processed in
                              15407                 :                :      * phase 3.
                              15408                 :                :      */
                              15409   [ +  -  +  -  :             22 :     Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
                                     +  -  +  -  -  
                                                 + ]
                              15410                 :                : 
                              15411                 :                :     /* Get a modifiable copy of the relation's pg_class row. */
                              15412                 :             22 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
                              15413                 :                : 
                              15414                 :             22 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
                              15415         [ -  + ]:             22 :     if (!HeapTupleIsValid(tuple))
   20 alvherre@alvh.no-ip.    15416         [ #  # ]:UNC           0 :         elog(ERROR, "cache lookup failed for relation %u", reloid);
   20 alvherre@alvh.no-ip.    15417                 :GNC          22 :     rd_rel = (Form_pg_class) GETSTRUCT(tuple);
                              15418                 :                : 
                              15419                 :                :     /* Update the pg_class row. */
                              15420                 :             22 :     oldAccessMethodId = rd_rel->relam;
                              15421                 :             22 :     rd_rel->relam = newAccessMethodId;
                              15422                 :                : 
                              15423                 :                :     /* Leave if no update required */
                              15424         [ -  + ]:             22 :     if (rd_rel->relam == oldAccessMethodId)
                              15425                 :                :     {
   20 alvherre@alvh.no-ip.    15426                 :UNC           0 :         heap_freetuple(tuple);
                              15427                 :              0 :         table_close(pg_class, RowExclusiveLock);
                              15428                 :              0 :         return;
                              15429                 :                :     }
                              15430                 :                : 
   20 alvherre@alvh.no-ip.    15431                 :GNC          22 :     CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
                              15432                 :                : 
                              15433                 :                :     /*
                              15434                 :                :      * Update the dependency on the new access method.  No dependency is added
                              15435                 :                :      * if the new access method is InvalidOid (default case).  Be very careful
                              15436                 :                :      * that this has to compare the previous value stored in pg_class with the
                              15437                 :                :      * new one.
                              15438                 :                :      */
                              15439   [ +  +  +  - ]:             22 :     if (!OidIsValid(oldAccessMethodId) && OidIsValid(rd_rel->relam))
                              15440                 :             10 :     {
                              15441                 :                :         ObjectAddress relobj,
                              15442                 :                :                     referenced;
                              15443                 :                : 
                              15444                 :                :         /*
                              15445                 :                :          * New access method is defined and there was no dependency
                              15446                 :                :          * previously, so record a new one.
                              15447                 :                :          */
                              15448                 :             10 :         ObjectAddressSet(relobj, RelationRelationId, reloid);
                              15449                 :             10 :         ObjectAddressSet(referenced, AccessMethodRelationId, rd_rel->relam);
                              15450                 :             10 :         recordDependencyOn(&relobj, &referenced, DEPENDENCY_NORMAL);
                              15451                 :                :     }
                              15452         [ +  - ]:             12 :     else if (OidIsValid(oldAccessMethodId) &&
                              15453         [ +  + ]:             12 :              !OidIsValid(rd_rel->relam))
                              15454                 :                :     {
                              15455                 :                :         /*
                              15456                 :                :          * There was an access method defined, and no new one, so just remove
                              15457                 :                :          * the existing dependency.
                              15458                 :                :          */
                              15459                 :              6 :         deleteDependencyRecordsForClass(RelationRelationId, reloid,
                              15460                 :                :                                         AccessMethodRelationId,
                              15461                 :                :                                         DEPENDENCY_NORMAL);
                              15462                 :                :     }
                              15463                 :                :     else
                              15464                 :                :     {
                              15465   [ +  -  -  + ]:              6 :         Assert(OidIsValid(oldAccessMethodId) &&
                              15466                 :                :                OidIsValid(rd_rel->relam));
                              15467                 :                : 
                              15468                 :                :         /* Both are valid, so update the dependency */
                              15469                 :              6 :         changeDependencyFor(RelationRelationId, reloid,
                              15470                 :                :                             AccessMethodRelationId,
                              15471                 :                :                             oldAccessMethodId, rd_rel->relam);
                              15472                 :                :     }
                              15473                 :                : 
                              15474                 :                :     /* make the relam and dependency changes visible */
                              15475                 :             22 :     CommandCounterIncrement();
                              15476                 :                : 
                              15477         [ -  + ]:             22 :     InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
                              15478                 :                : 
                              15479                 :             22 :     heap_freetuple(tuple);
                              15480                 :             22 :     table_close(pg_class, RowExclusiveLock);
                              15481                 :                : }
                              15482                 :                : 
                              15483                 :                : /*
                              15484                 :                :  * ALTER TABLE SET TABLESPACE
                              15485                 :                :  */
                              15486                 :                : static void
 2357 peter_e@gmx.net         15487                 :CBC          79 : ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
                              15488                 :                : {
                              15489                 :                :     Oid         tablespaceId;
                              15490                 :                : 
                              15491                 :                :     /* Check that the tablespace exists */
 5001 rhaas@postgresql.org    15492                 :             79 :     tablespaceId = get_tablespace_oid(tablespacename, false);
                              15493                 :                : 
                              15494                 :                :     /* Check permissions except when moving to database's default */
 3739 sfrost@snowman.net      15495   [ +  -  +  + ]:             79 :     if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
                              15496                 :                :     {
                              15497                 :                :         AclResult   aclresult;
                              15498                 :                : 
  518 peter@eisentraut.org    15499                 :             33 :         aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(), ACL_CREATE);
 3739 sfrost@snowman.net      15500         [ -  + ]:             33 :         if (aclresult != ACLCHECK_OK)
 2325 peter_e@gmx.net         15501                 :UBC           0 :             aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
                              15502                 :                :     }
                              15503                 :                : 
                              15504                 :                :     /* Save info for Phase 3 to do the real work */
 7217 tgl@sss.pgh.pa.us       15505         [ -  + ]:CBC          79 :     if (OidIsValid(tab->newTableSpace))
 7217 tgl@sss.pgh.pa.us       15506         [ #  # ]:UBC           0 :         ereport(ERROR,
                              15507                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                              15508                 :                :                  errmsg("cannot have multiple SET TABLESPACE subcommands")));
                              15509                 :                : 
 7217 tgl@sss.pgh.pa.us       15510                 :CBC          79 :     tab->newTableSpace = tablespaceId;
                              15511                 :             79 : }
                              15512                 :                : 
                              15513                 :                : /*
                              15514                 :                :  * Set, reset, or replace reloptions.
                              15515                 :                :  */
                              15516                 :                : static void
 4497 rhaas@postgresql.org    15517                 :            467 : ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
                              15518                 :                :                     LOCKMODE lockmode)
                              15519                 :                : {
                              15520                 :                :     Oid         relid;
                              15521                 :                :     Relation    pgclass;
                              15522                 :                :     HeapTuple   tuple;
                              15523                 :                :     HeapTuple   newtuple;
                              15524                 :                :     Datum       datum;
                              15525                 :                :     bool        isnull;
                              15526                 :                :     Datum       newOptions;
                              15527                 :                :     Datum       repl_val[Natts_pg_class];
                              15528                 :                :     bool        repl_null[Natts_pg_class];
                              15529                 :                :     bool        repl_repl[Natts_pg_class];
                              15530                 :                :     static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
                              15531                 :                : 
                              15532   [ +  +  -  + ]:            467 :     if (defList == NIL && operation != AT_ReplaceRelOptions)
 6495 tgl@sss.pgh.pa.us       15533                 :UBC           0 :         return;                 /* nothing to do */
                              15534                 :                : 
 1910 andres@anarazel.de      15535                 :CBC         467 :     pgclass = table_open(RelationRelationId, RowExclusiveLock);
                              15536                 :                : 
                              15537                 :                :     /* Fetch heap tuple */
 6495 tgl@sss.pgh.pa.us       15538                 :            467 :     relid = RelationGetRelid(rel);
 5173 rhaas@postgresql.org    15539                 :            467 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
 6496 bruce@momjian.us        15540         [ -  + ]:            467 :     if (!HeapTupleIsValid(tuple))
 6496 bruce@momjian.us        15541         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
                              15542                 :                : 
 4497 rhaas@postgresql.org    15543         [ +  + ]:CBC         467 :     if (operation == AT_ReplaceRelOptions)
                              15544                 :                :     {
                              15545                 :                :         /*
                              15546                 :                :          * If we're supposed to replace the reloptions list, we just pretend
                              15547                 :                :          * there were none before.
                              15548                 :                :          */
                              15549                 :             97 :         datum = (Datum) 0;
                              15550                 :             97 :         isnull = true;
                              15551                 :                :     }
                              15552                 :                :     else
                              15553                 :                :     {
                              15554                 :                :         /* Get the old reloptions */
                              15555                 :            370 :         datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
                              15556                 :                :                                 &isnull);
                              15557                 :                :     }
                              15558                 :                : 
                              15559                 :                :     /* Generate new proposed reloptions (text array) */
 6495 tgl@sss.pgh.pa.us       15560         [ +  + ]:            467 :     newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
                              15561                 :                :                                      defList, NULL, validnsps, false,
                              15562                 :                :                                      operation == AT_ResetRelOptions);
                              15563                 :                : 
                              15564                 :                :     /* Validate */
 6496 bruce@momjian.us        15565   [ +  +  +  +  :            464 :     switch (rel->rd_rel->relkind)
                                                 - ]
                              15566                 :                :     {
                              15567                 :            256 :         case RELKIND_RELATION:
                              15568                 :                :         case RELKIND_TOASTVALUE:
                              15569                 :                :         case RELKIND_MATVIEW:
    3 akorotkov@postgresql    15570                 :            256 :             (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
 6496 bruce@momjian.us        15571                 :            256 :             break;
 1613 michael@paquier.xyz     15572                 :              3 :         case RELKIND_PARTITIONED_TABLE:
                              15573                 :              3 :             (void) partitioned_table_reloptions(newOptions, true);
 1613 michael@paquier.xyz     15574                 :UBC           0 :             break;
 3562 alvherre@alvh.no-ip.    15575                 :CBC         148 :         case RELKIND_VIEW:
                              15576                 :            148 :             (void) view_reloptions(newOptions, true);
                              15577                 :            139 :             break;
 6496 bruce@momjian.us        15578                 :             57 :         case RELKIND_INDEX:
                              15579                 :                :         case RELKIND_PARTITIONED_INDEX:
 1910 andres@anarazel.de      15580                 :             57 :             (void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
 6496 bruce@momjian.us        15581                 :             46 :             break;
 6496 bruce@momjian.us        15582                 :UBC           0 :         default:
 6495 tgl@sss.pgh.pa.us       15583         [ #  # ]:              0 :             ereport(ERROR,
                              15584                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              15585                 :                :                      errmsg("cannot set options for relation \"%s\"",
                              15586                 :                :                             RelationGetRelationName(rel)),
                              15587                 :                :                      errdetail_relkind_not_supported(rel->rd_rel->relkind)));
                              15588                 :                :             break;
                              15589                 :                :     }
                              15590                 :                : 
                              15591                 :                :     /* Special-case validation of view options */
 3923 sfrost@snowman.net      15592         [ +  + ]:CBC         441 :     if (rel->rd_rel->relkind == RELKIND_VIEW)
                              15593                 :                :     {
                              15594                 :            139 :         Query      *view_query = get_view_query(rel);
                              15595                 :            139 :         List       *view_options = untransformRelOptions(newOptions);
                              15596                 :                :         ListCell   *cell;
                              15597                 :            139 :         bool        check_option = false;
                              15598                 :                : 
                              15599   [ +  +  +  +  :            190 :         foreach(cell, view_options)
                                              +  + ]
                              15600                 :                :         {
                              15601                 :             51 :             DefElem    *defel = (DefElem *) lfirst(cell);
                              15602                 :                : 
 2270 tgl@sss.pgh.pa.us       15603         [ +  + ]:             51 :             if (strcmp(defel->defname, "check_option") == 0)
 3923 sfrost@snowman.net      15604                 :             12 :                 check_option = true;
                              15605                 :                :         }
                              15606                 :                : 
                              15607                 :                :         /*
                              15608                 :                :          * If the check option is specified, look to see if the view is
                              15609                 :                :          * actually auto-updatable or not.
                              15610                 :                :          */
                              15611         [ +  + ]:            139 :         if (check_option)
                              15612                 :                :         {
                              15613                 :                :             const char *view_updatable_error =
  331 tgl@sss.pgh.pa.us       15614                 :             12 :                 view_query_is_auto_updatable(view_query, true);
                              15615                 :                : 
 3923 sfrost@snowman.net      15616         [ -  + ]:             12 :             if (view_updatable_error)
 3923 sfrost@snowman.net      15617         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              15618                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              15619                 :                :                          errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
                              15620                 :                :                          errhint("%s", _(view_updatable_error))));
                              15621                 :                :         }
                              15622                 :                :     }
                              15623                 :                : 
                              15624                 :                :     /*
                              15625                 :                :      * All we need do here is update the pg_class row; the new options will be
                              15626                 :                :      * propagated into relcaches during post-commit cache inval.
                              15627                 :                :      */
 6495 tgl@sss.pgh.pa.us       15628                 :CBC         441 :     memset(repl_val, 0, sizeof(repl_val));
 5642                         15629                 :            441 :     memset(repl_null, false, sizeof(repl_null));
                              15630                 :            441 :     memset(repl_repl, false, sizeof(repl_repl));
                              15631                 :                : 
 6495                         15632         [ +  + ]:            441 :     if (newOptions != (Datum) 0)
                              15633                 :            297 :         repl_val[Anum_pg_class_reloptions - 1] = newOptions;
                              15634                 :                :     else
 5642                         15635                 :            144 :         repl_null[Anum_pg_class_reloptions - 1] = true;
                              15636                 :                : 
                              15637                 :            441 :     repl_repl[Anum_pg_class_reloptions - 1] = true;
                              15638                 :                : 
                              15639                 :            441 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
                              15640                 :                :                                  repl_val, repl_null, repl_repl);
                              15641                 :                : 
 2630 alvherre@alvh.no-ip.    15642                 :            441 :     CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
                              15643                 :                : 
 4046 rhaas@postgresql.org    15644         [ -  + ]:            441 :     InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
                              15645                 :                : 
 6495 tgl@sss.pgh.pa.us       15646                 :            441 :     heap_freetuple(newtuple);
                              15647                 :                : 
 6496 bruce@momjian.us        15648                 :            441 :     ReleaseSysCache(tuple);
                              15649                 :                : 
                              15650                 :                :     /* repeat the whole exercise for the toast table, if there's one */
 5550 alvherre@alvh.no-ip.    15651         [ +  + ]:            441 :     if (OidIsValid(rel->rd_rel->reltoastrelid))
                              15652                 :                :     {
                              15653                 :                :         Relation    toastrel;
                              15654                 :            128 :         Oid         toastid = rel->rd_rel->reltoastrelid;
                              15655                 :                : 
 1910 andres@anarazel.de      15656                 :            128 :         toastrel = table_open(toastid, lockmode);
                              15657                 :                : 
                              15658                 :                :         /* Fetch heap tuple */
 5173 rhaas@postgresql.org    15659                 :            128 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
 5550 alvherre@alvh.no-ip.    15660         [ -  + ]:            128 :         if (!HeapTupleIsValid(tuple))
 5550 alvherre@alvh.no-ip.    15661         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for relation %u", toastid);
                              15662                 :                : 
 4497 rhaas@postgresql.org    15663         [ -  + ]:CBC         128 :         if (operation == AT_ReplaceRelOptions)
                              15664                 :                :         {
                              15665                 :                :             /*
                              15666                 :                :              * If we're supposed to replace the reloptions list, we just
                              15667                 :                :              * pretend there were none before.
                              15668                 :                :              */
 4497 rhaas@postgresql.org    15669                 :UBC           0 :             datum = (Datum) 0;
                              15670                 :              0 :             isnull = true;
                              15671                 :                :         }
                              15672                 :                :         else
                              15673                 :                :         {
                              15674                 :                :             /* Get the old reloptions */
 4497 rhaas@postgresql.org    15675                 :CBC         128 :             datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
                              15676                 :                :                                     &isnull);
                              15677                 :                :         }
                              15678                 :                : 
 5550 alvherre@alvh.no-ip.    15679         [ +  + ]:            128 :         newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
                              15680                 :                :                                          defList, "toast", validnsps, false,
                              15681                 :                :                                          operation == AT_ResetRelOptions);
                              15682                 :                : 
    3 akorotkov@postgresql    15683                 :            128 :         (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
                              15684                 :                : 
 5550 alvherre@alvh.no-ip.    15685                 :            128 :         memset(repl_val, 0, sizeof(repl_val));
                              15686                 :            128 :         memset(repl_null, false, sizeof(repl_null));
                              15687                 :            128 :         memset(repl_repl, false, sizeof(repl_repl));
                              15688                 :                : 
                              15689         [ +  + ]:            128 :         if (newOptions != (Datum) 0)
                              15690                 :             21 :             repl_val[Anum_pg_class_reloptions - 1] = newOptions;
                              15691                 :                :         else
                              15692                 :            107 :             repl_null[Anum_pg_class_reloptions - 1] = true;
                              15693                 :                : 
                              15694                 :            128 :         repl_repl[Anum_pg_class_reloptions - 1] = true;
                              15695                 :                : 
                              15696                 :            128 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
                              15697                 :                :                                      repl_val, repl_null, repl_repl);
                              15698                 :                : 
 2630                         15699                 :            128 :         CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
                              15700                 :                : 
 4046 rhaas@postgresql.org    15701         [ -  + ]:            128 :         InvokeObjectPostAlterHookArg(RelationRelationId,
                              15702                 :                :                                      RelationGetRelid(toastrel), 0,
                              15703                 :                :                                      InvalidOid, true);
                              15704                 :                : 
 5550 alvherre@alvh.no-ip.    15705                 :            128 :         heap_freetuple(newtuple);
                              15706                 :                : 
                              15707                 :            128 :         ReleaseSysCache(tuple);
                              15708                 :                : 
 1910 andres@anarazel.de      15709                 :            128 :         table_close(toastrel, NoLock);
                              15710                 :                :     }
                              15711                 :                : 
                              15712                 :            441 :     table_close(pgclass, RowExclusiveLock);
                              15713                 :                : }
                              15714                 :                : 
                              15715                 :                : /*
                              15716                 :                :  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
                              15717                 :                :  * rewriting to be done, so we just want to copy the data as fast as possible.
                              15718                 :                :  */
                              15719                 :                : static void
 5009 simon@2ndQuadrant.co    15720                 :             81 : ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
                              15721                 :                : {
                              15722                 :                :     Relation    rel;
                              15723                 :                :     Oid         reltoastrelid;
                              15724                 :                :     RelFileNumber newrelfilenumber;
                              15725                 :                :     RelFileLocator newrlocator;
 3937 fujii@postgresql.org    15726                 :             81 :     List       *reltoastidxids = NIL;
                              15727                 :                :     ListCell   *lc;
                              15728                 :                : 
                              15729                 :                :     /*
                              15730                 :                :      * Need lock here in case we are recursing to toast table or index
                              15731                 :                :      */
 5009 simon@2ndQuadrant.co    15732                 :             81 :     rel = relation_open(tableOid, lockmode);
                              15733                 :                : 
                              15734                 :                :     /* Check first if relation can be moved to new tablespace */
 1173 michael@paquier.xyz     15735         [ +  + ]:             81 :     if (!CheckRelationTableSpaceMove(rel, newTableSpace))
                              15736                 :                :     {
 4046 rhaas@postgresql.org    15737         [ -  + ]:              1 :         InvokeObjectPostAlterHook(RelationRelationId,
                              15738                 :                :                                   RelationGetRelid(rel), 0);
 5180 tgl@sss.pgh.pa.us       15739                 :              1 :         relation_close(rel, NoLock);
                              15740                 :              1 :         return;
                              15741                 :                :     }
                              15742                 :                : 
 7217                         15743                 :             80 :     reltoastrelid = rel->rd_rel->reltoastrelid;
                              15744                 :                :     /* Fetch the list of indexes on toast relation if necessary */
 3937 fujii@postgresql.org    15745         [ +  + ]:             80 :     if (OidIsValid(reltoastrelid))
                              15746                 :                :     {
 3631 bruce@momjian.us        15747                 :             10 :         Relation    toastRel = relation_open(reltoastrelid, lockmode);
                              15748                 :                : 
 3937 fujii@postgresql.org    15749                 :             10 :         reltoastidxids = RelationGetIndexList(toastRel);
                              15750                 :             10 :         relation_close(toastRel, lockmode);
                              15751                 :                :     }
                              15752                 :                : 
                              15753                 :                :     /*
                              15754                 :                :      * Relfilenumbers are not unique in databases across tablespaces, so we
                              15755                 :                :      * need to allocate a new one in the new tablespace.
                              15756                 :                :      */
  564 rhaas@postgresql.org    15757                 :             80 :     newrelfilenumber = GetNewRelFileNumber(newTableSpace, NULL,
  648                         15758                 :             80 :                                            rel->rd_rel->relpersistence);
                              15759                 :                : 
                              15760                 :                :     /* Open old and new relation */
                              15761                 :             80 :     newrlocator = rel->rd_locator;
                              15762                 :             80 :     newrlocator.relNumber = newrelfilenumber;
                              15763                 :             80 :     newrlocator.spcOid = newTableSpace;
                              15764                 :                : 
                              15765                 :                :     /* hand off to AM to actually create new rel storage and copy the data */
 1844 andres@anarazel.de      15766         [ +  + ]:             80 :     if (rel->rd_rel->relkind == RELKIND_INDEX)
                              15767                 :                :     {
  648 rhaas@postgresql.org    15768                 :             31 :         index_copy_data(rel, newrlocator);
                              15769                 :                :     }
                              15770                 :                :     else
                              15771                 :                :     {
  863 peter@eisentraut.org    15772   [ +  +  +  +  :             49 :         Assert(RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind));
                                              -  + ]
  648 rhaas@postgresql.org    15773                 :             49 :         table_relation_copy_data(rel, &newrlocator);
                              15774                 :                :     }
                              15775                 :                : 
                              15776                 :                :     /*
                              15777                 :                :      * Update the pg_class row.
                              15778                 :                :      *
                              15779                 :                :      * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
                              15780                 :                :      * executed on pg_class or its indexes (the above copy wouldn't contain
                              15781                 :                :      * the updated pg_class entry), but that's forbidden with
                              15782                 :                :      * CheckRelationTableSpaceMove().
                              15783                 :                :      */
                              15784                 :             80 :     SetRelationTableSpace(rel, newTableSpace, newrelfilenumber);
                              15785                 :                : 
 4046                         15786         [ -  + ]:             80 :     InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
                              15787                 :                : 
  648                         15788                 :             80 :     RelationAssumeNewRelfilelocator(rel);
                              15789                 :                : 
 7217 tgl@sss.pgh.pa.us       15790                 :             80 :     relation_close(rel, NoLock);
                              15791                 :                : 
                              15792                 :                :     /* Make sure the reltablespace change is visible */
                              15793                 :             80 :     CommandCounterIncrement();
                              15794                 :                : 
                              15795                 :                :     /* Move associated toast relation and/or indexes, too */
                              15796         [ +  + ]:             80 :     if (OidIsValid(reltoastrelid))
 5009 simon@2ndQuadrant.co    15797                 :             10 :         ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
 3937 fujii@postgresql.org    15798   [ +  +  +  +  :             90 :     foreach(lc, reltoastidxids)
                                              +  + ]
                              15799                 :             10 :         ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
                              15800                 :                : 
                              15801                 :                :     /* Clean up */
                              15802                 :             80 :     list_free(reltoastidxids);
                              15803                 :                : }
                              15804                 :                : 
                              15805                 :                : /*
                              15806                 :                :  * Special handling of ALTER TABLE SET TABLESPACE for relations with no
                              15807                 :                :  * storage that have an interest in preserving tablespace.
                              15808                 :                :  *
                              15809                 :                :  * Since these have no storage the tablespace can be updated with a simple
                              15810                 :                :  * metadata only operation to update the tablespace.
                              15811                 :                :  */
                              15812                 :                : static void
 1945 alvherre@alvh.no-ip.    15813                 :             18 : ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
                              15814                 :                : {
                              15815                 :                :     /*
                              15816                 :                :      * Shouldn't be called on relations having storage; these are processed in
                              15817                 :                :      * phase 3.
                              15818                 :                :      */
 1927                         15819   [ +  -  +  -  :             18 :     Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
                                     +  -  +  -  -  
                                                 + ]
                              15820                 :                : 
                              15821                 :                :     /* check if relation can be moved to its new tablespace */
 1173 michael@paquier.xyz     15822         [ -  + ]:             18 :     if (!CheckRelationTableSpaceMove(rel, newTableSpace))
                              15823                 :                :     {
 1173 michael@paquier.xyz     15824         [ #  # ]:UBC           0 :         InvokeObjectPostAlterHook(RelationRelationId,
                              15825                 :                :                                   RelationGetRelid(rel),
                              15826                 :                :                                   0);
 1989 alvherre@alvh.no-ip.    15827                 :              0 :         return;
                              15828                 :                :     }
                              15829                 :                : 
                              15830                 :                :     /* Update can be done, so change reltablespace */
 1173 michael@paquier.xyz     15831                 :CBC          15 :     SetRelationTableSpace(rel, newTableSpace, InvalidOid);
                              15832                 :                : 
                              15833         [ -  + ]:             15 :     InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
                              15834                 :                : 
                              15835                 :                :     /* Make sure the reltablespace change is visible */
 1989 alvherre@alvh.no-ip.    15836                 :             15 :     CommandCounterIncrement();
                              15837                 :                : }
                              15838                 :                : 
                              15839                 :                : /*
                              15840                 :                :  * Alter Table ALL ... SET TABLESPACE
                              15841                 :                :  *
                              15842                 :                :  * Allows a user to move all objects of some type in a given tablespace in the
                              15843                 :                :  * current database to another tablespace.  Objects can be chosen based on the
                              15844                 :                :  * owner of the object also, to allow users to move only their objects.
                              15845                 :                :  * The user must have CREATE rights on the new tablespace, as usual.   The main
                              15846                 :                :  * permissions handling is done by the lower-level table move function.
                              15847                 :                :  *
                              15848                 :                :  * All to-be-moved objects are locked first. If NOWAIT is specified and the
                              15849                 :                :  * lock can't be acquired then we ereport(ERROR).
                              15850                 :                :  */
                              15851                 :                : Oid
 3524 sfrost@snowman.net      15852                 :             15 : AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
                              15853                 :                : {
                              15854                 :             15 :     List       *relations = NIL;
                              15855                 :                :     ListCell   *l;
                              15856                 :                :     ScanKeyData key[1];
                              15857                 :                :     Relation    rel;
                              15858                 :                :     TableScanDesc scan;
                              15859                 :                :     HeapTuple   tuple;
                              15860                 :                :     Oid         orig_tablespaceoid;
                              15861                 :                :     Oid         new_tablespaceoid;
 3324 alvherre@alvh.no-ip.    15862                 :             15 :     List       *role_oids = roleSpecsToIds(stmt->roles);
                              15863                 :                : 
                              15864                 :                :     /* Ensure we were not asked to move something we can't */
 3524 sfrost@snowman.net      15865   [ +  +  +  + ]:             15 :     if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
                              15866         [ -  + ]:              6 :         stmt->objtype != OBJECT_MATVIEW)
 3524 sfrost@snowman.net      15867         [ #  # ]:UBC           0 :         ereport(ERROR,
                              15868                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                              15869                 :                :                  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
                              15870                 :                : 
                              15871                 :                :     /* Get the orig and new tablespace OIDs */
 3524 sfrost@snowman.net      15872                 :CBC          15 :     orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
                              15873                 :             15 :     new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
                              15874                 :                : 
                              15875                 :                :     /* Can't move shared relations in to or out of pg_global */
                              15876                 :                :     /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
                              15877   [ +  -  -  + ]:             15 :     if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
                              15878                 :                :         new_tablespaceoid == GLOBALTABLESPACE_OID)
 3524 sfrost@snowman.net      15879         [ #  # ]:UBC           0 :         ereport(ERROR,
                              15880                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                              15881                 :                :                  errmsg("cannot move relations in to or out of pg_global tablespace")));
                              15882                 :                : 
                              15883                 :                :     /*
                              15884                 :                :      * Must have CREATE rights on the new tablespace, unless it is the
                              15885                 :                :      * database default tablespace (which all users implicitly have CREATE
                              15886                 :                :      * rights on).
                              15887                 :                :      */
 3524 sfrost@snowman.net      15888   [ +  -  -  + ]:CBC          15 :     if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
                              15889                 :                :     {
                              15890                 :                :         AclResult   aclresult;
                              15891                 :                : 
  518 peter@eisentraut.org    15892                 :UBC           0 :         aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
                              15893                 :                :                                     ACL_CREATE);
 3524 sfrost@snowman.net      15894         [ #  # ]:              0 :         if (aclresult != ACLCHECK_OK)
 2325 peter_e@gmx.net         15895                 :              0 :             aclcheck_error(aclresult, OBJECT_TABLESPACE,
 3524 sfrost@snowman.net      15896                 :              0 :                            get_tablespace_name(new_tablespaceoid));
                              15897                 :                :     }
                              15898                 :                : 
                              15899                 :                :     /*
                              15900                 :                :      * Now that the checks are done, check if we should set either to
                              15901                 :                :      * InvalidOid because it is our database's default tablespace.
                              15902                 :                :      */
 3524 sfrost@snowman.net      15903         [ -  + ]:CBC          15 :     if (orig_tablespaceoid == MyDatabaseTableSpace)
 3524 sfrost@snowman.net      15904                 :UBC           0 :         orig_tablespaceoid = InvalidOid;
                              15905                 :                : 
 3524 sfrost@snowman.net      15906         [ +  - ]:CBC          15 :     if (new_tablespaceoid == MyDatabaseTableSpace)
                              15907                 :             15 :         new_tablespaceoid = InvalidOid;
                              15908                 :                : 
                              15909                 :                :     /* no-op */
                              15910         [ -  + ]:             15 :     if (orig_tablespaceoid == new_tablespaceoid)
 3524 sfrost@snowman.net      15911                 :UBC           0 :         return new_tablespaceoid;
                              15912                 :                : 
                              15913                 :                :     /*
                              15914                 :                :      * Walk the list of objects in the tablespace and move them. This will
                              15915                 :                :      * only find objects in our database, of course.
                              15916                 :                :      */
 3524 sfrost@snowman.net      15917                 :CBC          15 :     ScanKeyInit(&key[0],
                              15918                 :                :                 Anum_pg_class_reltablespace,
                              15919                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              15920                 :                :                 ObjectIdGetDatum(orig_tablespaceoid));
                              15921                 :                : 
 1910 andres@anarazel.de      15922                 :             15 :     rel = table_open(RelationRelationId, AccessShareLock);
 1861                         15923                 :             15 :     scan = table_beginscan_catalog(rel, 1, key);
 3524 sfrost@snowman.net      15924         [ +  + ]:             66 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
                              15925                 :                :     {
 1972 andres@anarazel.de      15926                 :             51 :         Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
                              15927                 :             51 :         Oid         relOid = relForm->oid;
                              15928                 :                : 
                              15929                 :                :         /*
                              15930                 :                :          * Do not move objects in pg_catalog as part of this, if an admin
                              15931                 :                :          * really wishes to do so, they can issue the individual ALTER
                              15932                 :                :          * commands directly.
                              15933                 :                :          *
                              15934                 :                :          * Also, explicitly avoid any shared tables, temp tables, or TOAST
                              15935                 :                :          * (TOAST will be moved with the main table).
                              15936                 :                :          */
 1803 tgl@sss.pgh.pa.us       15937         [ +  - ]:             51 :         if (IsCatalogNamespace(relForm->relnamespace) ||
                              15938   [ +  -  +  - ]:            102 :             relForm->relisshared ||
 3524 sfrost@snowman.net      15939         [ -  + ]:            102 :             isAnyTempNamespace(relForm->relnamespace) ||
 1803 tgl@sss.pgh.pa.us       15940                 :             51 :             IsToastNamespace(relForm->relnamespace))
 3524 sfrost@snowman.net      15941                 :UBC           0 :             continue;
                              15942                 :                : 
                              15943                 :                :         /* Only move the object type requested */
 3524 sfrost@snowman.net      15944         [ +  + ]:CBC          51 :         if ((stmt->objtype == OBJECT_TABLE &&
 2685 rhaas@postgresql.org    15945         [ +  + ]:             30 :              relForm->relkind != RELKIND_RELATION &&
                              15946         [ -  + ]:             18 :              relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
 3524 sfrost@snowman.net      15947         [ +  + ]:             33 :             (stmt->objtype == OBJECT_INDEX &&
 2277 alvherre@alvh.no-ip.    15948         [ +  + ]:             18 :              relForm->relkind != RELKIND_INDEX &&
                              15949         [ -  + ]:              3 :              relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
 3524 sfrost@snowman.net      15950         [ +  + ]:             30 :             (stmt->objtype == OBJECT_MATVIEW &&
                              15951         [ -  + ]:              3 :              relForm->relkind != RELKIND_MATVIEW))
                              15952                 :             21 :             continue;
                              15953                 :                : 
                              15954                 :                :         /* Check if we are only moving objects owned by certain roles */
                              15955   [ -  +  -  - ]:             30 :         if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
 3524 sfrost@snowman.net      15956                 :UBC           0 :             continue;
                              15957                 :                : 
                              15958                 :                :         /*
                              15959                 :                :          * Handle permissions-checking here since we are locking the tables
                              15960                 :                :          * and also to avoid doing a bunch of work only to fail part-way. Note
                              15961                 :                :          * that permissions will also be checked by AlterTableInternal().
                              15962                 :                :          *
                              15963                 :                :          * Caller must be considered an owner on the table to move it.
                              15964                 :                :          */
  518 peter@eisentraut.org    15965         [ -  + ]:CBC          30 :         if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
 2325 peter_e@gmx.net         15966                 :UBC           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)),
 3524 sfrost@snowman.net      15967                 :              0 :                            NameStr(relForm->relname));
                              15968                 :                : 
 3524 sfrost@snowman.net      15969         [ -  + ]:CBC          30 :         if (stmt->nowait &&
 3524 sfrost@snowman.net      15970         [ #  # ]:UBC           0 :             !ConditionalLockRelationOid(relOid, AccessExclusiveLock))
                              15971         [ #  # ]:              0 :             ereport(ERROR,
                              15972                 :                :                     (errcode(ERRCODE_OBJECT_IN_USE),
                              15973                 :                :                      errmsg("aborting because lock on relation \"%s.%s\" is not available",
                              15974                 :                :                             get_namespace_name(relForm->relnamespace),
                              15975                 :                :                             NameStr(relForm->relname))));
                              15976                 :                :         else
 3524 sfrost@snowman.net      15977                 :CBC          30 :             LockRelationOid(relOid, AccessExclusiveLock);
                              15978                 :                : 
                              15979                 :                :         /* Add to our list of objects to move */
                              15980                 :             30 :         relations = lappend_oid(relations, relOid);
                              15981                 :                :     }
                              15982                 :                : 
 1861 andres@anarazel.de      15983                 :             15 :     table_endscan(scan);
 1910                         15984                 :             15 :     table_close(rel, AccessShareLock);
                              15985                 :                : 
 3524 sfrost@snowman.net      15986         [ +  + ]:             15 :     if (relations == NIL)
                              15987   [ +  -  +  - ]:              6 :         ereport(NOTICE,
                              15988                 :                :                 (errcode(ERRCODE_NO_DATA_FOUND),
                              15989                 :                :                  errmsg("no matching relations in tablespace \"%s\" found",
                              15990                 :                :                         orig_tablespaceoid == InvalidOid ? "(database default)" :
                              15991                 :                :                         get_tablespace_name(orig_tablespaceoid))));
                              15992                 :                : 
                              15993                 :                :     /* Everything is locked, loop through and move all of the relations. */
                              15994   [ +  +  +  +  :             45 :     foreach(l, relations)
                                              +  + ]
                              15995                 :                :     {
                              15996                 :             30 :         List       *cmds = NIL;
                              15997                 :             30 :         AlterTableCmd *cmd = makeNode(AlterTableCmd);
                              15998                 :                : 
                              15999                 :             30 :         cmd->subtype = AT_SetTableSpace;
                              16000                 :             30 :         cmd->name = stmt->new_tablespacename;
                              16001                 :                : 
                              16002                 :             30 :         cmds = lappend(cmds, cmd);
                              16003                 :                : 
 3261 alvherre@alvh.no-ip.    16004                 :             30 :         EventTriggerAlterTableStart((Node *) stmt);
                              16005                 :                :         /* OID is set by AlterTableInternal */
 3524 sfrost@snowman.net      16006                 :             30 :         AlterTableInternal(lfirst_oid(l), cmds, false);
 3261 alvherre@alvh.no-ip.    16007                 :             30 :         EventTriggerAlterTableEnd();
                              16008                 :                :     }
                              16009                 :                : 
 3524 sfrost@snowman.net      16010                 :             15 :     return new_tablespaceoid;
                              16011                 :                : }
                              16012                 :                : 
                              16013                 :                : static void
  648 rhaas@postgresql.org    16014                 :             31 : index_copy_data(Relation rel, RelFileLocator newrlocator)
                              16015                 :                : {
                              16016                 :                :     SMgrRelation dstrel;
                              16017                 :                : 
                              16018                 :                :     /*
                              16019                 :                :      * Since we copy the file directly without looking at the shared buffers,
                              16020                 :                :      * we'd better first flush out any pages of the source relation that are
                              16021                 :                :      * in shared buffers.  We assume no new changes will be made while we are
                              16022                 :                :      * holding exclusive lock on the rel.
                              16023                 :                :      */
 1812 andres@anarazel.de      16024                 :             31 :     FlushRelationBuffers(rel);
                              16025                 :                : 
                              16026                 :                :     /*
                              16027                 :                :      * Create and copy all forks of the relation, and schedule unlinking of
                              16028                 :                :      * old physical files.
                              16029                 :                :      *
                              16030                 :                :      * NOTE: any conflict in relfilenumber value will be caught in
                              16031                 :                :      * RelationCreateStorage().
                              16032                 :                :      */
   62 heikki.linnakangas@i    16033                 :GNC          31 :     dstrel = RelationCreateStorage(newrlocator, rel->rd_rel->relpersistence, true);
                              16034                 :                : 
                              16035                 :                :     /* copy main fork */
 1007 tgl@sss.pgh.pa.us       16036                 :CBC          31 :     RelationCopyStorage(RelationGetSmgr(rel), dstrel, MAIN_FORKNUM,
 1844 andres@anarazel.de      16037                 :             31 :                         rel->rd_rel->relpersistence);
                              16038                 :                : 
                              16039                 :                :     /* copy those extra forks that exist */
                              16040                 :             31 :     for (ForkNumber forkNum = MAIN_FORKNUM + 1;
                              16041         [ +  + ]:            124 :          forkNum <= MAX_FORKNUM; forkNum++)
                              16042                 :                :     {
 1007 tgl@sss.pgh.pa.us       16043         [ -  + ]:             93 :         if (smgrexists(RelationGetSmgr(rel), forkNum))
                              16044                 :                :         {
 1844 andres@anarazel.de      16045                 :UBC           0 :             smgrcreate(dstrel, forkNum, false);
                              16046                 :                : 
                              16047                 :                :             /*
                              16048                 :                :              * WAL log creation if the relation is persistent, or this is the
                              16049                 :                :              * init fork of an unlogged relation.
                              16050                 :                :              */
 1119 bruce@momjian.us        16051         [ #  # ]:              0 :             if (RelationIsPermanent(rel) ||
 1844 andres@anarazel.de      16052   [ #  #  #  # ]:              0 :                 (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
                              16053                 :                :                  forkNum == INIT_FORKNUM))
  648 rhaas@postgresql.org    16054                 :              0 :                 log_smgrcreate(&newrlocator, forkNum);
 1007 tgl@sss.pgh.pa.us       16055                 :              0 :             RelationCopyStorage(RelationGetSmgr(rel), dstrel, forkNum,
 1844 andres@anarazel.de      16056                 :              0 :                                 rel->rd_rel->relpersistence);
                              16057                 :                :         }
                              16058                 :                :     }
                              16059                 :                : 
                              16060                 :                :     /* drop old relation, and close new one */
 1844 andres@anarazel.de      16061                 :CBC          31 :     RelationDropStorage(rel);
                              16062                 :             31 :     smgrclose(dstrel);
 7217 tgl@sss.pgh.pa.us       16063                 :             31 : }
                              16064                 :                : 
                              16065                 :                : /*
                              16066                 :                :  * ALTER TABLE ENABLE/DISABLE TRIGGER
                              16067                 :                :  *
                              16068                 :                :  * We just pass this off to trigger.c.
                              16069                 :                :  */
                              16070                 :                : static void
 2357 peter_e@gmx.net         16071                 :            170 : ATExecEnableDisableTrigger(Relation rel, const char *trigname,
                              16072                 :                :                            char fires_when, bool skip_system, bool recurse,
                              16073                 :                :                            LOCKMODE lockmode)
                              16074                 :                : {
  407 tgl@sss.pgh.pa.us       16075                 :            170 :     EnableDisableTrigger(rel, trigname, InvalidOid,
                              16076                 :                :                          fires_when, skip_system, recurse,
                              16077                 :                :                          lockmode);
                              16078                 :                : 
  241 michael@paquier.xyz     16079         [ +  + ]:GNC         170 :     InvokeObjectPostAlterHook(RelationRelationId,
                              16080                 :                :                               RelationGetRelid(rel), 0);
 6236 JanWieck@Yahoo.com      16081                 :CBC         170 : }
                              16082                 :                : 
                              16083                 :                : /*
                              16084                 :                :  * ALTER TABLE ENABLE/DISABLE RULE
                              16085                 :                :  *
                              16086                 :                :  * We just pass this off to rewriteDefine.c.
                              16087                 :                :  */
                              16088                 :                : static void
 2357 peter_e@gmx.net         16089                 :             23 : ATExecEnableDisableRule(Relation rel, const char *rulename,
                              16090                 :                :                         char fires_when, LOCKMODE lockmode)
                              16091                 :                : {
 2599                         16092                 :             23 :     EnableDisableRule(rel, rulename, fires_when);
                              16093                 :                : 
  241 michael@paquier.xyz     16094         [ +  + ]:GNC          23 :     InvokeObjectPostAlterHook(RelationRelationId,
                              16095                 :                :                               RelationGetRelid(rel), 0);
 6809 tgl@sss.pgh.pa.us       16096                 :CBC          23 : }
                              16097                 :                : 
                              16098                 :                : /*
                              16099                 :                :  * ALTER TABLE INHERIT
                              16100                 :                :  *
                              16101                 :                :  * Add a parent to the child's parents. This verifies that all the columns and
                              16102                 :                :  * check constraints of the parent appear in the child and that they have the
                              16103                 :                :  * same data types and expressions.
                              16104                 :                :  */
                              16105                 :                : static void
 5014 peter_e@gmx.net         16106                 :            163 : ATPrepAddInherit(Relation child_rel)
                              16107                 :                : {
                              16108         [ +  + ]:            163 :     if (child_rel->rd_rel->reloftype)
                              16109         [ +  - ]:              3 :         ereport(ERROR,
                              16110                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16111                 :                :                  errmsg("cannot change inheritance of typed table")));
                              16112                 :                : 
 2685 rhaas@postgresql.org    16113         [ +  + ]:            160 :     if (child_rel->rd_rel->relispartition)
                              16114         [ +  - ]:              3 :         ereport(ERROR,
                              16115                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16116                 :                :                  errmsg("cannot change inheritance of a partition")));
                              16117                 :                : 
                              16118         [ +  + ]:            157 :     if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              16119         [ +  - ]:              3 :         ereport(ERROR,
                              16120                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16121                 :                :                  errmsg("cannot change inheritance of partitioned table")));
 5014 peter_e@gmx.net         16122                 :            154 : }
                              16123                 :                : 
                              16124                 :                : /*
                              16125                 :                :  * Return the address of the new parent relation.
                              16126                 :                :  */
                              16127                 :                : static ObjectAddress
 5009 simon@2ndQuadrant.co    16128                 :            154 : ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
                              16129                 :                : {
                              16130                 :                :     Relation    parent_rel;
                              16131                 :                :     List       *children;
                              16132                 :                :     ObjectAddress address;
                              16133                 :                :     const char *trigger_name;
                              16134                 :                : 
                              16135                 :                :     /*
                              16136                 :                :      * A self-exclusive lock is needed here.  See the similar case in
                              16137                 :                :      * MergeAttributes() for a full explanation.
                              16138                 :                :      */
 1910 andres@anarazel.de      16139                 :            154 :     parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
                              16140                 :                : 
                              16141                 :                :     /*
                              16142                 :                :      * Must be owner of both parent and child -- child was checked by
                              16143                 :                :      * ATSimplePermissions call in ATPrepCmd
                              16144                 :                :      */
 1011 peter@eisentraut.org    16145                 :            154 :     ATSimplePermissions(AT_AddInherit, parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE);
                              16146                 :                : 
                              16147                 :                :     /* Permanent rels cannot inherit from temporary ones */
 4136 tgl@sss.pgh.pa.us       16148         [ +  + ]:            154 :     if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              16149         [ -  + ]:              3 :         child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
 6496 bruce@momjian.us        16150         [ #  # ]:UBC           0 :         ereport(ERROR,
                              16151                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16152                 :                :                  errmsg("cannot inherit from temporary relation \"%s\"",
                              16153                 :                :                         RelationGetRelationName(parent_rel))));
                              16154                 :                : 
                              16155                 :                :     /* If parent rel is temp, it must belong to this session */
 4136 tgl@sss.pgh.pa.us       16156         [ +  + ]:CBC         154 :     if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              16157         [ -  + ]:              3 :         !parent_rel->rd_islocaltemp)
 4136 tgl@sss.pgh.pa.us       16158         [ #  # ]:UBC           0 :         ereport(ERROR,
                              16159                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16160                 :                :                  errmsg("cannot inherit from temporary relation of another session")));
                              16161                 :                : 
                              16162                 :                :     /* Ditto for the child */
 4136 tgl@sss.pgh.pa.us       16163         [ +  + ]:CBC         154 :     if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              16164         [ -  + ]:              3 :         !child_rel->rd_islocaltemp)
 4136 tgl@sss.pgh.pa.us       16165         [ #  # ]:UBC           0 :         ereport(ERROR,
                              16166                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16167                 :                :                  errmsg("cannot inherit to temporary relation of another session")));
                              16168                 :                : 
                              16169                 :                :     /* Prevent partitioned tables from becoming inheritance parents */
 2685 rhaas@postgresql.org    16170         [ +  + ]:CBC         154 :     if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              16171         [ +  - ]:              3 :         ereport(ERROR,
                              16172                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16173                 :                :                  errmsg("cannot inherit from partitioned table \"%s\"",
                              16174                 :                :                         parent->relname)));
                              16175                 :                : 
                              16176                 :                :     /* Likewise for partitions */
                              16177         [ +  + ]:            151 :     if (parent_rel->rd_rel->relispartition)
                              16178         [ +  - ]:              3 :         ereport(ERROR,
                              16179                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16180                 :                :                  errmsg("cannot inherit from a partition")));
                              16181                 :                : 
                              16182                 :                :     /*
                              16183                 :                :      * Prevent circularity by seeing if proposed parent inherits from child.
                              16184                 :                :      * (In particular, this disallows making a rel inherit from itself.)
                              16185                 :                :      *
                              16186                 :                :      * This is not completely bulletproof because of race conditions: in
                              16187                 :                :      * multi-level inheritance trees, someone else could concurrently be
                              16188                 :                :      * making another inheritance link that closes the loop but does not join
                              16189                 :                :      * either of the rels we have locked.  Preventing that seems to require
                              16190                 :                :      * exclusive locks on the entire inheritance tree, which is a cure worse
                              16191                 :                :      * than the disease.  find_all_inheritors() will cope with circularity
                              16192                 :                :      * anyway, so don't sweat it too much.
                              16193                 :                :      *
                              16194                 :                :      * We use weakest lock we can on child's children, namely AccessShareLock.
                              16195                 :                :      */
                              16196                 :            148 :     children = find_all_inheritors(RelationGetRelid(child_rel),
                              16197                 :                :                                    AccessShareLock, NULL);
                              16198                 :                : 
                              16199         [ +  + ]:            148 :     if (list_member_oid(children, RelationGetRelid(parent_rel)))
                              16200         [ +  - ]:              6 :         ereport(ERROR,
                              16201                 :                :                 (errcode(ERRCODE_DUPLICATE_TABLE),
                              16202                 :                :                  errmsg("circular inheritance not allowed"),
                              16203                 :                :                  errdetail("\"%s\" is already a child of \"%s\".",
                              16204                 :                :                            parent->relname,
                              16205                 :                :                            RelationGetRelationName(child_rel))));
                              16206                 :                : 
                              16207                 :                :     /*
                              16208                 :                :      * If child_rel has row-level triggers with transition tables, we
                              16209                 :                :      * currently don't allow it to become an inheritance child.  See also
                              16210                 :                :      * prohibitions in ATExecAttachPartition() and CreateTrigger().
                              16211                 :                :      */
 2482 rhodiumtoad@postgres    16212                 :            142 :     trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
                              16213         [ +  + ]:            142 :     if (trigger_name != NULL)
                              16214         [ +  - ]:              3 :         ereport(ERROR,
                              16215                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              16216                 :                :                  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
                              16217                 :                :                         trigger_name, RelationGetRelationName(child_rel)),
                              16218                 :                :                  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
                              16219                 :                : 
                              16220                 :                :     /* OK to create inheritance */
   89 peter@eisentraut.org    16221                 :GNC         139 :     CreateInheritance(child_rel, parent_rel, false);
                              16222                 :                : 
                              16223                 :                :     /*
                              16224                 :                :      * If parent_rel has a primary key, then child_rel has not-null
                              16225                 :                :      * constraints that make these columns as non nullable.  Make those
                              16226                 :                :      * constraints as inherited.
                              16227                 :                :      */
  233 alvherre@alvh.no-ip.    16228                 :            115 :     ATInheritAdjustNotNulls(parent_rel, child_rel, 1);
                              16229                 :                : 
 2685 rhaas@postgresql.org    16230                 :CBC         112 :     ObjectAddressSet(address, RelationRelationId,
                              16231                 :                :                      RelationGetRelid(parent_rel));
                              16232                 :                : 
                              16233                 :                :     /* keep our lock on the parent relation until commit */
 1910 andres@anarazel.de      16234                 :            112 :     table_close(parent_rel, NoLock);
                              16235                 :                : 
 2685 rhaas@postgresql.org    16236                 :            112 :     return address;
                              16237                 :                : }
                              16238                 :                : 
                              16239                 :                : /*
                              16240                 :                :  * CreateInheritance
                              16241                 :                :  *      Catalog manipulation portion of creating inheritance between a child
                              16242                 :                :  *      table and a parent table.
                              16243                 :                :  *
                              16244                 :                :  * Common to ATExecAddInherit() and ATExecAttachPartition().
                              16245                 :                :  */
                              16246                 :                : static void
   89 peter@eisentraut.org    16247                 :GNC        1362 : CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
                              16248                 :                : {
                              16249                 :                :     Relation    catalogRelation;
                              16250                 :                :     SysScanDesc scan;
                              16251                 :                :     ScanKeyData key;
                              16252                 :                :     HeapTuple   inheritsTuple;
                              16253                 :                :     int32       inhseqno;
                              16254                 :                : 
                              16255                 :                :     /* Note: get RowExclusiveLock because we will write pg_inherits below. */
 1910 andres@anarazel.de      16256                 :CBC        1362 :     catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
                              16257                 :                : 
                              16258                 :                :     /*
                              16259                 :                :      * Check for duplicates in the list of parents, and determine the highest
                              16260                 :                :      * inhseqno already present; we'll use the next one for the new parent.
                              16261                 :                :      * Also, if proposed child is a partition, it cannot already be
                              16262                 :                :      * inheriting.
                              16263                 :                :      *
                              16264                 :                :      * Note: we do not reject the case where the child already inherits from
                              16265                 :                :      * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
                              16266                 :                :      */
 2685 rhaas@postgresql.org    16267                 :           1362 :     ScanKeyInit(&key,
                              16268                 :                :                 Anum_pg_inherits_inhrelid,
                              16269                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              16270                 :                :                 ObjectIdGetDatum(RelationGetRelid(child_rel)));
 6496 bruce@momjian.us        16271                 :           1362 :     scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
                              16272                 :                :                               true, NULL, 1, &key);
                              16273                 :                : 
                              16274                 :                :     /* inhseqno sequences start at 1 */
      neilc@samurai.com       16275                 :           1362 :     inhseqno = 0;
      bruce@momjian.us        16276         [ +  + ]:           1385 :     while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
                              16277                 :                :     {
                              16278                 :             26 :         Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
                              16279                 :                : 
      neilc@samurai.com       16280         [ +  + ]:             26 :         if (inh->inhparent == RelationGetRelid(parent_rel))
      bruce@momjian.us        16281         [ +  - ]:              3 :             ereport(ERROR,
                              16282                 :                :                     (errcode(ERRCODE_DUPLICATE_TABLE),
                              16283                 :                :                      errmsg("relation \"%s\" would be inherited from more than once",
                              16284                 :                :                             RelationGetRelationName(parent_rel))));
                              16285                 :                : 
 6393 tgl@sss.pgh.pa.us       16286         [ +  - ]:             23 :         if (inh->inhseqno > inhseqno)
 6496 bruce@momjian.us        16287                 :             23 :             inhseqno = inh->inhseqno;
                              16288                 :                :     }
                              16289                 :           1359 :     systable_endscan(scan);
                              16290                 :                : 
                              16291                 :                :     /* Match up the columns and bump attinhcount as needed */
   89 peter@eisentraut.org    16292                 :GNC        1359 :     MergeAttributesIntoExisting(child_rel, parent_rel, ispartition);
                              16293                 :                : 
                              16294                 :                :     /* Match up the constraints and bump coninhcount as needed */
 6496 neilc@samurai.com       16295                 :CBC        1320 :     MergeConstraintsIntoExisting(child_rel, parent_rel);
                              16296                 :                : 
                              16297                 :                :     /*
                              16298                 :                :      * OK, it looks valid.  Make the catalog entries that show inheritance.
                              16299                 :                :      */
                              16300                 :           1302 :     StoreCatalogInheritance1(RelationGetRelid(child_rel),
                              16301                 :                :                              RelationGetRelid(parent_rel),
                              16302                 :                :                              inhseqno + 1,
                              16303                 :                :                              catalogRelation,
 2596 simon@2ndQuadrant.co    16304                 :           1302 :                              parent_rel->rd_rel->relkind ==
                              16305                 :                :                              RELKIND_PARTITIONED_TABLE);
                              16306                 :                : 
                              16307                 :                :     /* Now we're done with pg_inherits */
 1910 andres@anarazel.de      16308                 :           1302 :     table_close(catalogRelation, RowExclusiveLock);
 6496 bruce@momjian.us        16309                 :           1302 : }
                              16310                 :                : 
                              16311                 :                : /*
                              16312                 :                :  * Obtain the source-text form of the constraint expression for a check
                              16313                 :                :  * constraint, given its pg_constraint tuple
                              16314                 :                :  */
                              16315                 :                : static char *
 6393 tgl@sss.pgh.pa.us       16316                 :             84 : decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
                              16317                 :                : {
                              16318                 :                :     Form_pg_constraint con;
                              16319                 :                :     bool        isnull;
                              16320                 :                :     Datum       attr;
                              16321                 :                :     Datum       expr;
                              16322                 :                : 
                              16323                 :             84 :     con = (Form_pg_constraint) GETSTRUCT(contup);
                              16324                 :             84 :     attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
                              16325         [ -  + ]:             84 :     if (isnull)
 1972 andres@anarazel.de      16326         [ #  # ]:UBC           0 :         elog(ERROR, "null conbin for constraint %u", con->oid);
                              16327                 :                : 
 6393 tgl@sss.pgh.pa.us       16328                 :CBC          84 :     expr = DirectFunctionCall2(pg_get_expr, attr,
                              16329                 :                :                                ObjectIdGetDatum(con->conrelid));
 5864                         16330                 :             84 :     return TextDatumGetCString(expr);
                              16331                 :                : }
                              16332                 :                : 
                              16333                 :                : /*
                              16334                 :                :  * Determine whether two check constraints are functionally equivalent
                              16335                 :                :  *
                              16336                 :                :  * The test we apply is to see whether they reverse-compile to the same
                              16337                 :                :  * source string.  This insulates us from issues like whether attributes
                              16338                 :                :  * have the same physical column numbers in parent and child relations.
                              16339                 :                :  */
                              16340                 :                : static bool
 5819                         16341                 :             42 : constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
                              16342                 :                : {
                              16343                 :             42 :     Form_pg_constraint acon = (Form_pg_constraint) GETSTRUCT(a);
                              16344                 :             42 :     Form_pg_constraint bcon = (Form_pg_constraint) GETSTRUCT(b);
                              16345                 :                : 
                              16346         [ +  - ]:             42 :     if (acon->condeferrable != bcon->condeferrable ||
                              16347         [ +  - ]:             42 :         acon->condeferred != bcon->condeferred ||
                              16348         [ +  + ]:             42 :         strcmp(decompile_conbin(a, tupleDesc),
                              16349                 :             42 :                decompile_conbin(b, tupleDesc)) != 0)
                              16350                 :              3 :         return false;
                              16351                 :                :     else
                              16352                 :             39 :         return true;
                              16353                 :                : }
                              16354                 :                : 
                              16355                 :                : /*
                              16356                 :                :  * Check columns in child table match up with columns in parent, and increment
                              16357                 :                :  * their attinhcount.
                              16358                 :                :  *
                              16359                 :                :  * Called by CreateInheritance
                              16360                 :                :  *
                              16361                 :                :  * Currently all parent columns must be found in child. Missing columns are an
                              16362                 :                :  * error.  One day we might consider creating new columns like CREATE TABLE
                              16363                 :                :  * does.  However, that is widely unpopular --- in the common use case of
                              16364                 :                :  * partitioned tables it's a foot-gun.
                              16365                 :                :  *
                              16366                 :                :  * The data type must match exactly. If the parent column is NOT NULL then
                              16367                 :                :  * the child must be as well. Defaults are not compared, however.
                              16368                 :                :  */
                              16369                 :                : static void
   89 peter@eisentraut.org    16370                 :GNC        1359 : MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
                              16371                 :                : {
                              16372                 :                :     Relation    attrrel;
                              16373                 :                :     TupleDesc   parent_desc;
                              16374                 :                : 
 1910 andres@anarazel.de      16375                 :CBC        1359 :     attrrel = table_open(AttributeRelationId, RowExclusiveLock);
  201 peter@eisentraut.org    16376                 :GNC        1359 :     parent_desc = RelationGetDescr(parent_rel);
                              16377                 :                : 
                              16378         [ +  + ]:           4664 :     for (AttrNumber parent_attno = 1; parent_attno <= parent_desc->natts; parent_attno++)
                              16379                 :                :     {
                              16380                 :           3344 :         Form_pg_attribute parent_att = TupleDescAttr(parent_desc, parent_attno - 1);
                              16381                 :           3344 :         char       *parent_attname = NameStr(parent_att->attname);
                              16382                 :                :         HeapTuple   tuple;
                              16383                 :                : 
                              16384                 :                :         /* Ignore dropped columns in the parent. */
                              16385         [ +  + ]:           3344 :         if (parent_att->attisdropped)
 6496 bruce@momjian.us        16386                 :CBC         148 :             continue;
                              16387                 :                : 
                              16388                 :                :         /* Find same column in child (matching on column name). */
  201 peter@eisentraut.org    16389                 :GNC        3196 :         tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel), parent_attname);
 6496 bruce@momjian.us        16390         [ +  + ]:CBC        3196 :         if (HeapTupleIsValid(tuple))
                              16391                 :                :         {
  201 peter@eisentraut.org    16392                 :GNC        3190 :             Form_pg_attribute child_att = (Form_pg_attribute) GETSTRUCT(tuple);
                              16393                 :                : 
                              16394         [ +  + ]:           3190 :             if (parent_att->atttypid != child_att->atttypid ||
                              16395         [ +  + ]:           3187 :                 parent_att->atttypmod != child_att->atttypmod)
 6496 bruce@momjian.us        16396         [ +  - ]:CBC           6 :                 ereport(ERROR,
                              16397                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16398                 :                :                          errmsg("child table \"%s\" has different type for column \"%s\"",
                              16399                 :                :                                 RelationGetRelationName(child_rel), parent_attname)));
                              16400                 :                : 
  201 peter@eisentraut.org    16401         [ +  + ]:GNC        3184 :             if (parent_att->attcollation != child_att->attcollation)
 4746 tgl@sss.pgh.pa.us       16402         [ +  - ]:CBC           3 :                 ereport(ERROR,
                              16403                 :                :                         (errcode(ERRCODE_COLLATION_MISMATCH),
                              16404                 :                :                          errmsg("child table \"%s\" has different collation for column \"%s\"",
                              16405                 :                :                                 RelationGetRelationName(child_rel), parent_attname)));
                              16406                 :                : 
                              16407                 :                :             /*
                              16408                 :                :              * If the parent has a not-null constraint that's not NO INHERIT,
                              16409                 :                :              * make sure the child has one too.
                              16410                 :                :              *
                              16411                 :                :              * Other constraints are checked elsewhere.
                              16412                 :                :              */
  201 peter@eisentraut.org    16413   [ +  +  +  + ]:GNC        3181 :             if (parent_att->attnotnull && !child_att->attnotnull)
                              16414                 :                :             {
                              16415                 :                :                 HeapTuple   contup;
                              16416                 :                : 
  233 alvherre@alvh.no-ip.    16417                 :             13 :                 contup = findNotNullConstraintAttnum(RelationGetRelid(parent_rel),
  201 peter@eisentraut.org    16418                 :             13 :                                                      parent_att->attnum);
  226 alvherre@alvh.no-ip.    16419         [ +  + ]:             13 :                 if (HeapTupleIsValid(contup) &&
                              16420         [ +  + ]:             10 :                     !((Form_pg_constraint) GETSTRUCT(contup))->connoinherit)
  233                         16421         [ +  - ]:              9 :                     ereport(ERROR,
                              16422                 :                :                             errcode(ERRCODE_DATATYPE_MISMATCH),
                              16423                 :                :                             errmsg("column \"%s\" in child table must be marked NOT NULL",
                              16424                 :                :                                    parent_attname));
                              16425                 :                :             }
                              16426                 :                : 
                              16427                 :                :             /*
                              16428                 :                :              * Child column must be generated if and only if parent column is.
                              16429                 :                :              */
  201 peter@eisentraut.org    16430   [ +  +  +  + ]:           3172 :             if (parent_att->attgenerated && !child_att->attgenerated)
 1076 peter@eisentraut.org    16431         [ +  - ]:CBC           9 :                 ereport(ERROR,
                              16432                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16433                 :                :                          errmsg("column \"%s\" in child table must be a generated column", parent_attname)));
  201 peter@eisentraut.org    16434   [ +  +  +  + ]:GNC        3163 :             if (child_att->attgenerated && !parent_att->attgenerated)
  459 tgl@sss.pgh.pa.us       16435         [ +  - ]:CBC           6 :                 ereport(ERROR,
                              16436                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16437                 :                :                          errmsg("column \"%s\" in child table must not be a generated column", parent_attname)));
                              16438                 :                : 
                              16439                 :                :             /*
                              16440                 :                :              * Regular inheritance children are independent enough not to
                              16441                 :                :              * inherit identity columns.  But partitions are integral part of
                              16442                 :                :              * a partitioned table and inherit identity column.
                              16443                 :                :              */
   89 peter@eisentraut.org    16444         [ +  + ]:GNC        3157 :             if (ispartition)
                              16445                 :           2895 :                 child_att->attidentity = parent_att->attidentity;
                              16446                 :                : 
                              16447                 :                :             /*
                              16448                 :                :              * OK, bump the child column's inheritance count.  (If we fail
                              16449                 :                :              * later on, this change will just roll back.)
                              16450                 :                :              */
  201                         16451                 :           3157 :             child_att->attinhcount++;
                              16452         [ -  + ]:           3157 :             if (child_att->attinhcount < 0)
  383 peter@eisentraut.org    16453         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              16454                 :                :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                              16455                 :                :                         errmsg("too many inheritance parents"));
                              16456                 :                : 
                              16457                 :                :             /*
                              16458                 :                :              * In case of partitions, we must enforce that value of attislocal
                              16459                 :                :              * is same in all partitions. (Note: there are only inherited
                              16460                 :                :              * attributes in partitions)
                              16461                 :                :              */
  201 peter@eisentraut.org    16462         [ +  + ]:GNC        3157 :             if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              16463                 :                :             {
                              16464         [ -  + ]:           2895 :                 Assert(child_att->attinhcount == 1);
                              16465                 :           2895 :                 child_att->attislocal = false;
                              16466                 :                :             }
                              16467                 :                : 
 2630 alvherre@alvh.no-ip.    16468                 :CBC        3157 :             CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
 6393 tgl@sss.pgh.pa.us       16469                 :           3157 :             heap_freetuple(tuple);
                              16470                 :                :         }
                              16471                 :                :         else
                              16472                 :                :         {
 6496 bruce@momjian.us        16473         [ +  - ]:              6 :             ereport(ERROR,
                              16474                 :                :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16475                 :                :                      errmsg("child table is missing column \"%s\"", parent_attname)));
                              16476                 :                :         }
                              16477                 :                :     }
                              16478                 :                : 
 1910 andres@anarazel.de      16479                 :           1320 :     table_close(attrrel, RowExclusiveLock);
 6496 bruce@momjian.us        16480                 :           1320 : }
                              16481                 :                : 
                              16482                 :                : /*
                              16483                 :                :  * Check constraints in child table match up with constraints in parent,
                              16484                 :                :  * and increment their coninhcount.
                              16485                 :                :  *
                              16486                 :                :  * Constraints that are marked ONLY in the parent are ignored.
                              16487                 :                :  *
                              16488                 :                :  * Called by CreateInheritance
                              16489                 :                :  *
                              16490                 :                :  * Currently all constraints in parent must be present in the child. One day we
                              16491                 :                :  * may consider adding new constraints like CREATE TABLE does.
                              16492                 :                :  *
                              16493                 :                :  * XXX This is O(N^2) which may be an issue with tables with hundreds of
                              16494                 :                :  * constraints. As long as tables have more like 10 constraints it shouldn't be
                              16495                 :                :  * a problem though. Even 100 constraints ought not be the end of the world.
                              16496                 :                :  *
                              16497                 :                :  * XXX See MergeWithExistingConstraint too if you change this code.
                              16498                 :                :  */
                              16499                 :                : static void
      neilc@samurai.com       16500                 :           1320 : MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
                              16501                 :                : {
                              16502                 :                :     Relation    constraintrel;
                              16503                 :                :     SysScanDesc parent_scan;
                              16504                 :                :     ScanKeyData parent_key;
                              16505                 :                :     HeapTuple   parent_tuple;
  233 alvherre@alvh.no-ip.    16506                 :GNC        1320 :     Oid         parent_relid = RelationGetRelid(parent_rel);
                              16507                 :                : 
  201 peter@eisentraut.org    16508                 :           1320 :     constraintrel = table_open(ConstraintRelationId, RowExclusiveLock);
                              16509                 :                : 
                              16510                 :                :     /* Outer loop scans through the parent's constraint definitions */
 5819 tgl@sss.pgh.pa.us       16511                 :CBC        1320 :     ScanKeyInit(&parent_key,
                              16512                 :                :                 Anum_pg_constraint_conrelid,
                              16513                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              16514                 :                :                 ObjectIdGetDatum(parent_relid));
  201 peter@eisentraut.org    16515                 :GNC        1320 :     parent_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
                              16516                 :                :                                      true, NULL, 1, &parent_key);
                              16517                 :                : 
 5819 tgl@sss.pgh.pa.us       16518         [ +  + ]:CBC        2002 :     while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
                              16519                 :                :     {
 5421 bruce@momjian.us        16520                 :            700 :         Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
                              16521                 :                :         SysScanDesc child_scan;
                              16522                 :                :         ScanKeyData child_key;
                              16523                 :                :         HeapTuple   child_tuple;
                              16524                 :            700 :         bool        found = false;
                              16525                 :                : 
  233 alvherre@alvh.no-ip.    16526         [ +  + ]:GNC         700 :         if (parent_con->contype != CONSTRAINT_CHECK &&
                              16527         [ +  + ]:            636 :             parent_con->contype != CONSTRAINT_NOTNULL)
 6496 bruce@momjian.us        16528                 :CBC         411 :             continue;
                              16529                 :                : 
                              16530                 :                :         /* if the parent's constraint is marked NO INHERIT, it's not inherited */
 4377 alvherre@alvh.no-ip.    16531         [ +  + ]:            339 :         if (parent_con->connoinherit)
 4472                         16532                 :             50 :             continue;
                              16533                 :                : 
                              16534                 :                :         /* Search for a child constraint matching this one */
 5819 tgl@sss.pgh.pa.us       16535                 :            289 :         ScanKeyInit(&child_key,
                              16536                 :                :                     Anum_pg_constraint_conrelid,
                              16537                 :                :                     BTEqualStrategyNumber, F_OIDEQ,
                              16538                 :                :                     ObjectIdGetDatum(RelationGetRelid(child_rel)));
  201 peter@eisentraut.org    16539                 :GNC         289 :         child_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
                              16540                 :                :                                         true, NULL, 1, &child_key);
                              16541                 :                : 
 5819 tgl@sss.pgh.pa.us       16542         [ +  + ]:CBC         495 :         while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
                              16543                 :                :         {
 5421 bruce@momjian.us        16544                 :            480 :             Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
                              16545                 :                :             HeapTuple   child_copy;
                              16546                 :                : 
  233 alvherre@alvh.no-ip.    16547         [ +  + ]:GNC         480 :             if (child_con->contype != parent_con->contype)
 5819 tgl@sss.pgh.pa.us       16548                 :GBC         108 :                 continue;
                              16549                 :                : 
                              16550                 :                :             /*
                              16551                 :                :              * CHECK constraint are matched by name, NOT NULL ones by
                              16552                 :                :              * attribute number
                              16553                 :                :              */
  201 peter@eisentraut.org    16554         [ +  + ]:GNC         372 :             if (child_con->contype == CONSTRAINT_CHECK)
                              16555                 :                :             {
                              16556                 :             72 :                 if (strcmp(NameStr(parent_con->conname),
                              16557         [ +  + ]:             57 :                            NameStr(child_con->conname)) != 0)
                              16558                 :             15 :                     continue;
                              16559                 :                :             }
  233 alvherre@alvh.no-ip.    16560         [ +  - ]:            315 :             else if (child_con->contype == CONSTRAINT_NOTNULL)
                              16561                 :                :             {
                              16562                 :            315 :                 AttrNumber  parent_attno = extractNotNullColumn(parent_tuple);
                              16563                 :            315 :                 AttrNumber  child_attno = extractNotNullColumn(child_tuple);
                              16564                 :                : 
                              16565         [ +  + ]:            315 :                 if (strcmp(get_attname(parent_relid, parent_attno, false),
                              16566                 :            315 :                            get_attname(RelationGetRelid(child_rel), child_attno,
                              16567                 :                :                                        false)) != 0)
                              16568                 :             83 :                     continue;
                              16569                 :                :             }
                              16570                 :                : 
                              16571         [ +  + ]:            274 :             if (child_con->contype == CONSTRAINT_CHECK &&
  201 peter@eisentraut.org    16572         [ +  + ]:             42 :                 !constraints_equivalent(parent_tuple, child_tuple, RelationGetDescr(constraintrel)))
 5819 tgl@sss.pgh.pa.us       16573         [ +  - ]:CBC           3 :                 ereport(ERROR,
                              16574                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16575                 :                :                          errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
                              16576                 :                :                                 RelationGetRelationName(child_rel), NameStr(parent_con->conname))));
                              16577                 :                : 
                              16578                 :                :             /*
                              16579                 :                :              * If the CHECK child constraint is "no inherit" then cannot
                              16580                 :                :              * merge.
                              16581                 :                :              *
                              16582                 :                :              * This is not desirable for not-null constraints, mostly because
                              16583                 :                :              * it breaks our pg_upgrade strategy, but it also makes sense on
                              16584                 :                :              * its own: if a child has its own not-null constraint and then
                              16585                 :                :              * acquires a parent with the same constraint, then we start to
                              16586                 :                :              * enforce that constraint for all the descendants of that child
                              16587                 :                :              * too, if any.
                              16588                 :                :              */
  233 alvherre@alvh.no-ip.    16589         [ +  + ]:GNC         271 :             if (child_con->contype == CONSTRAINT_CHECK &&
                              16590         [ -  + ]:             39 :                 child_con->connoinherit)
 4472 alvherre@alvh.no-ip.    16591         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              16592                 :                :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              16593                 :                :                          errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
                              16594                 :                :                                 NameStr(child_con->conname), RelationGetRelationName(child_rel))));
                              16595                 :                : 
                              16596                 :                :             /*
                              16597                 :                :              * If the child constraint is "not valid" then cannot merge with a
                              16598                 :                :              * valid parent constraint
                              16599                 :                :              */
 2745 tgl@sss.pgh.pa.us       16600   [ +  -  -  + ]:CBC         271 :             if (parent_con->convalidated && !child_con->convalidated)
 2745 tgl@sss.pgh.pa.us       16601         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              16602                 :                :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              16603                 :                :                          errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
                              16604                 :                :                                 NameStr(child_con->conname), RelationGetRelationName(child_rel))));
                              16605                 :                : 
                              16606                 :                :             /*
                              16607                 :                :              * OK, bump the child constraint's inheritance count.  (If we fail
                              16608                 :                :              * later on, this change will just roll back.)
                              16609                 :                :              */
 5819 tgl@sss.pgh.pa.us       16610                 :CBC         271 :             child_copy = heap_copytuple(child_tuple);
                              16611                 :            271 :             child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
                              16612                 :            271 :             child_con->coninhcount++;
  383 peter@eisentraut.org    16613         [ -  + ]:            271 :             if (child_con->coninhcount < 0)
  383 peter@eisentraut.org    16614         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              16615                 :                :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                              16616                 :                :                         errmsg("too many inheritance parents"));
  233 alvherre@alvh.no-ip.    16617         [ +  + ]:GNC         271 :             if (child_con->contype == CONSTRAINT_NOTNULL &&
                              16618         [ -  + ]:            232 :                 child_con->connoinherit)
  233 alvherre@alvh.no-ip.    16619                 :UNC           0 :                 child_con->connoinherit = false;
                              16620                 :                : 
                              16621                 :                :             /*
                              16622                 :                :              * In case of partitions, an inherited constraint must be
                              16623                 :                :              * inherited only once since it cannot have multiple parents and
                              16624                 :                :              * it is never considered local.
                              16625                 :                :              */
  201 peter@eisentraut.org    16626         [ +  + ]:GNC         271 :             if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              16627                 :                :             {
 2685 rhaas@postgresql.org    16628         [ -  + ]:CBC         234 :                 Assert(child_con->coninhcount == 1);
                              16629                 :            234 :                 child_con->conislocal = false;
                              16630                 :                :             }
                              16631                 :                : 
  201 peter@eisentraut.org    16632                 :GNC         271 :             CatalogTupleUpdate(constraintrel, &child_copy->t_self, child_copy);
 5819 tgl@sss.pgh.pa.us       16633                 :CBC         271 :             heap_freetuple(child_copy);
                              16634                 :                : 
                              16635                 :            271 :             found = true;
                              16636                 :            271 :             break;
                              16637                 :                :         }
                              16638                 :                : 
                              16639                 :            286 :         systable_endscan(child_scan);
                              16640                 :                : 
 6496 bruce@momjian.us        16641         [ +  + ]:            286 :         if (!found)
                              16642                 :                :         {
  226 alvherre@alvh.no-ip.    16643         [ +  + ]:GNC          15 :             if (parent_con->contype == CONSTRAINT_NOTNULL)
                              16644         [ +  - ]:              3 :                 ereport(ERROR,
                              16645                 :                :                         errcode(ERRCODE_DATATYPE_MISMATCH),
                              16646                 :                :                         errmsg("column \"%s\" in child table must be marked NOT NULL",
                              16647                 :                :                                get_attname(parent_relid,
                              16648                 :                :                                            extractNotNullColumn(parent_tuple),
                              16649                 :                :                                            false)));
                              16650                 :                : 
 6496 bruce@momjian.us        16651         [ +  - ]:CBC          12 :             ereport(ERROR,
                              16652                 :                :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              16653                 :                :                      errmsg("child table is missing constraint \"%s\"",
                              16654                 :                :                             NameStr(parent_con->conname))));
                              16655                 :                :         }
                              16656                 :                :     }
                              16657                 :                : 
 5819 tgl@sss.pgh.pa.us       16658                 :           1302 :     systable_endscan(parent_scan);
  201 peter@eisentraut.org    16659                 :GNC        1302 :     table_close(constraintrel, RowExclusiveLock);
 6496 bruce@momjian.us        16660                 :CBC        1302 : }
                              16661                 :                : 
                              16662                 :                : /*
                              16663                 :                :  * ALTER TABLE NO INHERIT
                              16664                 :                :  *
                              16665                 :                :  * Return value is the address of the relation that is no longer parent.
                              16666                 :                :  */
                              16667                 :                : static ObjectAddress
 2685 rhaas@postgresql.org    16668                 :             22 : ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
                              16669                 :                : {
                              16670                 :                :     ObjectAddress address;
                              16671                 :                :     Relation    parent_rel;
                              16672                 :                : 
                              16673         [ -  + ]:             22 :     if (rel->rd_rel->relispartition)
 2685 rhaas@postgresql.org    16674         [ #  # ]:UBC           0 :         ereport(ERROR,
                              16675                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              16676                 :                :                  errmsg("cannot change inheritance of a partition")));
                              16677                 :                : 
                              16678                 :                :     /*
                              16679                 :                :      * AccessShareLock on the parent is probably enough, seeing that DROP
                              16680                 :                :      * TABLE doesn't lock parent tables at all.  We need some lock since we'll
                              16681                 :                :      * be inspecting the parent's schema.
                              16682                 :                :      */
 1910 andres@anarazel.de      16683                 :CBC          22 :     parent_rel = table_openrv(parent, AccessShareLock);
                              16684                 :                : 
                              16685                 :                :     /*
                              16686                 :                :      * We don't bother to check ownership of the parent table --- ownership of
                              16687                 :                :      * the child is presumed enough rights.
                              16688                 :                :      */
                              16689                 :                : 
                              16690                 :                :     /* Off to RemoveInheritance() where most of the work happens */
 1116 alvherre@alvh.no-ip.    16691                 :             22 :     RemoveInheritance(rel, parent_rel, false);
                              16692                 :                : 
                              16693                 :                :     /*
                              16694                 :                :      * If parent_rel has a primary key, then child_rel has not-null
                              16695                 :                :      * constraints that make these columns as non nullable.  Mark those
                              16696                 :                :      * constraints as no longer inherited by this parent.
                              16697                 :                :      */
  233 alvherre@alvh.no-ip.    16698                 :GNC          19 :     ATInheritAdjustNotNulls(parent_rel, rel, -1);
                              16699                 :                : 
                              16700                 :                :     /*
                              16701                 :                :      * If the parent has a primary key, then we decrement counts for all NOT
                              16702                 :                :      * NULL constraints
                              16703                 :                :      */
                              16704                 :                : 
 2685 rhaas@postgresql.org    16705                 :CBC          19 :     ObjectAddressSet(address, RelationRelationId,
                              16706                 :                :                      RelationGetRelid(parent_rel));
                              16707                 :                : 
                              16708                 :                :     /* keep our lock on the parent relation until commit */
 1910 andres@anarazel.de      16709                 :             19 :     table_close(parent_rel, NoLock);
                              16710                 :                : 
 2685 rhaas@postgresql.org    16711                 :             19 :     return address;
                              16712                 :                : }
                              16713                 :                : 
                              16714                 :                : /*
                              16715                 :                :  * MarkInheritDetached
                              16716                 :                :  *
                              16717                 :                :  * Set inhdetachpending for a partition, for ATExecDetachPartition
                              16718                 :                :  * in concurrent mode.  While at it, verify that no other partition is
                              16719                 :                :  * already pending detach.
                              16720                 :                :  */
                              16721                 :                : static void
 1116 alvherre@alvh.no-ip.    16722                 :             73 : MarkInheritDetached(Relation child_rel, Relation parent_rel)
                              16723                 :                : {
                              16724                 :                :     Relation    catalogRelation;
                              16725                 :                :     SysScanDesc scan;
                              16726                 :                :     ScanKeyData key;
                              16727                 :                :     HeapTuple   inheritsTuple;
                              16728                 :             73 :     bool        found = false;
                              16729                 :                : 
                              16730         [ -  + ]:             73 :     Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                              16731                 :                : 
                              16732                 :                :     /*
                              16733                 :                :      * Find pg_inherits entries by inhparent.  (We need to scan them all in
                              16734                 :                :      * order to verify that no other partition is pending detach.)
                              16735                 :                :      */
                              16736                 :             73 :     catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
                              16737                 :             73 :     ScanKeyInit(&key,
                              16738                 :                :                 Anum_pg_inherits_inhparent,
                              16739                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              16740                 :                :                 ObjectIdGetDatum(RelationGetRelid(parent_rel)));
 1082                         16741                 :             73 :     scan = systable_beginscan(catalogRelation, InheritsParentIndexId,
                              16742                 :                :                               true, NULL, 1, &key);
                              16743                 :                : 
 1116                         16744         [ +  + ]:            288 :     while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
                              16745                 :                :     {
                              16746                 :                :         Form_pg_inherits inhForm;
                              16747                 :                : 
 1082                         16748                 :            143 :         inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
                              16749         [ +  + ]:            143 :         if (inhForm->inhdetachpending)
                              16750         [ +  - ]:              1 :             ereport(ERROR,
                              16751                 :                :                     errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              16752                 :                :                     errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"",
                              16753                 :                :                            get_rel_name(inhForm->inhrelid),
                              16754                 :                :                            get_namespace_name(parent_rel->rd_rel->relnamespace),
                              16755                 :                :                            RelationGetRelationName(parent_rel)),
                              16756                 :                :                     errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
                              16757                 :                : 
                              16758         [ +  + ]:            142 :         if (inhForm->inhrelid == RelationGetRelid(child_rel))
                              16759                 :                :         {
                              16760                 :                :             HeapTuple   newtup;
                              16761                 :                : 
                              16762                 :             72 :             newtup = heap_copytuple(inheritsTuple);
                              16763                 :             72 :             ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
                              16764                 :                : 
                              16765                 :             72 :             CatalogTupleUpdate(catalogRelation,
                              16766                 :                :                                &inheritsTuple->t_self,
                              16767                 :                :                                newtup);
                              16768                 :             72 :             found = true;
                              16769                 :             72 :             heap_freetuple(newtup);
                              16770                 :                :             /* keep looking, to ensure we catch others pending detach */
                              16771                 :                :         }
                              16772                 :                :     }
                              16773                 :                : 
                              16774                 :                :     /* Done */
 1116                         16775                 :             72 :     systable_endscan(scan);
                              16776                 :             72 :     table_close(catalogRelation, RowExclusiveLock);
                              16777                 :                : 
                              16778         [ -  + ]:             72 :     if (!found)
 1116 alvherre@alvh.no-ip.    16779         [ #  # ]:UBC           0 :         ereport(ERROR,
                              16780                 :                :                 (errcode(ERRCODE_UNDEFINED_TABLE),
                              16781                 :                :                  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
                              16782                 :                :                         RelationGetRelationName(child_rel),
                              16783                 :                :                         RelationGetRelationName(parent_rel))));
 1116 alvherre@alvh.no-ip.    16784                 :CBC          72 : }
                              16785                 :                : 
                              16786                 :                : /*
                              16787                 :                :  * RemoveInheritance
                              16788                 :                :  *
                              16789                 :                :  * Drop a parent from the child's parents. This just adjusts the attinhcount
                              16790                 :                :  * and attislocal of the columns and removes the pg_inherit and pg_depend
                              16791                 :                :  * entries.  expect_detached is passed down to DeleteInheritsTuple, q.v..
                              16792                 :                :  *
                              16793                 :                :  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
                              16794                 :                :  * up attislocal stays true, which means if a child is ever removed from a
                              16795                 :                :  * parent then its columns will never be automatically dropped which may
                              16796                 :                :  * surprise. But at least we'll never surprise by dropping columns someone
                              16797                 :                :  * isn't expecting to be dropped which would actually mean data loss.
                              16798                 :                :  *
                              16799                 :                :  * coninhcount and conislocal for inherited constraints are adjusted in
                              16800                 :                :  * exactly the same way.
                              16801                 :                :  *
                              16802                 :                :  * Common to ATExecDropInherit() and ATExecDetachPartition().
                              16803                 :                :  */
                              16804                 :                : static void
                              16805                 :            391 : RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
                              16806                 :                : {
                              16807                 :                :     Relation    catalogRelation;
                              16808                 :                :     SysScanDesc scan;
                              16809                 :                :     ScanKeyData key[3];
                              16810                 :                :     HeapTuple   attributeTuple,
                              16811                 :                :                 constraintTuple;
                              16812                 :                :     List       *connames;
                              16813                 :                :     List       *nncolumns;
                              16814                 :                :     bool        found;
                              16815                 :                :     bool        is_partitioning;
                              16816                 :                : 
  201 peter@eisentraut.org    16817                 :GNC         391 :     is_partitioning = (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
                              16818                 :                : 
 2277 alvherre@alvh.no-ip.    16819                 :CBC         391 :     found = DeleteInheritsTuple(RelationGetRelid(child_rel),
                              16820                 :                :                                 RelationGetRelid(parent_rel),
                              16821                 :                :                                 expect_detached,
 1116                         16822                 :            391 :                                 RelationGetRelationName(child_rel));
 6496 bruce@momjian.us        16823         [ +  + ]:            391 :     if (!found)
                              16824                 :                :     {
  201 peter@eisentraut.org    16825         [ +  + ]:GNC          12 :         if (is_partitioning)
 2685 rhaas@postgresql.org    16826         [ +  - ]:CBC           9 :             ereport(ERROR,
                              16827                 :                :                     (errcode(ERRCODE_UNDEFINED_TABLE),
                              16828                 :                :                      errmsg("relation \"%s\" is not a partition of relation \"%s\"",
                              16829                 :                :                             RelationGetRelationName(child_rel),
                              16830                 :                :                             RelationGetRelationName(parent_rel))));
                              16831                 :                :         else
                              16832         [ +  - ]:              3 :             ereport(ERROR,
                              16833                 :                :                     (errcode(ERRCODE_UNDEFINED_TABLE),
                              16834                 :                :                      errmsg("relation \"%s\" is not a parent of relation \"%s\"",
                              16835                 :                :                             RelationGetRelationName(parent_rel),
                              16836                 :                :                             RelationGetRelationName(child_rel))));
                              16837                 :                :     }
                              16838                 :                : 
                              16839                 :                :     /*
                              16840                 :                :      * Search through child columns looking for ones matching parent rel
                              16841                 :                :      */
 1910 andres@anarazel.de      16842                 :            379 :     catalogRelation = table_open(AttributeRelationId, RowExclusiveLock);
 6393 tgl@sss.pgh.pa.us       16843                 :            379 :     ScanKeyInit(&key[0],
                              16844                 :                :                 Anum_pg_attribute_attrelid,
                              16845                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              16846                 :                :                 ObjectIdGetDatum(RelationGetRelid(child_rel)));
 6496 bruce@momjian.us        16847                 :            379 :     scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
                              16848                 :                :                               true, NULL, 1, key);
                              16849         [ +  + ]:           3589 :     while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
                              16850                 :                :     {
      neilc@samurai.com       16851                 :           3210 :         Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
                              16852                 :                : 
                              16853                 :                :         /* Ignore if dropped or not inherited */
      bruce@momjian.us        16854         [ +  + ]:           3210 :         if (att->attisdropped)
 6496 bruce@momjian.us        16855                 :GBC          18 :             continue;
 6393 tgl@sss.pgh.pa.us       16856         [ +  + ]:CBC        3192 :         if (att->attinhcount <= 0)
                              16857                 :           2283 :             continue;
                              16858                 :                : 
                              16859         [ +  + ]:            909 :         if (SearchSysCacheExistsAttName(RelationGetRelid(parent_rel),
                              16860                 :            909 :                                         NameStr(att->attname)))
                              16861                 :                :         {
                              16862                 :                :             /* Decrement inhcount and possibly set islocal to true */
 6496 bruce@momjian.us        16863                 :            903 :             HeapTuple   copyTuple = heap_copytuple(attributeTuple);
      neilc@samurai.com       16864                 :            903 :             Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
                              16865                 :                : 
      bruce@momjian.us        16866                 :            903 :             copy_att->attinhcount--;
                              16867         [ +  - ]:            903 :             if (copy_att->attinhcount == 0)
                              16868                 :            903 :                 copy_att->attislocal = true;
                              16869                 :                : 
 2630 alvherre@alvh.no-ip.    16870                 :            903 :             CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
 6496 bruce@momjian.us        16871                 :            903 :             heap_freetuple(copyTuple);
                              16872                 :                :         }
                              16873                 :                :     }
                              16874                 :            379 :     systable_endscan(scan);
 1910 andres@anarazel.de      16875                 :            379 :     table_close(catalogRelation, RowExclusiveLock);
                              16876                 :                : 
                              16877                 :                :     /*
                              16878                 :                :      * Likewise, find inherited check constraints and disinherit them. To do
                              16879                 :                :      * this, we first need a list of the names of the parent's check
                              16880                 :                :      * constraints.  (We cheat a bit by only checking for name matches,
                              16881                 :                :      * assuming that the expressions will match.)
                              16882                 :                :      *
                              16883                 :                :      * For NOT NULL columns, we store column numbers to match.
                              16884                 :                :      */
                              16885                 :            379 :     catalogRelation = table_open(ConstraintRelationId, RowExclusiveLock);
 5819 tgl@sss.pgh.pa.us       16886                 :            379 :     ScanKeyInit(&key[0],
                              16887                 :                :                 Anum_pg_constraint_conrelid,
                              16888                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              16889                 :                :                 ObjectIdGetDatum(RelationGetRelid(parent_rel)));
 2049                         16890                 :            379 :     scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
                              16891                 :                :                               true, NULL, 1, key);
                              16892                 :                : 
 5819                         16893                 :            379 :     connames = NIL;
  233 alvherre@alvh.no-ip.    16894                 :GNC         379 :     nncolumns = NIL;
                              16895                 :                : 
 5819 tgl@sss.pgh.pa.us       16896         [ +  + ]:CBC         537 :     while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
                              16897                 :                :     {
                              16898                 :            158 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
                              16899                 :                : 
                              16900         [ +  + ]:            158 :         if (con->contype == CONSTRAINT_CHECK)
                              16901                 :              9 :             connames = lappend(connames, pstrdup(NameStr(con->conname)));
  233 alvherre@alvh.no-ip.    16902         [ +  + ]:GNC         158 :         if (con->contype == CONSTRAINT_NOTNULL)
                              16903                 :             40 :             nncolumns = lappend_int(nncolumns, extractNotNullColumn(constraintTuple));
                              16904                 :                :     }
                              16905                 :                : 
 5819 tgl@sss.pgh.pa.us       16906                 :CBC         379 :     systable_endscan(scan);
                              16907                 :                : 
                              16908                 :                :     /* Now scan the child's constraints */
                              16909                 :            379 :     ScanKeyInit(&key[0],
                              16910                 :                :                 Anum_pg_constraint_conrelid,
                              16911                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              16912                 :                :                 ObjectIdGetDatum(RelationGetRelid(child_rel)));
 2049                         16913                 :            379 :     scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
                              16914                 :                :                               true, NULL, 1, key);
                              16915                 :                : 
 5819                         16916         [ +  + ]:            635 :     while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
                              16917                 :                :     {
                              16918                 :            256 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
  233 alvherre@alvh.no-ip.    16919                 :GNC         256 :         bool        match = false;
                              16920                 :                :         ListCell   *lc;
                              16921                 :                : 
                              16922                 :                :         /*
                              16923                 :                :          * Match CHECK constraints by name, not-null constraints by column
                              16924                 :                :          * number, and ignore all others.
                              16925                 :                :          */
                              16926         [ +  + ]:            256 :         if (con->contype == CONSTRAINT_CHECK)
                              16927                 :                :         {
                              16928   [ +  +  +  +  :             95 :             foreach(lc, connames)
                                              +  + ]
                              16929                 :                :             {
                              16930         [ +  - ]:             15 :                 if (con->contype == CONSTRAINT_CHECK &&
                              16931         [ +  + ]:             15 :                     strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
                              16932                 :                :                 {
                              16933                 :              9 :                     match = true;
                              16934                 :              9 :                     break;
                              16935                 :                :                 }
                              16936                 :                :             }
                              16937                 :                :         }
                              16938         [ +  + ]:            167 :         else if (con->contype == CONSTRAINT_NOTNULL)
                              16939                 :                :         {
                              16940                 :             49 :             AttrNumber  child_attno = extractNotNullColumn(constraintTuple);
                              16941                 :                : 
                              16942   [ +  +  +  +  :             64 :             foreach(lc, nncolumns)
                                              +  + ]
                              16943                 :                :             {
                              16944         [ +  + ]:             55 :                 if (lfirst_int(lc) == child_attno)
                              16945                 :                :                 {
                              16946                 :             40 :                     match = true;
                              16947                 :             40 :                     break;
                              16948                 :                :                 }
                              16949                 :                :             }
                              16950                 :                :         }
                              16951                 :                :         else
                              16952                 :            118 :             continue;
                              16953                 :                : 
 5819 tgl@sss.pgh.pa.us       16954         [ +  + ]:CBC         138 :         if (match)
                              16955                 :                :         {
                              16956                 :                :             /* Decrement inhcount and possibly set islocal to true */
                              16957                 :             49 :             HeapTuple   copyTuple = heap_copytuple(constraintTuple);
                              16958                 :             49 :             Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
                              16959                 :                : 
 2489                         16960         [ -  + ]:             49 :             if (copy_con->coninhcount <= 0) /* shouldn't happen */
 5819 tgl@sss.pgh.pa.us       16961         [ #  # ]:UBC           0 :                 elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
                              16962                 :                :                      RelationGetRelid(child_rel), NameStr(copy_con->conname));
                              16963                 :                : 
 5819 tgl@sss.pgh.pa.us       16964                 :CBC          49 :             copy_con->coninhcount--;
                              16965         [ +  - ]:             49 :             if (copy_con->coninhcount == 0)
                              16966                 :             49 :                 copy_con->conislocal = true;
                              16967                 :                : 
 2630 alvherre@alvh.no-ip.    16968                 :             49 :             CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
 5819 tgl@sss.pgh.pa.us       16969                 :             49 :             heap_freetuple(copyTuple);
                              16970                 :                :         }
                              16971                 :                :     }
                              16972                 :                : 
                              16973                 :            379 :     systable_endscan(scan);
 1910 andres@anarazel.de      16974                 :            379 :     table_close(catalogRelation, RowExclusiveLock);
                              16975                 :                : 
 2685 rhaas@postgresql.org    16976         [ +  + ]:            379 :     drop_parent_dependency(RelationGetRelid(child_rel),
                              16977                 :                :                            RelationRelationId,
                              16978                 :                :                            RelationGetRelid(parent_rel),
                              16979                 :                :                            child_dependency_type(is_partitioning));
                              16980                 :                : 
                              16981                 :                :     /*
                              16982                 :                :      * Post alter hook of this inherits. Since object_access_hook doesn't take
                              16983                 :                :      * multiple object identifiers, we relay oid of parent relation using
                              16984                 :                :      * auxiliary_id argument.
                              16985                 :                :      */
 4046                         16986         [ -  + ]:            379 :     InvokeObjectPostAlterHookArg(InheritsRelationId,
                              16987                 :                :                                  RelationGetRelid(child_rel), 0,
                              16988                 :                :                                  RelationGetRelid(parent_rel), false);
 4743                         16989                 :            379 : }
                              16990                 :                : 
                              16991                 :                : /*
                              16992                 :                :  * Adjust coninhcount of not-null constraints upwards or downwards when a
                              16993                 :                :  * table is marked as inheriting or no longer doing so a table with a primary
                              16994                 :                :  * key.
                              16995                 :                :  *
                              16996                 :                :  * Note: these constraints are not dropped, even if their inhcount goes to zero
                              16997                 :                :  * and conislocal is false.  Instead we mark the constraints as locally defined.
                              16998                 :                :  * This is seen as more useful behavior, with no downsides.  The user can always
                              16999                 :                :  * drop them afterwards.
                              17000                 :                :  */
                              17001                 :                : static void
  233 alvherre@alvh.no-ip.    17002                 :GNC         134 : ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel, int inhcount)
                              17003                 :                : {
                              17004                 :                :     Bitmapset  *pkattnos;
                              17005                 :                : 
                              17006                 :                :     /* Quick exit when parent has no PK */
                              17007         [ +  + ]:            134 :     if (!parent_rel->rd_rel->relhasindex)
                              17008                 :            113 :         return;
                              17009                 :                : 
                              17010                 :             21 :     pkattnos = RelationGetIndexAttrBitmap(parent_rel,
                              17011                 :                :                                           INDEX_ATTR_BITMAP_PRIMARY_KEY);
                              17012         [ +  + ]:             21 :     if (pkattnos != NULL)
                              17013                 :                :     {
                              17014                 :             18 :         Bitmapset  *childattnums = NULL;
                              17015                 :                :         AttrMap    *attmap;
                              17016                 :                :         int         i;
                              17017                 :                : 
                              17018                 :             18 :         attmap = build_attrmap_by_name(RelationGetDescr(parent_rel),
                              17019                 :                :                                        RelationGetDescr(child_rel), true);
                              17020                 :                : 
                              17021                 :             18 :         i = -1;
                              17022         [ +  + ]:             36 :         while ((i = bms_next_member(pkattnos, i)) >= 0)
                              17023                 :                :         {
                              17024                 :             18 :             childattnums = bms_add_member(childattnums,
                              17025                 :             18 :                                           attmap->attnums[i + FirstLowInvalidHeapAttributeNumber - 1]);
                              17026                 :                :         }
                              17027                 :                : 
                              17028                 :                :         /*
                              17029                 :                :          * CCI is needed in case there's a NOT NULL PRIMARY KEY column in the
                              17030                 :                :          * parent: the relevant not-null constraint in the child already had
                              17031                 :                :          * its inhcount modified earlier.
                              17032                 :                :          */
                              17033                 :             18 :         CommandCounterIncrement();
                              17034                 :             18 :         AdjustNotNullInheritance(RelationGetRelid(child_rel), childattnums,
                              17035                 :                :                                  inhcount);
                              17036                 :                :     }
                              17037                 :                : }
                              17038                 :                : 
                              17039                 :                : /*
                              17040                 :                :  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
                              17041                 :                :  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
                              17042                 :                :  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
                              17043                 :                :  * be TypeRelationId).  There's no convenient way to do this, so go trawling
                              17044                 :                :  * through pg_depend.
                              17045                 :                :  */
                              17046                 :                : static void
 2497 rhaas@postgresql.org    17047                 :CBC         385 : drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
                              17048                 :                :                        DependencyType deptype)
                              17049                 :                : {
                              17050                 :                :     Relation    catalogRelation;
                              17051                 :                :     SysScanDesc scan;
                              17052                 :                :     ScanKeyData key[3];
                              17053                 :                :     HeapTuple   depTuple;
                              17054                 :                : 
 1910 andres@anarazel.de      17055                 :            385 :     catalogRelation = table_open(DependRelationId, RowExclusiveLock);
                              17056                 :                : 
 6496 bruce@momjian.us        17057                 :            385 :     ScanKeyInit(&key[0],
                              17058                 :                :                 Anum_pg_depend_classid,
                              17059                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              17060                 :                :                 ObjectIdGetDatum(RelationRelationId));
                              17061                 :            385 :     ScanKeyInit(&key[1],
                              17062                 :                :                 Anum_pg_depend_objid,
                              17063                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              17064                 :                :                 ObjectIdGetDatum(relid));
 6393 tgl@sss.pgh.pa.us       17065                 :            385 :     ScanKeyInit(&key[2],
                              17066                 :                :                 Anum_pg_depend_objsubid,
                              17067                 :                :                 BTEqualStrategyNumber, F_INT4EQ,
                              17068                 :                :                 Int32GetDatum(0));
                              17069                 :                : 
 6496 bruce@momjian.us        17070                 :            385 :     scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
                              17071                 :                :                               NULL, 3, key);
                              17072                 :                : 
                              17073         [ +  + ]:           1170 :     while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
                              17074                 :                :     {
                              17075                 :            785 :         Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
                              17076                 :                : 
 4743 rhaas@postgresql.org    17077         [ +  + ]:            785 :         if (dep->refclassid == refclassid &&
                              17078         [ +  + ]:            391 :             dep->refobjid == refobjid &&
 6393 tgl@sss.pgh.pa.us       17079         [ +  - ]:            385 :             dep->refobjsubid == 0 &&
 2497 rhaas@postgresql.org    17080         [ +  - ]:            385 :             dep->deptype == deptype)
 2629 tgl@sss.pgh.pa.us       17081                 :            385 :             CatalogTupleDelete(catalogRelation, &depTuple->t_self);
                              17082                 :                :     }
                              17083                 :                : 
 6496 neilc@samurai.com       17084                 :            385 :     systable_endscan(scan);
 1910 andres@anarazel.de      17085                 :            385 :     table_close(catalogRelation, RowExclusiveLock);
 4743 rhaas@postgresql.org    17086                 :            385 : }
                              17087                 :                : 
                              17088                 :                : /*
                              17089                 :                :  * ALTER TABLE OF
                              17090                 :                :  *
                              17091                 :                :  * Attach a table to a composite type, as though it had been created with CREATE
                              17092                 :                :  * TABLE OF.  All attname, atttypid, atttypmod and attcollation must match.  The
                              17093                 :                :  * subject table must not have inheritance parents.  These restrictions ensure
                              17094                 :                :  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
                              17095                 :                :  *
                              17096                 :                :  * The address of the type is returned.
                              17097                 :                :  */
                              17098                 :                : static ObjectAddress
                              17099                 :             33 : ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
                              17100                 :                : {
                              17101                 :             33 :     Oid         relid = RelationGetRelid(rel);
                              17102                 :                :     Type        typetuple;
                              17103                 :                :     Form_pg_type typeform;
                              17104                 :                :     Oid         typeid;
                              17105                 :                :     Relation    inheritsRelation,
                              17106                 :                :                 relationRelation;
                              17107                 :                :     SysScanDesc scan;
                              17108                 :                :     ScanKeyData key;
                              17109                 :                :     AttrNumber  table_attno,
                              17110                 :                :                 type_attno;
                              17111                 :                :     TupleDesc   typeTupleDesc,
                              17112                 :                :                 tableTupleDesc;
                              17113                 :                :     ObjectAddress tableobj,
                              17114                 :                :                 typeobj;
                              17115                 :                :     HeapTuple   classtuple;
                              17116                 :                : 
                              17117                 :                :     /* Validate the type. */
                              17118                 :             33 :     typetuple = typenameType(NULL, ofTypename, NULL);
                              17119                 :             33 :     check_of_type(typetuple);
 1972 andres@anarazel.de      17120                 :             33 :     typeform = (Form_pg_type) GETSTRUCT(typetuple);
                              17121                 :             33 :     typeid = typeform->oid;
                              17122                 :                : 
                              17123                 :                :     /* Fail if the table has any inheritance parents. */
 1910                         17124                 :             33 :     inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
 4743 rhaas@postgresql.org    17125                 :             33 :     ScanKeyInit(&key,
                              17126                 :                :                 Anum_pg_inherits_inhrelid,
                              17127                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              17128                 :                :                 ObjectIdGetDatum(relid));
                              17129                 :             33 :     scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
                              17130                 :                :                               true, NULL, 1, &key);
                              17131         [ +  + ]:             33 :     if (HeapTupleIsValid(systable_getnext(scan)))
                              17132         [ +  - ]:              3 :         ereport(ERROR,
                              17133                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17134                 :                :                  errmsg("typed tables cannot inherit")));
                              17135                 :             30 :     systable_endscan(scan);
 1910 andres@anarazel.de      17136                 :             30 :     table_close(inheritsRelation, AccessShareLock);
                              17137                 :                : 
                              17138                 :                :     /*
                              17139                 :                :      * Check the tuple descriptors for compatibility.  Unlike inheritance, we
                              17140                 :                :      * require that the order also match.  However, attnotnull need not match.
                              17141                 :                :      */
 4743 rhaas@postgresql.org    17142                 :             30 :     typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
                              17143                 :             30 :     tableTupleDesc = RelationGetDescr(rel);
                              17144                 :             30 :     table_attno = 1;
                              17145         [ +  + ]:             95 :     for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
                              17146                 :                :     {
                              17147                 :                :         Form_pg_attribute type_attr,
                              17148                 :                :                     table_attr;
                              17149                 :                :         const char *type_attname,
                              17150                 :                :                    *table_attname;
                              17151                 :                : 
                              17152                 :                :         /* Get the next non-dropped type attribute. */
 2429 andres@anarazel.de      17153                 :             77 :         type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
 4743 rhaas@postgresql.org    17154         [ +  + ]:             77 :         if (type_attr->attisdropped)
                              17155                 :             22 :             continue;
                              17156                 :             55 :         type_attname = NameStr(type_attr->attname);
                              17157                 :                : 
                              17158                 :                :         /* Get the next non-dropped table attribute. */
                              17159                 :                :         do
                              17160                 :                :         {
                              17161         [ +  + ]:             61 :             if (table_attno > tableTupleDesc->natts)
                              17162         [ +  - ]:              3 :                 ereport(ERROR,
                              17163                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              17164                 :                :                          errmsg("table is missing column \"%s\"",
                              17165                 :                :                                 type_attname)));
 2429 andres@anarazel.de      17166                 :             58 :             table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
                              17167                 :             58 :             table_attno++;
 4743 rhaas@postgresql.org    17168         [ +  + ]:             58 :         } while (table_attr->attisdropped);
                              17169                 :             52 :         table_attname = NameStr(table_attr->attname);
                              17170                 :                : 
                              17171                 :                :         /* Compare name. */
                              17172         [ +  + ]:             52 :         if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
                              17173         [ +  - ]:              3 :             ereport(ERROR,
                              17174                 :                :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              17175                 :                :                      errmsg("table has column \"%s\" where type requires \"%s\"",
                              17176                 :                :                             table_attname, type_attname)));
                              17177                 :                : 
                              17178                 :                :         /* Compare type. */
                              17179         [ +  + ]:             49 :         if (table_attr->atttypid != type_attr->atttypid ||
                              17180         [ +  + ]:             46 :             table_attr->atttypmod != type_attr->atttypmod ||
                              17181         [ -  + ]:             43 :             table_attr->attcollation != type_attr->attcollation)
                              17182         [ +  - ]:              6 :             ereport(ERROR,
                              17183                 :                :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              17184                 :                :                      errmsg("table \"%s\" has different type for column \"%s\"",
                              17185                 :                :                             RelationGetRelationName(rel), type_attname)));
                              17186                 :                :     }
  851 tgl@sss.pgh.pa.us       17187         [ +  - ]:             18 :     ReleaseTupleDesc(typeTupleDesc);
                              17188                 :                : 
                              17189                 :                :     /* Any remaining columns at the end of the table had better be dropped. */
 4743 rhaas@postgresql.org    17190         [ +  + ]:             18 :     for (; table_attno <= tableTupleDesc->natts; table_attno++)
                              17191                 :                :     {
 2429 andres@anarazel.de      17192                 :              3 :         Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
                              17193                 :                :                                                      table_attno - 1);
                              17194                 :                : 
 4743 rhaas@postgresql.org    17195         [ +  - ]:              3 :         if (!table_attr->attisdropped)
                              17196         [ +  - ]:              3 :             ereport(ERROR,
                              17197                 :                :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              17198                 :                :                      errmsg("table has extra column \"%s\"",
                              17199                 :                :                             NameStr(table_attr->attname))));
                              17200                 :                :     }
                              17201                 :                : 
                              17202                 :                :     /* If the table was already typed, drop the existing dependency. */
                              17203         [ +  + ]:             15 :     if (rel->rd_rel->reloftype)
 2497                         17204                 :              3 :         drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
                              17205                 :                :                                DEPENDENCY_NORMAL);
                              17206                 :                : 
                              17207                 :                :     /* Record a dependency on the new type. */
 4743                         17208                 :             15 :     tableobj.classId = RelationRelationId;
                              17209                 :             15 :     tableobj.objectId = relid;
                              17210                 :             15 :     tableobj.objectSubId = 0;
                              17211                 :             15 :     typeobj.classId = TypeRelationId;
                              17212                 :             15 :     typeobj.objectId = typeid;
                              17213                 :             15 :     typeobj.objectSubId = 0;
                              17214                 :             15 :     recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
                              17215                 :                : 
                              17216                 :                :     /* Update pg_class.reloftype */
 1910 andres@anarazel.de      17217                 :             15 :     relationRelation = table_open(RelationRelationId, RowExclusiveLock);
 4743 rhaas@postgresql.org    17218                 :             15 :     classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
                              17219         [ -  + ]:             15 :     if (!HeapTupleIsValid(classtuple))
 4743 rhaas@postgresql.org    17220         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
 4743 rhaas@postgresql.org    17221                 :CBC          15 :     ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
 2630 alvherre@alvh.no-ip.    17222                 :             15 :     CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
                              17223                 :                : 
 4046 rhaas@postgresql.org    17224         [ -  + ]:             15 :     InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
                              17225                 :                : 
 4743                         17226                 :             15 :     heap_freetuple(classtuple);
 1910 andres@anarazel.de      17227                 :             15 :     table_close(relationRelation, RowExclusiveLock);
                              17228                 :                : 
 4743 rhaas@postgresql.org    17229                 :             15 :     ReleaseSysCache(typetuple);
                              17230                 :                : 
 3308 alvherre@alvh.no-ip.    17231                 :             15 :     return typeobj;
                              17232                 :                : }
                              17233                 :                : 
                              17234                 :                : /*
                              17235                 :                :  * ALTER TABLE NOT OF
                              17236                 :                :  *
                              17237                 :                :  * Detach a typed table from its originating type.  Just clear reloftype and
                              17238                 :                :  * remove the dependency.
                              17239                 :                :  */
                              17240                 :                : static void
 4743 rhaas@postgresql.org    17241                 :              3 : ATExecDropOf(Relation rel, LOCKMODE lockmode)
                              17242                 :                : {
                              17243                 :              3 :     Oid         relid = RelationGetRelid(rel);
                              17244                 :                :     Relation    relationRelation;
                              17245                 :                :     HeapTuple   tuple;
                              17246                 :                : 
                              17247         [ -  + ]:              3 :     if (!OidIsValid(rel->rd_rel->reloftype))
 4743 rhaas@postgresql.org    17248         [ #  # ]:UBC           0 :         ereport(ERROR,
                              17249                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17250                 :                :                  errmsg("\"%s\" is not a typed table",
                              17251                 :                :                         RelationGetRelationName(rel))));
                              17252                 :                : 
                              17253                 :                :     /*
                              17254                 :                :      * We don't bother to check ownership of the type --- ownership of the
                              17255                 :                :      * table is presumed enough rights.  No lock required on the type, either.
                              17256                 :                :      */
                              17257                 :                : 
 2497 rhaas@postgresql.org    17258                 :CBC           3 :     drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
                              17259                 :                :                            DEPENDENCY_NORMAL);
                              17260                 :                : 
                              17261                 :                :     /* Clear pg_class.reloftype */
 1910 andres@anarazel.de      17262                 :              3 :     relationRelation = table_open(RelationRelationId, RowExclusiveLock);
 4743 rhaas@postgresql.org    17263                 :              3 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
                              17264         [ -  + ]:              3 :     if (!HeapTupleIsValid(tuple))
 4743 rhaas@postgresql.org    17265         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
 4743 rhaas@postgresql.org    17266                 :CBC           3 :     ((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
 2630 alvherre@alvh.no-ip.    17267                 :              3 :     CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
                              17268                 :                : 
 4046 rhaas@postgresql.org    17269         [ -  + ]:              3 :     InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
                              17270                 :                : 
 4743                         17271                 :              3 :     heap_freetuple(tuple);
 1910 andres@anarazel.de      17272                 :              3 :     table_close(relationRelation, RowExclusiveLock);
 6496 bruce@momjian.us        17273                 :              3 : }
                              17274                 :                : 
                              17275                 :                : /*
                              17276                 :                :  * relation_mark_replica_identity: Update a table's replica identity
                              17277                 :                :  *
                              17278                 :                :  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
                              17279                 :                :  * index. Otherwise, it must be InvalidOid.
                              17280                 :                :  *
                              17281                 :                :  * Caller had better hold an exclusive lock on the relation, as the results
                              17282                 :                :  * of running two of these concurrently wouldn't be pretty.
                              17283                 :                :  */
                              17284                 :                : static void
 3810 rhaas@postgresql.org    17285                 :            200 : relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
                              17286                 :                :                                bool is_internal)
                              17287                 :                : {
                              17288                 :                :     Relation    pg_index;
                              17289                 :                :     Relation    pg_class;
                              17290                 :                :     HeapTuple   pg_class_tuple;
                              17291                 :                :     HeapTuple   pg_index_tuple;
                              17292                 :                :     Form_pg_class pg_class_form;
                              17293                 :                :     Form_pg_index pg_index_form;
                              17294                 :                :     ListCell   *index;
                              17295                 :                : 
                              17296                 :                :     /*
                              17297                 :                :      * Check whether relreplident has changed, and update it if so.
                              17298                 :                :      */
 1910 andres@anarazel.de      17299                 :            200 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
 3810 rhaas@postgresql.org    17300                 :            200 :     pg_class_tuple = SearchSysCacheCopy1(RELOID,
                              17301                 :                :                                          ObjectIdGetDatum(RelationGetRelid(rel)));
                              17302         [ -  + ]:            200 :     if (!HeapTupleIsValid(pg_class_tuple))
 3810 rhaas@postgresql.org    17303         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation \"%s\"",
                              17304                 :                :              RelationGetRelationName(rel));
 3810 rhaas@postgresql.org    17305                 :CBC         200 :     pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
                              17306         [ +  + ]:            200 :     if (pg_class_form->relreplident != ri_type)
                              17307                 :                :     {
                              17308                 :            175 :         pg_class_form->relreplident = ri_type;
 2630 alvherre@alvh.no-ip.    17309                 :            175 :         CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
                              17310                 :                :     }
 1910 andres@anarazel.de      17311                 :            200 :     table_close(pg_class, RowExclusiveLock);
 3810 rhaas@postgresql.org    17312                 :            200 :     heap_freetuple(pg_class_tuple);
                              17313                 :                : 
                              17314                 :                :     /*
                              17315                 :                :      * Update the per-index indisreplident flags correctly.
                              17316                 :                :      */
 1910 andres@anarazel.de      17317                 :            200 :     pg_index = table_open(IndexRelationId, RowExclusiveLock);
 3810 rhaas@postgresql.org    17318   [ +  +  +  +  :            539 :     foreach(index, RelationGetIndexList(rel))
                                              +  + ]
                              17319                 :                :     {
                              17320                 :            339 :         Oid         thisIndexOid = lfirst_oid(index);
                              17321                 :            339 :         bool        dirty = false;
                              17322                 :                : 
                              17323                 :            339 :         pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
                              17324                 :                :                                              ObjectIdGetDatum(thisIndexOid));
                              17325         [ -  + ]:            339 :         if (!HeapTupleIsValid(pg_index_tuple))
 3810 rhaas@postgresql.org    17326         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
 3810 rhaas@postgresql.org    17327                 :CBC         339 :         pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
                              17328                 :                : 
  449 tgl@sss.pgh.pa.us       17329         [ +  + ]:            339 :         if (thisIndexOid == indexOid)
                              17330                 :                :         {
                              17331                 :                :             /* Set the bit if not already set. */
                              17332         [ +  + ]:            110 :             if (!pg_index_form->indisreplident)
                              17333                 :                :             {
                              17334                 :            101 :                 dirty = true;
                              17335                 :            101 :                 pg_index_form->indisreplident = true;
                              17336                 :                :             }
                              17337                 :                :         }
                              17338                 :                :         else
                              17339                 :                :         {
                              17340                 :                :             /* Unset the bit if set. */
                              17341         [ +  + ]:            229 :             if (pg_index_form->indisreplident)
                              17342                 :                :             {
                              17343                 :             23 :                 dirty = true;
                              17344                 :             23 :                 pg_index_form->indisreplident = false;
                              17345                 :                :             }
                              17346                 :                :         }
                              17347                 :                : 
 3810 rhaas@postgresql.org    17348         [ +  + ]:            339 :         if (dirty)
                              17349                 :                :         {
 2630 alvherre@alvh.no-ip.    17350                 :            124 :             CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
 3810 rhaas@postgresql.org    17351         [ -  + ]:            124 :             InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
                              17352                 :                :                                          InvalidOid, is_internal);
                              17353                 :                : 
                              17354                 :                :             /*
                              17355                 :                :              * Invalidate the relcache for the table, so that after we commit
                              17356                 :                :              * all sessions will refresh the table's replica identity index
                              17357                 :                :              * before attempting any UPDATE or DELETE on the table.  (If we
                              17358                 :                :              * changed the table's pg_class row above, then a relcache inval
                              17359                 :                :              * is already queued due to that; but we might not have.)
                              17360                 :                :              */
  880 akapila@postgresql.o    17361                 :            124 :             CacheInvalidateRelcache(rel);
                              17362                 :                :         }
 3810 rhaas@postgresql.org    17363                 :            339 :         heap_freetuple(pg_index_tuple);
                              17364                 :                :     }
                              17365                 :                : 
 1910 andres@anarazel.de      17366                 :            200 :     table_close(pg_index, RowExclusiveLock);
 3810 rhaas@postgresql.org    17367                 :            200 : }
                              17368                 :                : 
                              17369                 :                : /*
                              17370                 :                :  * ALTER TABLE <name> REPLICA IDENTITY ...
                              17371                 :                :  */
                              17372                 :                : static void
                              17373                 :            224 : ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
                              17374                 :                : {
                              17375                 :                :     Oid         indexOid;
                              17376                 :                :     Relation    indexRel;
                              17377                 :                :     int         key;
                              17378                 :                : 
                              17379         [ +  + ]:            224 :     if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
                              17380                 :                :     {
                              17381                 :              3 :         relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
                              17382                 :              3 :         return;
                              17383                 :                :     }
                              17384         [ +  + ]:            221 :     else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
                              17385                 :                :     {
                              17386                 :             69 :         relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
                              17387                 :             69 :         return;
                              17388                 :                :     }
                              17389         [ +  + ]:            152 :     else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
                              17390                 :                :     {
                              17391                 :             18 :         relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
                              17392                 :             18 :         return;
                              17393                 :                :     }
                              17394         [ -  + ]:            134 :     else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
                              17395                 :                :     {
                              17396                 :                :          /* fallthrough */ ;
                              17397                 :                :     }
                              17398                 :                :     else
 3810 rhaas@postgresql.org    17399         [ #  # ]:UBC           0 :         elog(ERROR, "unexpected identity type %u", stmt->identity_type);
                              17400                 :                : 
                              17401                 :                :     /* Check that the index exists */
 3810 rhaas@postgresql.org    17402                 :CBC         134 :     indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
                              17403         [ -  + ]:            134 :     if (!OidIsValid(indexOid))
 3810 rhaas@postgresql.org    17404         [ #  # ]:UBC           0 :         ereport(ERROR,
                              17405                 :                :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              17406                 :                :                  errmsg("index \"%s\" for table \"%s\" does not exist",
                              17407                 :                :                         stmt->name, RelationGetRelationName(rel))));
                              17408                 :                : 
 3810 rhaas@postgresql.org    17409                 :CBC         134 :     indexRel = index_open(indexOid, ShareLock);
                              17410                 :                : 
                              17411                 :                :     /* Check that the index is on the relation we're altering. */
                              17412         [ +  - ]:            134 :     if (indexRel->rd_index == NULL ||
                              17413         [ +  + ]:            134 :         indexRel->rd_index->indrelid != RelationGetRelid(rel))
                              17414         [ +  - ]:              3 :         ereport(ERROR,
                              17415                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17416                 :                :                  errmsg("\"%s\" is not an index for table \"%s\"",
                              17417                 :                :                         RelationGetRelationName(indexRel),
                              17418                 :                :                         RelationGetRelationName(rel))));
                              17419                 :                :     /* The AM must support uniqueness, and the index must in fact be unique. */
 1910 andres@anarazel.de      17420         [ +  + ]:            131 :     if (!indexRel->rd_indam->amcanunique ||
 3010 tgl@sss.pgh.pa.us       17421         [ +  + ]:            128 :         !indexRel->rd_index->indisunique)
 3810 rhaas@postgresql.org    17422         [ +  - ]:              6 :         ereport(ERROR,
                              17423                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17424                 :                :                  errmsg("cannot use non-unique index \"%s\" as replica identity",
                              17425                 :                :                         RelationGetRelationName(indexRel))));
                              17426                 :                :     /* Deferred indexes are not guaranteed to be always unique. */
                              17427         [ +  + ]:            125 :     if (!indexRel->rd_index->indimmediate)
                              17428         [ +  - ]:              6 :         ereport(ERROR,
                              17429                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              17430                 :                :                  errmsg("cannot use non-immediate index \"%s\" as replica identity",
                              17431                 :                :                         RelationGetRelationName(indexRel))));
                              17432                 :                :     /* Expression indexes aren't supported. */
                              17433         [ +  + ]:            119 :     if (RelationGetIndexExpressions(indexRel) != NIL)
                              17434         [ +  - ]:              3 :         ereport(ERROR,
                              17435                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              17436                 :                :                  errmsg("cannot use expression index \"%s\" as replica identity",
                              17437                 :                :                         RelationGetRelationName(indexRel))));
                              17438                 :                :     /* Predicate indexes aren't supported. */
                              17439         [ +  + ]:            116 :     if (RelationGetIndexPredicate(indexRel) != NIL)
                              17440         [ +  - ]:              3 :         ereport(ERROR,
                              17441                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              17442                 :                :                  errmsg("cannot use partial index \"%s\" as replica identity",
                              17443                 :                :                         RelationGetRelationName(indexRel))));
                              17444                 :                : 
                              17445                 :                :     /* Check index for nullable columns. */
 2199 teodor@sigaev.ru        17446         [ +  + ]:            249 :     for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
                              17447                 :                :     {
 3631 bruce@momjian.us        17448                 :            139 :         int16       attno = indexRel->rd_index->indkey.values[key];
                              17449                 :                :         Form_pg_attribute attr;
                              17450                 :                : 
                              17451                 :                :         /*
                              17452                 :                :          * Reject any other system columns.  (Going forward, we'll disallow
                              17453                 :                :          * indexes containing such columns in the first place, but they might
                              17454                 :                :          * exist in older branches.)
                              17455                 :                :          */
 2921 tgl@sss.pgh.pa.us       17456         [ -  + ]:            139 :         if (attno <= 0)
 2921 tgl@sss.pgh.pa.us       17457         [ #  # ]:UBC           0 :             ereport(ERROR,
                              17458                 :                :                     (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                              17459                 :                :                      errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
                              17460                 :                :                             RelationGetRelationName(indexRel), attno)));
                              17461                 :                : 
 2429 andres@anarazel.de      17462                 :CBC         139 :         attr = TupleDescAttr(rel->rd_att, attno - 1);
 3810 rhaas@postgresql.org    17463         [ +  + ]:            139 :         if (!attr->attnotnull)
                              17464         [ +  - ]:              3 :             ereport(ERROR,
                              17465                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              17466                 :                :                      errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
                              17467                 :                :                             RelationGetRelationName(indexRel),
                              17468                 :                :                             NameStr(attr->attname))));
                              17469                 :                :     }
                              17470                 :                : 
                              17471                 :                :     /* This index is suitable for use as a replica identity. Mark it. */
                              17472                 :            110 :     relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
                              17473                 :                : 
                              17474                 :            110 :     index_close(indexRel, NoLock);
                              17475                 :                : }
                              17476                 :                : 
                              17477                 :                : /*
                              17478                 :                :  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
                              17479                 :                :  */
                              17480                 :                : static void
 1139 michael@paquier.xyz     17481                 :            144 : ATExecSetRowSecurity(Relation rel, bool rls)
                              17482                 :                : {
                              17483                 :                :     Relation    pg_class;
                              17484                 :                :     Oid         relid;
                              17485                 :                :     HeapTuple   tuple;
                              17486                 :                : 
 3495 sfrost@snowman.net      17487                 :            144 :     relid = RelationGetRelid(rel);
                              17488                 :                : 
                              17489                 :                :     /* Pull the record for this relation and update it */
 1910 andres@anarazel.de      17490                 :            144 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
                              17491                 :                : 
 3495 sfrost@snowman.net      17492                 :            144 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
                              17493                 :                : 
                              17494         [ -  + ]:            144 :     if (!HeapTupleIsValid(tuple))
 3495 sfrost@snowman.net      17495         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
                              17496                 :                : 
 1139 michael@paquier.xyz     17497                 :CBC         144 :     ((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls;
 2630 alvherre@alvh.no-ip.    17498                 :            144 :     CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
                              17499                 :                : 
  241 michael@paquier.xyz     17500         [ +  + ]:GNC         144 :     InvokeObjectPostAlterHook(RelationRelationId,
                              17501                 :                :                               RelationGetRelid(rel), 0);
                              17502                 :                : 
 1910 andres@anarazel.de      17503                 :CBC         144 :     table_close(pg_class, RowExclusiveLock);
 3115 sfrost@snowman.net      17504                 :            144 :     heap_freetuple(tuple);
                              17505                 :            144 : }
                              17506                 :                : 
                              17507                 :                : /*
                              17508                 :                :  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
                              17509                 :                :  */
                              17510                 :                : static void
                              17511                 :             57 : ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
                              17512                 :                : {
                              17513                 :                :     Relation    pg_class;
                              17514                 :                :     Oid         relid;
                              17515                 :                :     HeapTuple   tuple;
                              17516                 :                : 
                              17517                 :             57 :     relid = RelationGetRelid(rel);
                              17518                 :                : 
 1910 andres@anarazel.de      17519                 :             57 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
                              17520                 :                : 
 3115 sfrost@snowman.net      17521                 :             57 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
                              17522                 :                : 
                              17523         [ -  + ]:             57 :     if (!HeapTupleIsValid(tuple))
 3115 sfrost@snowman.net      17524         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
                              17525                 :                : 
 3115 sfrost@snowman.net      17526                 :CBC          57 :     ((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
 2630 alvherre@alvh.no-ip.    17527                 :             57 :     CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
                              17528                 :                : 
  241 michael@paquier.xyz     17529         [ +  + ]:GNC          57 :     InvokeObjectPostAlterHook(RelationRelationId,
                              17530                 :                :                               RelationGetRelid(rel), 0);
                              17531                 :                : 
 1910 andres@anarazel.de      17532                 :CBC          57 :     table_close(pg_class, RowExclusiveLock);
 3495 sfrost@snowman.net      17533                 :             57 :     heap_freetuple(tuple);
                              17534                 :             57 : }
                              17535                 :                : 
                              17536                 :                : /*
                              17537                 :                :  * ALTER FOREIGN TABLE <name> OPTIONS (...)
                              17538                 :                :  */
                              17539                 :                : static void
 4852 rhaas@postgresql.org    17540                 :             25 : ATExecGenericOptions(Relation rel, List *options)
                              17541                 :                : {
                              17542                 :                :     Relation    ftrel;
                              17543                 :                :     ForeignServer *server;
                              17544                 :                :     ForeignDataWrapper *fdw;
                              17545                 :                :     HeapTuple   tuple;
                              17546                 :                :     bool        isnull;
                              17547                 :                :     Datum       repl_val[Natts_pg_foreign_table];
                              17548                 :                :     bool        repl_null[Natts_pg_foreign_table];
                              17549                 :                :     bool        repl_repl[Natts_pg_foreign_table];
                              17550                 :                :     Datum       datum;
                              17551                 :                :     Form_pg_foreign_table tableform;
                              17552                 :                : 
 4753 bruce@momjian.us        17553         [ -  + ]:             25 :     if (options == NIL)
 4852 rhaas@postgresql.org    17554                 :UBC           0 :         return;
                              17555                 :                : 
 1910 andres@anarazel.de      17556                 :CBC          25 :     ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
                              17557                 :                : 
  269 michael@paquier.xyz     17558                 :GNC          25 :     tuple = SearchSysCacheCopy1(FOREIGNTABLEREL,
                              17559                 :                :                                 ObjectIdGetDatum(rel->rd_id));
 4852 rhaas@postgresql.org    17560         [ -  + ]:CBC          25 :     if (!HeapTupleIsValid(tuple))
 4852 rhaas@postgresql.org    17561         [ #  # ]:UBC           0 :         ereport(ERROR,
                              17562                 :                :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              17563                 :                :                  errmsg("foreign table \"%s\" does not exist",
                              17564                 :                :                         RelationGetRelationName(rel))));
 4852 rhaas@postgresql.org    17565                 :CBC          25 :     tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
                              17566                 :             25 :     server = GetForeignServer(tableform->ftserver);
                              17567                 :             25 :     fdw = GetForeignDataWrapper(server->fdwid);
                              17568                 :                : 
                              17569                 :             25 :     memset(repl_val, 0, sizeof(repl_val));
                              17570                 :             25 :     memset(repl_null, false, sizeof(repl_null));
                              17571                 :             25 :     memset(repl_repl, false, sizeof(repl_repl));
                              17572                 :                : 
                              17573                 :                :     /* Extract the current options */
                              17574                 :             25 :     datum = SysCacheGetAttr(FOREIGNTABLEREL,
                              17575                 :                :                             tuple,
                              17576                 :                :                             Anum_pg_foreign_table_ftoptions,
                              17577                 :                :                             &isnull);
                              17578         [ +  + ]:             25 :     if (isnull)
                              17579                 :              2 :         datum = PointerGetDatum(NULL);
                              17580                 :                : 
                              17581                 :                :     /* Transform the options */
                              17582                 :             25 :     datum = transformGenericOptions(ForeignTableRelationId,
                              17583                 :                :                                     datum,
                              17584                 :                :                                     options,
                              17585                 :                :                                     fdw->fdwvalidator);
                              17586                 :                : 
                              17587         [ +  - ]:             24 :     if (PointerIsValid(DatumGetPointer(datum)))
                              17588                 :             24 :         repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
                              17589                 :                :     else
 4852 rhaas@postgresql.org    17590                 :UBC           0 :         repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
                              17591                 :                : 
 4852 rhaas@postgresql.org    17592                 :CBC          24 :     repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
                              17593                 :                : 
                              17594                 :                :     /* Everything looks good - update the tuple */
                              17595                 :                : 
                              17596                 :             24 :     tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
                              17597                 :                :                               repl_val, repl_null, repl_repl);
                              17598                 :                : 
 2630 alvherre@alvh.no-ip.    17599                 :             24 :     CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
                              17600                 :                : 
                              17601                 :                :     /*
                              17602                 :                :      * Invalidate relcache so that all sessions will refresh any cached plans
                              17603                 :                :      * that might depend on the old options.
                              17604                 :                :      */
 2655 tgl@sss.pgh.pa.us       17605                 :             24 :     CacheInvalidateRelcache(rel);
                              17606                 :                : 
 4046 rhaas@postgresql.org    17607         [ -  + ]:             24 :     InvokeObjectPostAlterHook(ForeignTableRelationId,
                              17608                 :                :                               RelationGetRelid(rel), 0);
                              17609                 :                : 
 1910 andres@anarazel.de      17610                 :             24 :     table_close(ftrel, RowExclusiveLock);
                              17611                 :                : 
 4852 rhaas@postgresql.org    17612                 :             24 :     heap_freetuple(tuple);
                              17613                 :                : }
                              17614                 :                : 
                              17615                 :                : /*
                              17616                 :                :  * ALTER TABLE ALTER COLUMN SET COMPRESSION
                              17617                 :                :  *
                              17618                 :                :  * Return value is the address of the modified column
                              17619                 :                :  */
                              17620                 :                : static ObjectAddress
  641 peter@eisentraut.org    17621                 :             33 : ATExecSetCompression(Relation rel,
                              17622                 :                :                      const char *column,
                              17623                 :                :                      Node *newValue,
                              17624                 :                :                      LOCKMODE lockmode)
                              17625                 :                : {
                              17626                 :                :     Relation    attrel;
                              17627                 :                :     HeapTuple   tuple;
                              17628                 :                :     Form_pg_attribute atttableform;
                              17629                 :                :     AttrNumber  attnum;
                              17630                 :                :     char       *compression;
                              17631                 :                :     char        cmethod;
                              17632                 :                :     ObjectAddress address;
                              17633                 :                : 
 1122 rhaas@postgresql.org    17634                 :             33 :     compression = strVal(newValue);
                              17635                 :                : 
                              17636                 :             33 :     attrel = table_open(AttributeRelationId, RowExclusiveLock);
                              17637                 :                : 
                              17638                 :                :     /* copy the cache entry so we can scribble on it below */
 1120 tgl@sss.pgh.pa.us       17639                 :             33 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), column);
 1122 rhaas@postgresql.org    17640         [ -  + ]:             33 :     if (!HeapTupleIsValid(tuple))
 1122 rhaas@postgresql.org    17641         [ #  # ]:UBC           0 :         ereport(ERROR,
                              17642                 :                :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
                              17643                 :                :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
                              17644                 :                :                         column, RelationGetRelationName(rel))));
                              17645                 :                : 
                              17646                 :                :     /* prevent them from altering a system attribute */
 1122 rhaas@postgresql.org    17647                 :CBC          33 :     atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
                              17648                 :             33 :     attnum = atttableform->attnum;
                              17649         [ -  + ]:             33 :     if (attnum <= 0)
 1122 rhaas@postgresql.org    17650         [ #  # ]:UBC           0 :         ereport(ERROR,
                              17651                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              17652                 :                :                  errmsg("cannot alter system column \"%s\"", column)));
                              17653                 :                : 
                              17654                 :                :     /*
                              17655                 :                :      * Check that column type is compressible, then get the attribute
                              17656                 :                :      * compression method code
                              17657                 :                :      */
 1053 tgl@sss.pgh.pa.us       17658                 :CBC          33 :     cmethod = GetAttributeCompression(atttableform->atttypid, compression);
                              17659                 :                : 
                              17660                 :                :     /* update pg_attribute entry */
 1119 rhaas@postgresql.org    17661                 :             30 :     atttableform->attcompression = cmethod;
 1122                         17662                 :             30 :     CatalogTupleUpdate(attrel, &tuple->t_self, tuple);
                              17663                 :                : 
                              17664         [ -  + ]:             30 :     InvokeObjectPostAlterHook(RelationRelationId,
                              17665                 :                :                               RelationGetRelid(rel),
                              17666                 :                :                               attnum);
                              17667                 :                : 
                              17668                 :                :     /*
                              17669                 :                :      * Apply the change to indexes as well (only for simple index columns,
                              17670                 :                :      * matching behavior of index.c ConstructTupleDescriptor()).
                              17671                 :                :      */
 1053 tgl@sss.pgh.pa.us       17672                 :             30 :     SetIndexStorageProperties(rel, attrel, attnum,
                              17673                 :                :                               false, 0,
                              17674                 :                :                               true, cmethod,
                              17675                 :                :                               lockmode);
                              17676                 :                : 
 1120                         17677                 :             30 :     heap_freetuple(tuple);
                              17678                 :                : 
 1122 rhaas@postgresql.org    17679                 :             30 :     table_close(attrel, RowExclusiveLock);
                              17680                 :                : 
                              17681                 :                :     /* make changes visible */
                              17682                 :             30 :     CommandCounterIncrement();
                              17683                 :                : 
                              17684                 :             30 :     ObjectAddressSubSet(address, RelationRelationId,
                              17685                 :                :                         RelationGetRelid(rel), attnum);
                              17686                 :             30 :     return address;
                              17687                 :                : }
                              17688                 :                : 
                              17689                 :                : 
                              17690                 :                : /*
                              17691                 :                :  * Preparation phase for SET LOGGED/UNLOGGED
                              17692                 :                :  *
                              17693                 :                :  * This verifies that we're not trying to change a temp table.  Also,
                              17694                 :                :  * existing foreign key constraints are checked to avoid ending up with
                              17695                 :                :  * permanent tables referencing unlogged tables.
                              17696                 :                :  *
                              17697                 :                :  * Return value is false if the operation is a no-op (in which case the
                              17698                 :                :  * checks are skipped), otherwise true.
                              17699                 :                :  */
                              17700                 :                : static bool
 3520 alvherre@alvh.no-ip.    17701                 :             44 : ATPrepChangePersistence(Relation rel, bool toLogged)
                              17702                 :                : {
                              17703                 :                :     Relation    pg_constraint;
                              17704                 :                :     HeapTuple   tuple;
                              17705                 :                :     SysScanDesc scan;
                              17706                 :                :     ScanKeyData skey[1];
                              17707                 :                : 
                              17708                 :                :     /*
                              17709                 :                :      * Disallow changing status for a temp table.  Also verify whether we can
                              17710                 :                :      * get away with doing nothing; in such cases we don't need to run the
                              17711                 :                :      * checks below, either.
                              17712                 :                :      */
 3523                         17713   [ -  +  +  - ]:             44 :     switch (rel->rd_rel->relpersistence)
                              17714                 :                :     {
 3523 alvherre@alvh.no-ip.    17715                 :UBC           0 :         case RELPERSISTENCE_TEMP:
                              17716         [ #  # ]:              0 :             ereport(ERROR,
                              17717                 :                :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              17718                 :                :                      errmsg("cannot change logged status of table \"%s\" because it is temporary",
                              17719                 :                :                             RelationGetRelationName(rel)),
                              17720                 :                :                      errtable(rel)));
                              17721                 :                :             break;
 3523 alvherre@alvh.no-ip.    17722                 :CBC          25 :         case RELPERSISTENCE_PERMANENT:
                              17723         [ +  + ]:             25 :             if (toLogged)
                              17724                 :                :                 /* nothing to do */
                              17725                 :              3 :                 return false;
                              17726                 :             22 :             break;
                              17727                 :             19 :         case RELPERSISTENCE_UNLOGGED:
                              17728         [ +  + ]:             19 :             if (!toLogged)
                              17729                 :                :                 /* nothing to do */
                              17730                 :              3 :                 return false;
                              17731                 :             16 :             break;
                              17732                 :                :     }
                              17733                 :                : 
                              17734                 :                :     /*
                              17735                 :                :      * Check that the table is not part of any publication when changing to
                              17736                 :                :      * UNLOGGED, as UNLOGGED tables can't be published.
                              17737                 :                :      */
 2642 peter_e@gmx.net         17738   [ +  +  -  + ]:             60 :     if (!toLogged &&
  606 tgl@sss.pgh.pa.us       17739                 :             22 :         GetRelationPublications(RelationGetRelid(rel)) != NIL)
 2642 peter_e@gmx.net         17740         [ #  # ]:UBC           0 :         ereport(ERROR,
                              17741                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              17742                 :                :                  errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
                              17743                 :                :                         RelationGetRelationName(rel)),
                              17744                 :                :                  errdetail("Unlogged relations cannot be replicated.")));
                              17745                 :                : 
                              17746                 :                :     /*
                              17747                 :                :      * Check existing foreign key constraints to preserve the invariant that
                              17748                 :                :      * permanent tables cannot reference unlogged ones.  Self-referencing
                              17749                 :                :      * foreign keys can safely be ignored.
                              17750                 :                :      */
 1910 andres@anarazel.de      17751                 :CBC          38 :     pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
                              17752                 :                : 
                              17753                 :                :     /*
                              17754                 :                :      * Scan conrelid if changing to permanent, else confrelid.  This also
                              17755                 :                :      * determines whether a useful index exists.
                              17756                 :                :      */
 3523 alvherre@alvh.no-ip.    17757         [ +  + ]:             38 :     ScanKeyInit(&skey[0],
                              17758                 :                :                 toLogged ? Anum_pg_constraint_conrelid :
                              17759                 :                :                 Anum_pg_constraint_confrelid,
                              17760                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              17761                 :                :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                              17762         [ +  + ]:             38 :     scan = systable_beginscan(pg_constraint,
                              17763                 :                :                               toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
                              17764                 :                :                               true, NULL, 1, skey);
                              17765                 :                : 
                              17766         [ +  + ]:             65 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
                              17767                 :                :     {
                              17768                 :             33 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
                              17769                 :                : 
                              17770         [ +  + ]:             33 :         if (con->contype == CONSTRAINT_FOREIGN)
                              17771                 :                :         {
                              17772                 :                :             Oid         foreignrelid;
                              17773                 :                :             Relation    foreignrel;
                              17774                 :                : 
                              17775                 :                :             /* the opposite end of what we used as scankey */
                              17776         [ +  + ]:             15 :             foreignrelid = toLogged ? con->confrelid : con->conrelid;
                              17777                 :                : 
                              17778                 :                :             /* ignore if self-referencing */
                              17779         [ +  + ]:             15 :             if (RelationGetRelid(rel) == foreignrelid)
                              17780                 :              6 :                 continue;
                              17781                 :                : 
                              17782                 :              9 :             foreignrel = relation_open(foreignrelid, AccessShareLock);
                              17783                 :                : 
                              17784         [ +  + ]:              9 :             if (toLogged)
                              17785                 :                :             {
 1119 bruce@momjian.us        17786         [ +  - ]:              3 :                 if (!RelationIsPermanent(foreignrel))
 3523 alvherre@alvh.no-ip.    17787         [ +  - ]:              3 :                     ereport(ERROR,
                              17788                 :                :                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              17789                 :                :                              errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
                              17790                 :                :                                     RelationGetRelationName(rel),
                              17791                 :                :                                     RelationGetRelationName(foreignrel)),
                              17792                 :                :                              errtableconstraint(rel, NameStr(con->conname))));
                              17793                 :                :             }
                              17794                 :                :             else
                              17795                 :                :             {
 1119 bruce@momjian.us        17796         [ +  + ]:              6 :                 if (RelationIsPermanent(foreignrel))
 3523 alvherre@alvh.no-ip.    17797         [ +  - ]:              3 :                     ereport(ERROR,
                              17798                 :                :                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              17799                 :                :                              errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
                              17800                 :                :                                     RelationGetRelationName(rel),
                              17801                 :                :                                     RelationGetRelationName(foreignrel)),
                              17802                 :                :                              errtableconstraint(rel, NameStr(con->conname))));
                              17803                 :                :             }
                              17804                 :                : 
                              17805                 :              3 :             relation_close(foreignrel, AccessShareLock);
                              17806                 :                :         }
                              17807                 :                :     }
                              17808                 :                : 
                              17809                 :             32 :     systable_endscan(scan);
                              17810                 :                : 
 1910 andres@anarazel.de      17811                 :             32 :     table_close(pg_constraint, AccessShareLock);
                              17812                 :                : 
 3523 alvherre@alvh.no-ip.    17813                 :             32 :     return true;
                              17814                 :                : }
                              17815                 :                : 
                              17816                 :                : /*
                              17817                 :                :  * Execute ALTER TABLE SET SCHEMA
                              17818                 :                :  */
                              17819                 :                : ObjectAddress
 3330                         17820                 :             52 : AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
                              17821                 :                : {
                              17822                 :                :     Relation    rel;
                              17823                 :                :     Oid         relid;
                              17824                 :                :     Oid         oldNspOid;
                              17825                 :                :     Oid         nspOid;
                              17826                 :                :     RangeVar   *newrv;
                              17827                 :                :     ObjectAddresses *objsMoved;
                              17828                 :                :     ObjectAddress myself;
                              17829                 :                : 
 4482 rhaas@postgresql.org    17830                 :             52 :     relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
 2207 andres@anarazel.de      17831                 :             52 :                                      stmt->missing_ok ? RVR_MISSING_OK : 0,
                              17832                 :                :                                      RangeVarCallbackForAlterRelation,
                              17833                 :                :                                      (void *) stmt);
                              17834                 :                : 
 4465 simon@2ndQuadrant.co    17835         [ +  + ]:             51 :     if (!OidIsValid(relid))
                              17836                 :                :     {
                              17837         [ +  - ]:              6 :         ereport(NOTICE,
                              17838                 :                :                 (errmsg("relation \"%s\" does not exist, skipping",
                              17839                 :                :                         stmt->relation->relname)));
 3330 alvherre@alvh.no-ip.    17840                 :              6 :         return InvalidObjectAddress;
                              17841                 :                :     }
                              17842                 :                : 
 4504 rhaas@postgresql.org    17843                 :             45 :     rel = relation_open(relid, NoLock);
                              17844                 :                : 
                              17845                 :             45 :     oldNspOid = RelationGetNamespace(rel);
                              17846                 :                : 
                              17847                 :                :     /* If it's an owned sequence, disallow moving it by itself. */
                              17848         [ +  + ]:             45 :     if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
                              17849                 :                :     {
                              17850                 :                :         Oid         tableId;
                              17851                 :                :         int32       colId;
                              17852                 :                : 
 2565 peter_e@gmx.net         17853   [ +  +  -  + ]:              5 :         if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
                              17854                 :              1 :             sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
 4504 rhaas@postgresql.org    17855         [ +  - ]:              3 :             ereport(ERROR,
                              17856                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              17857                 :                :                      errmsg("cannot move an owned sequence into another schema"),
                              17858                 :                :                      errdetail("Sequence \"%s\" is linked to table \"%s\".",
                              17859                 :                :                                RelationGetRelationName(rel),
                              17860                 :                :                                get_rel_name(tableId))));
                              17861                 :                :     }
                              17862                 :                : 
                              17863                 :                :     /* Get and lock schema OID and check its permissions. */
 4472                         17864                 :             42 :     newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
                              17865                 :             42 :     nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
                              17866                 :                : 
                              17867                 :                :     /* common checks on switching namespaces */
 3069                         17868                 :             42 :     CheckSetNamespace(oldNspOid, nspOid);
                              17869                 :                : 
 4183 alvherre@alvh.no-ip.    17870                 :             42 :     objsMoved = new_object_addresses();
                              17871                 :             42 :     AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
                              17872                 :             42 :     free_object_addresses(objsMoved);
                              17873                 :                : 
 3330                         17874                 :             42 :     ObjectAddressSet(myself, RelationRelationId, relid);
                              17875                 :                : 
                              17876         [ +  - ]:             42 :     if (oldschema)
                              17877                 :             42 :         *oldschema = oldNspOid;
                              17878                 :                : 
                              17879                 :                :     /* close rel, but keep lock until commit */
 4183                         17880                 :             42 :     relation_close(rel, NoLock);
                              17881                 :                : 
 3330                         17882                 :             42 :     return myself;
                              17883                 :                : }
                              17884                 :                : 
                              17885                 :                : /*
                              17886                 :                :  * The guts of relocating a table or materialized view to another namespace:
                              17887                 :                :  * besides moving the relation itself, its dependent objects are relocated to
                              17888                 :                :  * the new schema.
                              17889                 :                :  */
                              17890                 :                : void
 4183                         17891                 :             42 : AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
                              17892                 :                :                             ObjectAddresses *objsMoved)
                              17893                 :                : {
                              17894                 :                :     Relation    classRel;
                              17895                 :                : 
                              17896         [ -  + ]:             42 :     Assert(objsMoved != NULL);
                              17897                 :                : 
                              17898                 :                :     /* OK, modify the pg_class row and pg_depend entry */
 1910 andres@anarazel.de      17899                 :             42 :     classRel = table_open(RelationRelationId, RowExclusiveLock);
                              17900                 :                : 
 4183 alvherre@alvh.no-ip.    17901                 :             42 :     AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
                              17902                 :                :                                    nspOid, true, objsMoved);
                              17903                 :                : 
                              17904                 :                :     /* Fix the table's row type too, if it has one */
 1377 tgl@sss.pgh.pa.us       17905         [ +  + ]:             42 :     if (OidIsValid(rel->rd_rel->reltype))
                              17906                 :             41 :         AlterTypeNamespaceInternal(rel->rd_rel->reltype,
                              17907                 :                :                                    nspOid, false, false, objsMoved);
                              17908                 :                : 
                              17909                 :                :     /* Fix other dependent stuff */
   19                         17910                 :             42 :     AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
                              17911                 :             42 :     AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
                              17912                 :                :                        objsMoved, AccessExclusiveLock);
                              17913                 :             42 :     AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
                              17914                 :                :                               false, objsMoved);
                              17915                 :                : 
 1910 andres@anarazel.de      17916                 :             42 :     table_close(classRel, RowExclusiveLock);
 6831 tgl@sss.pgh.pa.us       17917                 :             42 : }
                              17918                 :                : 
                              17919                 :                : /*
                              17920                 :                :  * The guts of relocating a relation to another namespace: fix the pg_class
                              17921                 :                :  * entry, and the pg_depend entry if any.  Caller must already have
                              17922                 :                :  * opened and write-locked pg_class.
                              17923                 :                :  */
                              17924                 :                : void
                              17925                 :             91 : AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
                              17926                 :                :                                Oid oldNspOid, Oid newNspOid,
                              17927                 :                :                                bool hasDependEntry,
                              17928                 :                :                                ObjectAddresses *objsMoved)
                              17929                 :                : {
                              17930                 :                :     HeapTuple   classTup;
                              17931                 :                :     Form_pg_class classForm;
                              17932                 :                :     ObjectAddress thisobj;
 3069 rhaas@postgresql.org    17933                 :             91 :     bool        already_done = false;
                              17934                 :                : 
 5173                         17935                 :             91 :     classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
 6831 tgl@sss.pgh.pa.us       17936         [ -  + ]:             91 :     if (!HeapTupleIsValid(classTup))
 6831 tgl@sss.pgh.pa.us       17937         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relOid);
 6831 tgl@sss.pgh.pa.us       17938                 :CBC          91 :     classForm = (Form_pg_class) GETSTRUCT(classTup);
                              17939                 :                : 
                              17940         [ -  + ]:             91 :     Assert(classForm->relnamespace == oldNspOid);
                              17941                 :                : 
 4183 alvherre@alvh.no-ip.    17942                 :             91 :     thisobj.classId = RelationRelationId;
                              17943                 :             91 :     thisobj.objectId = relOid;
                              17944                 :             91 :     thisobj.objectSubId = 0;
                              17945                 :                : 
                              17946                 :                :     /*
                              17947                 :                :      * If the object has already been moved, don't move it again.  If it's
                              17948                 :                :      * already in the right place, don't move it, but still fire the object
                              17949                 :                :      * access hook.
                              17950                 :                :      */
 3069 rhaas@postgresql.org    17951                 :             91 :     already_done = object_address_present(&thisobj, objsMoved);
                              17952   [ +  -  +  + ]:             91 :     if (!already_done && oldNspOid != newNspOid)
                              17953                 :                :     {
                              17954                 :                :         /* check for duplicate name (more friendly than unique-index failure) */
 4183 alvherre@alvh.no-ip.    17955         [ -  + ]:             70 :         if (get_relname_relid(NameStr(classForm->relname),
                              17956                 :                :                               newNspOid) != InvalidOid)
 4183 alvherre@alvh.no-ip.    17957         [ #  # ]:UBC           0 :             ereport(ERROR,
                              17958                 :                :                     (errcode(ERRCODE_DUPLICATE_TABLE),
                              17959                 :                :                      errmsg("relation \"%s\" already exists in schema \"%s\"",
                              17960                 :                :                             NameStr(classForm->relname),
                              17961                 :                :                             get_namespace_name(newNspOid))));
                              17962                 :                : 
                              17963                 :                :         /* classTup is a copy, so OK to scribble on */
 4183 alvherre@alvh.no-ip.    17964                 :CBC          70 :         classForm->relnamespace = newNspOid;
                              17965                 :                : 
 2630                         17966                 :             70 :         CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
                              17967                 :                : 
                              17968                 :                :         /* Update dependency on schema if caller said so */
 4183                         17969   [ +  +  -  + ]:            121 :         if (hasDependEntry &&
 3970 sfrost@snowman.net      17970                 :             51 :             changeDependencyFor(RelationRelationId,
                              17971                 :                :                                 relOid,
                              17972                 :                :                                 NamespaceRelationId,
                              17973                 :                :                                 oldNspOid,
                              17974                 :                :                                 newNspOid) != 1)
  279 michael@paquier.xyz     17975         [ #  # ]:UNC           0 :             elog(ERROR, "could not change schema dependency for relation \"%s\"",
                              17976                 :                :                  NameStr(classForm->relname));
                              17977                 :                :     }
 3069 rhaas@postgresql.org    17978         [ +  - ]:CBC          91 :     if (!already_done)
                              17979                 :                :     {
 4183 alvherre@alvh.no-ip.    17980                 :             91 :         add_exact_object_address(&thisobj, objsMoved);
                              17981                 :                : 
 4046 rhaas@postgresql.org    17982         [ -  + ]:             91 :         InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
                              17983                 :                :     }
                              17984                 :                : 
 6831 tgl@sss.pgh.pa.us       17985                 :             91 :     heap_freetuple(classTup);
                              17986                 :             91 : }
                              17987                 :                : 
                              17988                 :                : /*
                              17989                 :                :  * Move all indexes for the specified relation to another namespace.
                              17990                 :                :  *
                              17991                 :                :  * Note: we assume adequate permission checking was done by the caller,
                              17992                 :                :  * and that the caller has a suitable lock on the owning relation.
                              17993                 :                :  */
                              17994                 :                : static void
                              17995                 :             42 : AlterIndexNamespaces(Relation classRel, Relation rel,
                              17996                 :                :                      Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
                              17997                 :                : {
                              17998                 :                :     List       *indexList;
                              17999                 :                :     ListCell   *l;
                              18000                 :                : 
                              18001                 :             42 :     indexList = RelationGetIndexList(rel);
                              18002                 :                : 
                              18003   [ +  +  +  +  :             64 :     foreach(l, indexList)
                                              +  + ]
                              18004                 :                :     {
 6756 bruce@momjian.us        18005                 :             22 :         Oid         indexOid = lfirst_oid(l);
                              18006                 :                :         ObjectAddress thisobj;
                              18007                 :                : 
 4183 alvherre@alvh.no-ip.    18008                 :             22 :         thisobj.classId = RelationRelationId;
                              18009                 :             22 :         thisobj.objectId = indexOid;
                              18010                 :             22 :         thisobj.objectSubId = 0;
                              18011                 :                : 
                              18012                 :                :         /*
                              18013                 :                :          * Note: currently, the index will not have its own dependency on the
                              18014                 :                :          * namespace, so we don't need to do changeDependencyFor(). There's no
                              18015                 :                :          * row type in pg_type, either.
                              18016                 :                :          *
                              18017                 :                :          * XXX this objsMoved test may be pointless -- surely we have a single
                              18018                 :                :          * dependency link from a relation to each index?
                              18019                 :                :          */
                              18020         [ +  - ]:             22 :         if (!object_address_present(&thisobj, objsMoved))
                              18021                 :                :         {
                              18022                 :             22 :             AlterRelationNamespaceInternal(classRel, indexOid,
                              18023                 :                :                                            oldNspOid, newNspOid,
                              18024                 :                :                                            false, objsMoved);
                              18025                 :             22 :             add_exact_object_address(&thisobj, objsMoved);
                              18026                 :                :         }
                              18027                 :                :     }
                              18028                 :                : 
 6831 tgl@sss.pgh.pa.us       18029                 :             42 :     list_free(indexList);
                              18030                 :             42 : }
                              18031                 :                : 
                              18032                 :                : /*
                              18033                 :                :  * Move all identity and SERIAL-column sequences of the specified relation to another
                              18034                 :                :  * namespace.
                              18035                 :                :  *
                              18036                 :                :  * Note: we assume adequate permission checking was done by the caller,
                              18037                 :                :  * and that the caller has a suitable lock on the owning relation.
                              18038                 :                :  */
                              18039                 :                : static void
                              18040                 :             42 : AlterSeqNamespaces(Relation classRel, Relation rel,
                              18041                 :                :                    Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
                              18042                 :                :                    LOCKMODE lockmode)
                              18043                 :                : {
                              18044                 :                :     Relation    depRel;
                              18045                 :                :     SysScanDesc scan;
                              18046                 :                :     ScanKeyData key[2];
                              18047                 :                :     HeapTuple   tup;
                              18048                 :                : 
                              18049                 :                :     /*
                              18050                 :                :      * SERIAL sequences are those having an auto dependency on one of the
                              18051                 :                :      * table's columns (we don't care *which* column, exactly).
                              18052                 :                :      */
 1910 andres@anarazel.de      18053                 :             42 :     depRel = table_open(DependRelationId, AccessShareLock);
                              18054                 :                : 
 6831 tgl@sss.pgh.pa.us       18055                 :             42 :     ScanKeyInit(&key[0],
                              18056                 :                :                 Anum_pg_depend_refclassid,
                              18057                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              18058                 :                :                 ObjectIdGetDatum(RelationRelationId));
                              18059                 :             42 :     ScanKeyInit(&key[1],
                              18060                 :                :                 Anum_pg_depend_refobjid,
                              18061                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              18062                 :                :                 ObjectIdGetDatum(RelationGetRelid(rel)));
                              18063                 :                :     /* we leave refobjsubid unspecified */
                              18064                 :                : 
                              18065                 :             42 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
                              18066                 :                :                               NULL, 2, key);
                              18067                 :                : 
                              18068         [ +  + ]:            294 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
                              18069                 :                :     {
                              18070                 :            252 :         Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
                              18071                 :                :         Relation    seqRel;
                              18072                 :                : 
                              18073                 :                :         /* skip dependencies other than auto dependencies on columns */
                              18074         [ +  + ]:            252 :         if (depForm->refobjsubid == 0 ||
                              18075         [ +  + ]:            180 :             depForm->classid != RelationRelationId ||
                              18076         [ +  - ]:             21 :             depForm->objsubid != 0 ||
 2565 peter_e@gmx.net         18077   [ -  +  -  - ]:             21 :             !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
 6831 tgl@sss.pgh.pa.us       18078                 :            231 :             continue;
                              18079                 :                : 
                              18080                 :                :         /* Use relation_open just in case it's an index */
 5009 simon@2ndQuadrant.co    18081                 :             21 :         seqRel = relation_open(depForm->objid, lockmode);
                              18082                 :                : 
                              18083                 :                :         /* skip non-sequence relations */
 6831 tgl@sss.pgh.pa.us       18084         [ -  + ]:             21 :         if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
                              18085                 :                :         {
                              18086                 :                :             /* No need to keep the lock */
 5009 simon@2ndQuadrant.co    18087                 :UBC           0 :             relation_close(seqRel, lockmode);
 6831 tgl@sss.pgh.pa.us       18088                 :              0 :             continue;
                              18089                 :                :         }
                              18090                 :                : 
                              18091                 :                :         /* Fix the pg_class and pg_depend entries */
 6831 tgl@sss.pgh.pa.us       18092                 :CBC          21 :         AlterRelationNamespaceInternal(classRel, depForm->objid,
                              18093                 :                :                                        oldNspOid, newNspOid,
                              18094                 :                :                                        true, objsMoved);
                              18095                 :                : 
                              18096                 :                :         /*
                              18097                 :                :          * Sequences used to have entries in pg_type, but no longer do.  If we
                              18098                 :                :          * ever re-instate that, we'll need to move the pg_type entry to the
                              18099                 :                :          * new namespace, too (using AlterTypeNamespaceInternal).
                              18100                 :                :          */
 1377                         18101         [ -  + ]:             21 :         Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
                              18102                 :                : 
                              18103                 :                :         /* Now we can close it.  Keep the lock till end of transaction. */
 6831                         18104                 :             21 :         relation_close(seqRel, NoLock);
                              18105                 :                :     }
                              18106                 :                : 
                              18107                 :             42 :     systable_endscan(scan);
                              18108                 :                : 
                              18109                 :             42 :     relation_close(depRel, AccessShareLock);
                              18110                 :             42 : }
                              18111                 :                : 
                              18112                 :                : 
                              18113                 :                : /*
                              18114                 :                :  * This code supports
                              18115                 :                :  *  CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
                              18116                 :                :  *
                              18117                 :                :  * Because we only support this for TEMP tables, it's sufficient to remember
                              18118                 :                :  * the state in a backend-local data structure.
                              18119                 :                :  */
                              18120                 :                : 
                              18121                 :                : /*
                              18122                 :                :  * Register a newly-created relation's ON COMMIT action.
                              18123                 :                :  */
                              18124                 :                : void
 7825                         18125                 :             83 : register_on_commit_action(Oid relid, OnCommitAction action)
                              18126                 :                : {
                              18127                 :                :     OnCommitItem *oc;
                              18128                 :                :     MemoryContext oldcxt;
                              18129                 :                : 
                              18130                 :                :     /*
                              18131                 :                :      * We needn't bother registering the relation unless there is an ON COMMIT
                              18132                 :                :      * action we need to take.
                              18133                 :                :      */
                              18134   [ +  -  +  + ]:             83 :     if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
 7827 bruce@momjian.us        18135                 :             12 :         return;
                              18136                 :                : 
 7825 tgl@sss.pgh.pa.us       18137                 :             71 :     oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
                              18138                 :                : 
                              18139                 :             71 :     oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
                              18140                 :             71 :     oc->relid = relid;
                              18141                 :             71 :     oc->oncommit = action;
 7150                         18142                 :             71 :     oc->creating_subid = GetCurrentSubTransactionId();
                              18143                 :             71 :     oc->deleting_subid = InvalidSubTransactionId;
                              18144                 :                : 
                              18145                 :                :     /*
                              18146                 :                :      * We use lcons() here so that ON COMMIT actions are processed in reverse
                              18147                 :                :      * order of registration.  That might not be essential but it seems
                              18148                 :                :      * reasonable.
                              18149                 :                :      */
 7825                         18150                 :             71 :     on_commits = lcons(oc, on_commits);
                              18151                 :                : 
                              18152                 :             71 :     MemoryContextSwitchTo(oldcxt);
                              18153                 :                : }
                              18154                 :                : 
                              18155                 :                : /*
                              18156                 :                :  * Unregister any ON COMMIT action when a relation is deleted.
                              18157                 :                :  *
                              18158                 :                :  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
                              18159                 :                :  */
                              18160                 :                : void
                              18161                 :          21039 : remove_on_commit_action(Oid relid)
                              18162                 :                : {
                              18163                 :                :     ListCell   *l;
                              18164                 :                : 
                              18165   [ +  +  +  +  :          21106 :     foreach(l, on_commits)
                                              +  + ]
                              18166                 :                :     {
 7559 bruce@momjian.us        18167                 :            132 :         OnCommitItem *oc = (OnCommitItem *) lfirst(l);
                              18168                 :                : 
 7825 tgl@sss.pgh.pa.us       18169         [ +  + ]:            132 :         if (oc->relid == relid)
                              18170                 :                :         {
 7150                         18171                 :             65 :             oc->deleting_subid = GetCurrentSubTransactionId();
 7825                         18172                 :             65 :             break;
                              18173                 :                :         }
                              18174                 :                :     }
 7827 bruce@momjian.us        18175                 :          21039 : }
                              18176                 :                : 
                              18177                 :                : /*
                              18178                 :                :  * Perform ON COMMIT actions.
                              18179                 :                :  *
                              18180                 :                :  * This is invoked just before actually committing, since it's possible
                              18181                 :                :  * to encounter errors.
                              18182                 :                :  */
                              18183                 :                : void
 7825 tgl@sss.pgh.pa.us       18184                 :         408922 : PreCommit_on_commit_actions(void)
                              18185                 :                : {
                              18186                 :                :     ListCell   *l;
 7017                         18187                 :         408922 :     List       *oids_to_truncate = NIL;
 1983 michael@paquier.xyz     18188                 :         408922 :     List       *oids_to_drop = NIL;
                              18189                 :                : 
 7825 tgl@sss.pgh.pa.us       18190   [ +  +  +  +  :         409280 :     foreach(l, on_commits)
                                              +  + ]
                              18191                 :                :     {
 7559 bruce@momjian.us        18192                 :            358 :         OnCommitItem *oc = (OnCommitItem *) lfirst(l);
                              18193                 :                : 
                              18194                 :                :         /* Ignore entry if already dropped in this xact */
 7150 tgl@sss.pgh.pa.us       18195         [ +  + ]:            358 :         if (oc->deleting_subid != InvalidSubTransactionId)
 7825                         18196                 :             34 :             continue;
                              18197                 :                : 
                              18198   [ -  +  +  - ]:            324 :         switch (oc->oncommit)
                              18199                 :                :         {
 7825 tgl@sss.pgh.pa.us       18200                 :UBC           0 :             case ONCOMMIT_NOOP:
                              18201                 :                :             case ONCOMMIT_PRESERVE_ROWS:
                              18202                 :                :                 /* Do nothing (there shouldn't be such entries, actually) */
                              18203                 :              0 :                 break;
 7825 tgl@sss.pgh.pa.us       18204                 :CBC         299 :             case ONCOMMIT_DELETE_ROWS:
                              18205                 :                : 
                              18206                 :                :                 /*
                              18207                 :                :                  * If this transaction hasn't accessed any temporary
                              18208                 :                :                  * relations, we can skip truncating ON COMMIT DELETE ROWS
                              18209                 :                :                  * tables, as they must still be empty.
                              18210                 :                :                  */
 1905 michael@paquier.xyz     18211         [ +  + ]:            299 :                 if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
 4093 heikki.linnakangas@i    18212                 :            200 :                     oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
 7825 tgl@sss.pgh.pa.us       18213                 :            299 :                 break;
                              18214                 :             25 :             case ONCOMMIT_DROP:
 1983 michael@paquier.xyz     18215                 :             25 :                 oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
                              18216                 :             25 :                 break;
                              18217                 :                :         }
                              18218                 :                :     }
                              18219                 :                : 
                              18220                 :                :     /*
                              18221                 :                :      * Truncate relations before dropping so that all dependencies between
                              18222                 :                :      * relations are removed after they are worked on.  Doing it like this
                              18223                 :                :      * might be a waste as it is possible that a relation being truncated will
                              18224                 :                :      * be dropped anyway due to its parent being dropped, but this makes the
                              18225                 :                :      * code more robust because of not having to re-check that the relation
                              18226                 :                :      * exists at truncation time.
                              18227                 :                :      */
 7017 tgl@sss.pgh.pa.us       18228         [ +  + ]:         408922 :     if (oids_to_truncate != NIL)
                              18229                 :            167 :         heap_truncate(oids_to_truncate);
                              18230                 :                : 
 1983 michael@paquier.xyz     18231         [ +  + ]:         408919 :     if (oids_to_drop != NIL)
                              18232                 :                :     {
                              18233                 :             22 :         ObjectAddresses *targetObjects = new_object_addresses();
                              18234                 :                : 
                              18235   [ +  -  +  +  :             47 :         foreach(l, oids_to_drop)
                                              +  + ]
                              18236                 :                :         {
                              18237                 :                :             ObjectAddress object;
                              18238                 :                : 
                              18239                 :             25 :             object.classId = RelationRelationId;
                              18240                 :             25 :             object.objectId = lfirst_oid(l);
                              18241                 :             25 :             object.objectSubId = 0;
                              18242                 :                : 
                              18243         [ -  + ]:             25 :             Assert(!object_address_present(&object, targetObjects));
                              18244                 :                : 
                              18245                 :             25 :             add_exact_object_address(&object, targetObjects);
                              18246                 :                :         }
                              18247                 :                : 
                              18248                 :                :         /*
                              18249                 :                :          * Object deletion might involve toast table access (to clean up
                              18250                 :                :          * toasted catalog entries), so ensure we have a valid snapshot.
                              18251                 :                :          */
  181 tgl@sss.pgh.pa.us       18252                 :             22 :         PushActiveSnapshot(GetTransactionSnapshot());
                              18253                 :                : 
                              18254                 :                :         /*
                              18255                 :                :          * Since this is an automatic drop, rather than one directly initiated
                              18256                 :                :          * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
                              18257                 :                :          */
 1983 michael@paquier.xyz     18258                 :             22 :         performMultipleDeletions(targetObjects, DROP_CASCADE,
                              18259                 :                :                                  PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY);
                              18260                 :                : 
  181 tgl@sss.pgh.pa.us       18261                 :             22 :         PopActiveSnapshot();
                              18262                 :                : 
                              18263                 :                : #ifdef USE_ASSERT_CHECKING
                              18264                 :                : 
                              18265                 :                :         /*
                              18266                 :                :          * Note that table deletion will call remove_on_commit_action, so the
                              18267                 :                :          * entry should get marked as deleted.
                              18268                 :                :          */
 1983 michael@paquier.xyz     18269   [ +  -  +  +  :             72 :         foreach(l, on_commits)
                                              +  + ]
                              18270                 :                :         {
                              18271                 :             50 :             OnCommitItem *oc = (OnCommitItem *) lfirst(l);
                              18272                 :                : 
                              18273         [ +  + ]:             50 :             if (oc->oncommit != ONCOMMIT_DROP)
                              18274                 :             25 :                 continue;
                              18275                 :                : 
                              18276         [ -  + ]:             25 :             Assert(oc->deleting_subid != InvalidSubTransactionId);
                              18277                 :                :         }
                              18278                 :                : #endif
                              18279                 :                :     }
 7827 bruce@momjian.us        18280                 :         408919 : }
                              18281                 :                : 
                              18282                 :                : /*
                              18283                 :                :  * Post-commit or post-abort cleanup for ON COMMIT management.
                              18284                 :                :  *
                              18285                 :                :  * All we do here is remove no-longer-needed OnCommitItem entries.
                              18286                 :                :  *
                              18287                 :                :  * During commit, remove entries that were deleted during this transaction;
                              18288                 :                :  * during abort, remove those created during this transaction.
                              18289                 :                :  */
                              18290                 :                : void
 7150 tgl@sss.pgh.pa.us       18291                 :         431482 : AtEOXact_on_commit_actions(bool isCommit)
                              18292                 :                : {
                              18293                 :                :     ListCell   *cur_item;
                              18294                 :                : 
 1735                         18295   [ +  +  +  +  :         431855 :     foreach(cur_item, on_commits)
                                              +  + ]
                              18296                 :                :     {
 7263 neilc@samurai.com       18297                 :            373 :         OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
                              18298                 :                : 
 7150 tgl@sss.pgh.pa.us       18299   [ +  +  +  + ]:            424 :         if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
                              18300                 :             51 :             oc->creating_subid != InvalidSubTransactionId)
                              18301                 :                :         {
                              18302                 :                :             /* cur_item must be removed */
 1735                         18303                 :             71 :             on_commits = foreach_delete_current(on_commits, cur_item);
 7825                         18304                 :             71 :             pfree(oc);
                              18305                 :                :         }
                              18306                 :                :         else
                              18307                 :                :         {
                              18308                 :                :             /* cur_item must be preserved */
 7150                         18309                 :            302 :             oc->creating_subid = InvalidSubTransactionId;
                              18310                 :            302 :             oc->deleting_subid = InvalidSubTransactionId;
                              18311                 :                :         }
                              18312                 :                :     }
 7227                         18313                 :         431482 : }
                              18314                 :                : 
                              18315                 :                : /*
                              18316                 :                :  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
                              18317                 :                :  *
                              18318                 :                :  * During subabort, we can immediately remove entries created during this
                              18319                 :                :  * subtransaction.  During subcommit, just relabel entries marked during
                              18320                 :                :  * this subtransaction as being the parent's responsibility.
                              18321                 :                :  */
                              18322                 :                : void
 7150                         18323                 :           9927 : AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
                              18324                 :                :                               SubTransactionId parentSubid)
                              18325                 :                : {
                              18326                 :                :     ListCell   *cur_item;
                              18327                 :                : 
 1735                         18328   [ -  +  -  -  :           9927 :     foreach(cur_item, on_commits)
                                              -  + ]
                              18329                 :                :     {
 7227 tgl@sss.pgh.pa.us       18330                 :UBC           0 :         OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
                              18331                 :                : 
 7150                         18332   [ #  #  #  # ]:              0 :         if (!isCommit && oc->creating_subid == mySubid)
                              18333                 :                :         {
                              18334                 :                :             /* cur_item must be removed */
 1735                         18335                 :              0 :             on_commits = foreach_delete_current(on_commits, cur_item);
 7227                         18336                 :              0 :             pfree(oc);
                              18337                 :                :         }
                              18338                 :                :         else
                              18339                 :                :         {
                              18340                 :                :             /* cur_item must be preserved */
 7150                         18341         [ #  # ]:              0 :             if (oc->creating_subid == mySubid)
                              18342                 :              0 :                 oc->creating_subid = parentSubid;
                              18343         [ #  # ]:              0 :             if (oc->deleting_subid == mySubid)
                              18344         [ #  # ]:              0 :                 oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
                              18345                 :                :         }
                              18346                 :                :     }
 7827 bruce@momjian.us        18347                 :CBC        9927 : }
                              18348                 :                : 
                              18349                 :                : /*
                              18350                 :                :  * This is intended as a callback for RangeVarGetRelidExtended().  It allows
                              18351                 :                :  * the relation to be locked only if (1) it's a plain or partitioned table,
                              18352                 :                :  * materialized view, or TOAST table and (2) the current user is the owner (or
                              18353                 :                :  * the superuser) or has been granted MAINTAIN.  This meets the
                              18354                 :                :  * permission-checking needs of CLUSTER, REINDEX TABLE, and REFRESH
                              18355                 :                :  * MATERIALIZED VIEW; we expose it here so that it can be used by all.
                              18356                 :                :  */
                              18357                 :                : void
   32 nathan@postgresql.or    18358                 :GNC         495 : RangeVarCallbackMaintainsTable(const RangeVar *relation,
                              18359                 :                :                                Oid relId, Oid oldRelId, void *arg)
                              18360                 :                : {
                              18361                 :                :     char        relkind;
                              18362                 :                :     AclResult   aclresult;
                              18363                 :                : 
                              18364                 :                :     /* Nothing to do if the relation was not found. */
 4498 rhaas@postgresql.org    18365         [ +  + ]:CBC         495 :     if (!OidIsValid(relId))
                              18366                 :              3 :         return;
                              18367                 :                : 
                              18368                 :                :     /*
                              18369                 :                :      * If the relation does exist, check whether it's an index.  But note that
                              18370                 :                :      * the relation might have been dropped between the time we did the name
                              18371                 :                :      * lookup and now.  In that case, there's nothing to do.
                              18372                 :                :      */
                              18373                 :            492 :     relkind = get_rel_relkind(relId);
                              18374         [ -  + ]:            492 :     if (!relkind)
 4498 rhaas@postgresql.org    18375                 :UBC           0 :         return;
 4060 kgrittn@postgresql.o    18376   [ +  +  +  +  :CBC         492 :     if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
                                              +  + ]
 2685 rhaas@postgresql.org    18377         [ +  + ]:             68 :         relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
 4498                         18378         [ +  - ]:             14 :         ereport(ERROR,
                              18379                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18380                 :                :                  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
                              18381                 :                : 
                              18382                 :                :     /* Check permissions */
   32 nathan@postgresql.or    18383                 :GNC         478 :     aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
                              18384         [ +  + ]:            478 :     if (aclresult != ACLCHECK_OK)
                              18385                 :             15 :         aclcheck_error(aclresult,
                              18386                 :             15 :                        get_relkind_objtype(get_rel_relkind(relId)),
                              18387                 :             15 :                        relation->relname);
                              18388                 :                : }
                              18389                 :                : 
                              18390                 :                : /*
                              18391                 :                :  * Callback to RangeVarGetRelidExtended() for TRUNCATE processing.
                              18392                 :                :  */
                              18393                 :                : static void
 2074 michael@paquier.xyz     18394                 :CBC         917 : RangeVarCallbackForTruncate(const RangeVar *relation,
                              18395                 :                :                             Oid relId, Oid oldRelId, void *arg)
                              18396                 :                : {
                              18397                 :                :     HeapTuple   tuple;
                              18398                 :                : 
                              18399                 :                :     /* Nothing to do if the relation was not found. */
                              18400         [ -  + ]:            917 :     if (!OidIsValid(relId))
 2074 michael@paquier.xyz     18401                 :UBC           0 :         return;
                              18402                 :                : 
 2074 michael@paquier.xyz     18403                 :CBC         917 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
                              18404         [ -  + ]:            917 :     if (!HeapTupleIsValid(tuple))   /* should not happen */
 2074 michael@paquier.xyz     18405         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relId);
                              18406                 :                : 
 2074 michael@paquier.xyz     18407                 :CBC         917 :     truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
 1535 fujii@postgresql.org    18408                 :            915 :     truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
                              18409                 :                : 
 2074 michael@paquier.xyz     18410                 :            899 :     ReleaseSysCache(tuple);
                              18411                 :                : }
                              18412                 :                : 
                              18413                 :                : /*
                              18414                 :                :  * Callback for RangeVarGetRelidExtended().  Checks that the current user is
                              18415                 :                :  * the owner of the relation, or superuser.
                              18416                 :                :  */
                              18417                 :                : void
 3709 rhaas@postgresql.org    18418                 :           7498 : RangeVarCallbackOwnsRelation(const RangeVar *relation,
                              18419                 :                :                              Oid relId, Oid oldRelId, void *arg)
                              18420                 :                : {
                              18421                 :                :     HeapTuple   tuple;
                              18422                 :                : 
                              18423                 :                :     /* Nothing to do if the relation was not found. */
                              18424         [ +  + ]:           7498 :     if (!OidIsValid(relId))
                              18425                 :              7 :         return;
                              18426                 :                : 
                              18427                 :           7491 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
 2489 tgl@sss.pgh.pa.us       18428         [ -  + ]:           7491 :     if (!HeapTupleIsValid(tuple))   /* should not happen */
 3709 rhaas@postgresql.org    18429         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relId);
                              18430                 :                : 
  518 peter@eisentraut.org    18431         [ +  + ]:CBC        7491 :     if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
 2325 peter_e@gmx.net         18432                 :              3 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)),
 3709 rhaas@postgresql.org    18433                 :              3 :                        relation->relname);
                              18434                 :                : 
                              18435   [ +  +  +  + ]:          14916 :     if (!allowSystemTableMods &&
                              18436                 :           7428 :         IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
                              18437         [ +  - ]:              1 :         ereport(ERROR,
                              18438                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                              18439                 :                :                  errmsg("permission denied: \"%s\" is a system catalog",
                              18440                 :                :                         relation->relname)));
                              18441                 :                : 
                              18442                 :           7487 :     ReleaseSysCache(tuple);
                              18443                 :                : }
                              18444                 :                : 
                              18445                 :                : /*
                              18446                 :                :  * Common RangeVarGetRelid callback for rename, set schema, and alter table
                              18447                 :                :  * processing.
                              18448                 :                :  */
                              18449                 :                : static void
 4482                         18450                 :          17844 : RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
                              18451                 :                :                                  void *arg)
                              18452                 :                : {
 4326 bruce@momjian.us        18453                 :          17844 :     Node       *stmt = (Node *) arg;
                              18454                 :                :     ObjectType  reltype;
                              18455                 :                :     HeapTuple   tuple;
                              18456                 :                :     Form_pg_class classform;
                              18457                 :                :     AclResult   aclresult;
                              18458                 :                :     char        relkind;
                              18459                 :                : 
 4482 rhaas@postgresql.org    18460                 :          17844 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
                              18461         [ +  + ]:          17844 :     if (!HeapTupleIsValid(tuple))
 4326 bruce@momjian.us        18462                 :            109 :         return;                 /* concurrently dropped */
 4482 rhaas@postgresql.org    18463                 :          17735 :     classform = (Form_pg_class) GETSTRUCT(tuple);
                              18464                 :          17735 :     relkind = classform->relkind;
                              18465                 :                : 
                              18466                 :                :     /* Must own relation. */
  518 peter@eisentraut.org    18467         [ +  + ]:          17735 :     if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
 2325 peter_e@gmx.net         18468                 :             30 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
                              18469                 :                : 
                              18470                 :                :     /* No system table modifications unless explicitly allowed. */
 3790 rhaas@postgresql.org    18471   [ +  +  +  + ]:          17705 :     if (!allowSystemTableMods && IsSystemClass(relid, classform))
 4482                         18472         [ +  - ]:             14 :         ereport(ERROR,
                              18473                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                              18474                 :                :                  errmsg("permission denied: \"%s\" is a system catalog",
                              18475                 :                :                         rv->relname)));
                              18476                 :                : 
                              18477                 :                :     /*
                              18478                 :                :      * Extract the specified relation type from the statement parse tree.
                              18479                 :                :      *
                              18480                 :                :      * Also, for ALTER .. RENAME, check permissions: the user must (still)
                              18481                 :                :      * have CREATE rights on the containing namespace.
                              18482                 :                :      */
                              18483         [ +  + ]:          17691 :     if (IsA(stmt, RenameStmt))
                              18484                 :                :     {
  518 peter@eisentraut.org    18485                 :            252 :         aclresult = object_aclcheck(NamespaceRelationId, classform->relnamespace,
                              18486                 :                :                                     GetUserId(), ACL_CREATE);
 4482 rhaas@postgresql.org    18487         [ -  + ]:            252 :         if (aclresult != ACLCHECK_OK)
 2325 peter_e@gmx.net         18488                 :UBC           0 :             aclcheck_error(aclresult, OBJECT_SCHEMA,
 4482 rhaas@postgresql.org    18489                 :              0 :                            get_namespace_name(classform->relnamespace));
 4482 rhaas@postgresql.org    18490                 :CBC         252 :         reltype = ((RenameStmt *) stmt)->renameType;
                              18491                 :                :     }
                              18492         [ +  + ]:          17439 :     else if (IsA(stmt, AlterObjectSchemaStmt))
                              18493                 :             46 :         reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
                              18494                 :                : 
                              18495         [ +  - ]:          17393 :     else if (IsA(stmt, AlterTableStmt))
 1373 michael@paquier.xyz     18496                 :          17393 :         reltype = ((AlterTableStmt *) stmt)->objtype;
                              18497                 :                :     else
                              18498                 :                :     {
 4482 rhaas@postgresql.org    18499         [ #  # ]:UBC           0 :         elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
                              18500                 :                :         reltype = OBJECT_TABLE; /* placate compiler */
                              18501                 :                :     }
                              18502                 :                : 
                              18503                 :                :     /*
                              18504                 :                :      * For compatibility with prior releases, we allow ALTER TABLE to be used
                              18505                 :                :      * with most other types of relations (but not composite types). We allow
                              18506                 :                :      * similar flexibility for ALTER INDEX in the case of RENAME, but not
                              18507                 :                :      * otherwise.  Otherwise, the user must select the correct form of the
                              18508                 :                :      * command for the relation at issue.
                              18509                 :                :      */
 4482 rhaas@postgresql.org    18510   [ +  +  -  + ]:CBC       17691 :     if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
 4482 rhaas@postgresql.org    18511         [ #  # ]:UBC           0 :         ereport(ERROR,
                              18512                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18513                 :                :                  errmsg("\"%s\" is not a sequence", rv->relname)));
                              18514                 :                : 
 4482 rhaas@postgresql.org    18515   [ +  +  -  + ]:CBC       17691 :     if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
 4482 rhaas@postgresql.org    18516         [ #  # ]:UBC           0 :         ereport(ERROR,
                              18517                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18518                 :                :                  errmsg("\"%s\" is not a view", rv->relname)));
                              18519                 :                : 
 4060 kgrittn@postgresql.o    18520   [ +  +  -  + ]:CBC       17691 :     if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
 4060 kgrittn@postgresql.o    18521         [ #  # ]:UBC           0 :         ereport(ERROR,
                              18522                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18523                 :                :                  errmsg("\"%s\" is not a materialized view", rv->relname)));
                              18524                 :                : 
 4482 rhaas@postgresql.org    18525   [ +  +  -  + ]:CBC       17691 :     if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
 4482 rhaas@postgresql.org    18526         [ #  # ]:UBC           0 :         ereport(ERROR,
                              18527                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18528                 :                :                  errmsg("\"%s\" is not a foreign table", rv->relname)));
                              18529                 :                : 
 4482 rhaas@postgresql.org    18530   [ +  +  -  + ]:CBC       17691 :     if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
 4482 rhaas@postgresql.org    18531         [ #  # ]:UBC           0 :         ereport(ERROR,
                              18532                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18533                 :                :                  errmsg("\"%s\" is not a composite type", rv->relname)));
                              18534                 :                : 
 2277 alvherre@alvh.no-ip.    18535   [ +  +  +  +  :CBC       17691 :     if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
                                              +  + ]
                              18536                 :                :         relkind != RELKIND_PARTITIONED_INDEX
 4482 rhaas@postgresql.org    18537         [ +  + ]:             17 :         && !IsA(stmt, RenameStmt))
                              18538         [ +  - ]:              3 :         ereport(ERROR,
                              18539                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18540                 :                :                  errmsg("\"%s\" is not an index", rv->relname)));
                              18541                 :                : 
                              18542                 :                :     /*
                              18543                 :                :      * Don't allow ALTER TABLE on composite types. We want people to use ALTER
                              18544                 :                :      * TYPE for that.
                              18545                 :                :      */
                              18546   [ +  +  -  + ]:          17688 :     if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
 4482 rhaas@postgresql.org    18547         [ #  # ]:UBC           0 :         ereport(ERROR,
                              18548                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18549                 :                :                  errmsg("\"%s\" is a composite type", rv->relname),
                              18550                 :                :         /* translator: %s is an SQL ALTER command */
                              18551                 :                :                  errhint("Use %s instead.",
                              18552                 :                :                          "ALTER TYPE")));
                              18553                 :                : 
                              18554                 :                :     /*
                              18555                 :                :      * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
                              18556                 :                :      * to a different schema, such as indexes and TOAST tables.
                              18557                 :                :      */
 1011 peter@eisentraut.org    18558         [ +  + ]:CBC       17688 :     if (IsA(stmt, AlterObjectSchemaStmt))
                              18559                 :                :     {
                              18560   [ +  -  -  + ]:             46 :         if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX)
 1011 peter@eisentraut.org    18561         [ #  # ]:UBC           0 :             ereport(ERROR,
                              18562                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18563                 :                :                      errmsg("cannot change schema of index \"%s\"",
                              18564                 :                :                             rv->relname),
                              18565                 :                :                      errhint("Change the schema of the table instead.")));
 1011 peter@eisentraut.org    18566         [ -  + ]:CBC          46 :         else if (relkind == RELKIND_COMPOSITE_TYPE)
 1011 peter@eisentraut.org    18567         [ #  # ]:UBC           0 :             ereport(ERROR,
                              18568                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18569                 :                :                      errmsg("cannot change schema of composite type \"%s\"",
                              18570                 :                :                             rv->relname),
                              18571                 :                :             /* translator: %s is an SQL ALTER command */
                              18572                 :                :                      errhint("Use %s instead.",
                              18573                 :                :                              "ALTER TYPE")));
 1011 peter@eisentraut.org    18574         [ -  + ]:CBC          46 :         else if (relkind == RELKIND_TOASTVALUE)
 1011 peter@eisentraut.org    18575         [ #  # ]:UBC           0 :             ereport(ERROR,
                              18576                 :                :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              18577                 :                :                      errmsg("cannot change schema of TOAST table \"%s\"",
                              18578                 :                :                             rv->relname),
                              18579                 :                :                      errhint("Change the schema of the table instead.")));
                              18580                 :                :     }
                              18581                 :                : 
 4482 rhaas@postgresql.org    18582                 :CBC       17688 :     ReleaseSysCache(tuple);
                              18583                 :                : }
                              18584                 :                : 
                              18585                 :                : /*
                              18586                 :                :  * Transform any expressions present in the partition key
                              18587                 :                :  *
                              18588                 :                :  * Returns a transformed PartitionSpec.
                              18589                 :                :  */
                              18590                 :                : static PartitionSpec *
  528 alvherre@alvh.no-ip.    18591                 :           2423 : transformPartitionSpec(Relation rel, PartitionSpec *partspec)
                              18592                 :                : {
                              18593                 :                :     PartitionSpec *newspec;
                              18594                 :                :     ParseState *pstate;
                              18595                 :                :     ParseNamespaceItem *nsitem;
                              18596                 :                :     ListCell   *l;
                              18597                 :                : 
 2669 peter_e@gmx.net         18598                 :           2423 :     newspec = makeNode(PartitionSpec);
                              18599                 :                : 
 2685 rhaas@postgresql.org    18600                 :           2423 :     newspec->strategy = partspec->strategy;
                              18601                 :           2423 :     newspec->partParams = NIL;
 2513 tgl@sss.pgh.pa.us       18602                 :           2423 :     newspec->location = partspec->location;
                              18603                 :                : 
                              18604                 :                :     /* Check valid number of columns for strategy */
  528 alvherre@alvh.no-ip.    18605   [ +  +  +  + ]:           3585 :     if (partspec->strategy == PARTITION_STRATEGY_LIST &&
 2513 tgl@sss.pgh.pa.us       18606                 :           1162 :         list_length(partspec->partParams) != 1)
                              18607         [ +  - ]:              3 :         ereport(ERROR,
                              18608                 :                :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18609                 :                :                  errmsg("cannot use \"list\" partition strategy with more than one column")));
                              18610                 :                : 
                              18611                 :                :     /*
                              18612                 :                :      * Create a dummy ParseState and insert the target relation as its sole
                              18613                 :                :      * rangetable entry.  We need a ParseState for transformExpr.
                              18614                 :                :      */
 2685 rhaas@postgresql.org    18615                 :           2420 :     pstate = make_parsestate(NULL);
 1564 tgl@sss.pgh.pa.us       18616                 :           2420 :     nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
                              18617                 :                :                                            NULL, false, true);
                              18618                 :           2420 :     addNSItemToQuery(pstate, nsitem, true, true, true);
                              18619                 :                : 
                              18620                 :                :     /* take care of any partition expressions */
 2685 rhaas@postgresql.org    18621   [ +  -  +  +  :           5056 :     foreach(l, partspec->partParams)
                                              +  + ]
                              18622                 :                :     {
 1000 peter@eisentraut.org    18623                 :           2648 :         PartitionElem *pelem = lfirst_node(PartitionElem, l);
                              18624                 :                : 
 2685 rhaas@postgresql.org    18625         [ +  + ]:           2648 :         if (pelem->expr)
                              18626                 :                :         {
                              18627                 :                :             /* Copy, to avoid scribbling on the input */
 2513 tgl@sss.pgh.pa.us       18628                 :            149 :             pelem = copyObject(pelem);
                              18629                 :                : 
                              18630                 :                :             /* Now do parse transformation of the expression */
 2685 rhaas@postgresql.org    18631                 :            149 :             pelem->expr = transformExpr(pstate, pelem->expr,
                              18632                 :                :                                         EXPR_KIND_PARTITION_EXPRESSION);
                              18633                 :                : 
                              18634                 :                :             /* we have to fix its collations too */
                              18635                 :            137 :             assign_expr_collations(pstate, pelem->expr);
                              18636                 :                :         }
                              18637                 :                : 
                              18638                 :           2636 :         newspec->partParams = lappend(newspec->partParams, pelem);
                              18639                 :                :     }
                              18640                 :                : 
                              18641                 :           2408 :     return newspec;
                              18642                 :                : }
                              18643                 :                : 
                              18644                 :                : /*
                              18645                 :                :  * Compute per-partition-column information from a list of PartitionElems.
                              18646                 :                :  * Expressions in the PartitionElems must be parse-analyzed already.
                              18647                 :                :  */
                              18648                 :                : static void
 2062 peter_e@gmx.net         18649                 :           2408 : ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
                              18650                 :                :                       List **partexprs, Oid *partopclass, Oid *partcollation,
                              18651                 :                :                       PartitionStrategy strategy)
                              18652                 :                : {
                              18653                 :                :     int         attn;
                              18654                 :                :     ListCell   *lc;
                              18655                 :                :     Oid         am_oid;
                              18656                 :                : 
 2685 rhaas@postgresql.org    18657                 :           2408 :     attn = 0;
                              18658   [ +  -  +  +  :           5002 :     foreach(lc, partParams)
                                              +  + ]
                              18659                 :                :     {
 1000 peter@eisentraut.org    18660                 :           2636 :         PartitionElem *pelem = lfirst_node(PartitionElem, lc);
                              18661                 :                :         Oid         atttype;
                              18662                 :                :         Oid         attcollation;
                              18663                 :                : 
 2685 rhaas@postgresql.org    18664         [ +  + ]:           2636 :         if (pelem->name != NULL)
                              18665                 :                :         {
                              18666                 :                :             /* Simple attribute reference */
                              18667                 :                :             HeapTuple   atttuple;
                              18668                 :                :             Form_pg_attribute attform;
                              18669                 :                : 
 2513 tgl@sss.pgh.pa.us       18670                 :           2499 :             atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
                              18671                 :           2499 :                                              pelem->name);
 2685 rhaas@postgresql.org    18672         [ +  + ]:           2499 :             if (!HeapTupleIsValid(atttuple))
                              18673         [ +  - ]:              6 :                 ereport(ERROR,
                              18674                 :                :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
                              18675                 :                :                          errmsg("column \"%s\" named in partition key does not exist",
                              18676                 :                :                                 pelem->name),
                              18677                 :                :                          parser_errposition(pstate, pelem->location)));
                              18678                 :           2493 :             attform = (Form_pg_attribute) GETSTRUCT(atttuple);
                              18679                 :                : 
                              18680         [ +  + ]:           2493 :             if (attform->attnum <= 0)
                              18681         [ +  - ]:              3 :                 ereport(ERROR,
                              18682                 :                :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18683                 :                :                          errmsg("cannot use system column \"%s\" in partition key",
                              18684                 :                :                                 pelem->name),
                              18685                 :                :                          parser_errposition(pstate, pelem->location)));
                              18686                 :                : 
                              18687                 :                :             /*
                              18688                 :                :              * Generated columns cannot work: They are computed after BEFORE
                              18689                 :                :              * triggers, but partition routing is done before all triggers.
                              18690                 :                :              */
 1842 peter@eisentraut.org    18691         [ +  + ]:           2490 :             if (attform->attgenerated)
                              18692         [ +  - ]:              3 :                 ereport(ERROR,
                              18693                 :                :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18694                 :                :                          errmsg("cannot use generated column in partition key"),
                              18695                 :                :                          errdetail("Column \"%s\" is a generated column.",
                              18696                 :                :                                    pelem->name),
                              18697                 :                :                          parser_errposition(pstate, pelem->location)));
                              18698                 :                : 
 2685 rhaas@postgresql.org    18699                 :           2487 :             partattrs[attn] = attform->attnum;
                              18700                 :           2487 :             atttype = attform->atttypid;
                              18701                 :           2487 :             attcollation = attform->attcollation;
                              18702                 :           2487 :             ReleaseSysCache(atttuple);
                              18703                 :                :         }
                              18704                 :                :         else
                              18705                 :                :         {
                              18706                 :                :             /* Expression */
                              18707                 :            137 :             Node       *expr = pelem->expr;
                              18708                 :                :             char        partattname[16];
                              18709                 :                : 
                              18710         [ -  + ]:            137 :             Assert(expr != NULL);
                              18711                 :            137 :             atttype = exprType(expr);
                              18712                 :            137 :             attcollation = exprCollation(expr);
                              18713                 :                : 
                              18714                 :                :             /*
                              18715                 :                :              * The expression must be of a storable type (e.g., not RECORD).
                              18716                 :                :              * The test is the same as for whether a table column is of a safe
                              18717                 :                :              * type (which is why we needn't check for the non-expression
                              18718                 :                :              * case).
                              18719                 :                :              */
 1574 tgl@sss.pgh.pa.us       18720                 :            137 :             snprintf(partattname, sizeof(partattname), "%d", attn + 1);
                              18721                 :            137 :             CheckAttributeType(partattname,
                              18722                 :                :                                atttype, attcollation,
                              18723                 :                :                                NIL, CHKATYPE_IS_PARTKEY);
                              18724                 :                : 
                              18725                 :                :             /*
                              18726                 :                :              * Strip any top-level COLLATE clause.  This ensures that we treat
                              18727                 :                :              * "x COLLATE y" and "(x COLLATE y)" alike.
                              18728                 :                :              */
 2685 rhaas@postgresql.org    18729         [ -  + ]:            131 :             while (IsA(expr, CollateExpr))
 2685 rhaas@postgresql.org    18730                 :UBC           0 :                 expr = (Node *) ((CollateExpr *) expr)->arg;
                              18731                 :                : 
 2685 rhaas@postgresql.org    18732         [ +  + ]:CBC         131 :             if (IsA(expr, Var) &&
 2513 tgl@sss.pgh.pa.us       18733         [ +  + ]:              6 :                 ((Var *) expr)->varattno > 0)
                              18734                 :                :             {
                              18735                 :                :                 /*
                              18736                 :                :                  * User wrote "(column)" or "(column COLLATE something)".
                              18737                 :                :                  * Treat it like simple attribute anyway.
                              18738                 :                :                  */
 2685 rhaas@postgresql.org    18739                 :              3 :                 partattrs[attn] = ((Var *) expr)->varattno;
                              18740                 :                :             }
                              18741                 :                :             else
                              18742                 :                :             {
 2679                         18743                 :            128 :                 Bitmapset  *expr_attrs = NULL;
                              18744                 :                :                 int         i;
                              18745                 :                : 
                              18746                 :            128 :                 partattrs[attn] = 0;    /* marks the column as expression */
 2685                         18747                 :            128 :                 *partexprs = lappend(*partexprs, expr);
                              18748                 :                : 
                              18749                 :                :                 /*
                              18750                 :                :                  * transformPartitionSpec() should have already rejected
                              18751                 :                :                  * subqueries, aggregates, window functions, and SRFs, based
                              18752                 :                :                  * on the EXPR_KIND_ for partition expressions.
                              18753                 :                :                  */
                              18754                 :                : 
                              18755                 :                :                 /*
                              18756                 :                :                  * Cannot allow system column references, since that would
                              18757                 :                :                  * make partition routing impossible: their values won't be
                              18758                 :                :                  * known yet when we need to do that.
                              18759                 :                :                  */
                              18760                 :            128 :                 pull_varattnos(expr, 1, &expr_attrs);
 2513 tgl@sss.pgh.pa.us       18761         [ +  + ]:           1024 :                 for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
                              18762                 :                :                 {
                              18763         [ -  + ]:            896 :                     if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
                              18764                 :                :                                       expr_attrs))
 2513 tgl@sss.pgh.pa.us       18765         [ #  # ]:UBC           0 :                         ereport(ERROR,
                              18766                 :                :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18767                 :                :                                  errmsg("partition key expressions cannot contain system column references")));
                              18768                 :                :                 }
                              18769                 :                : 
                              18770                 :                :                 /*
                              18771                 :                :                  * Generated columns cannot work: They are computed after
                              18772                 :                :                  * BEFORE triggers, but partition routing is done before all
                              18773                 :                :                  * triggers.
                              18774                 :                :                  */
 1842 peter@eisentraut.org    18775                 :CBC         128 :                 i = -1;
                              18776         [ +  + ]:            282 :                 while ((i = bms_next_member(expr_attrs, i)) >= 0)
                              18777                 :                :                 {
 1789 tgl@sss.pgh.pa.us       18778                 :            157 :                     AttrNumber  attno = i + FirstLowInvalidHeapAttributeNumber;
                              18779                 :                : 
 1572                         18780         [ +  + ]:            157 :                     if (attno > 0 &&
                              18781         [ +  + ]:            154 :                         TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
 1842 peter@eisentraut.org    18782         [ +  - ]:              3 :                         ereport(ERROR,
                              18783                 :                :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18784                 :                :                                  errmsg("cannot use generated column in partition key"),
                              18785                 :                :                                  errdetail("Column \"%s\" is a generated column.",
                              18786                 :                :                                            get_attname(RelationGetRelid(rel), attno, false)),
                              18787                 :                :                                  parser_errposition(pstate, pelem->location)));
                              18788                 :                :                 }
                              18789                 :                : 
                              18790                 :                :                 /*
                              18791                 :                :                  * Preprocess the expression before checking for mutability.
                              18792                 :                :                  * This is essential for the reasons described in
                              18793                 :                :                  * contain_mutable_functions_after_planning.  However, we call
                              18794                 :                :                  * expression_planner for ourselves rather than using that
                              18795                 :                :                  * function, because if constant-folding reduces the
                              18796                 :                :                  * expression to a constant, we'd like to know that so we can
                              18797                 :                :                  * complain below.
                              18798                 :                :                  *
                              18799                 :                :                  * Like contain_mutable_functions_after_planning, assume that
                              18800                 :                :                  * expression_planner won't scribble on its input, so this
                              18801                 :                :                  * won't affect the partexprs entry we saved above.
                              18802                 :                :                  */
  150 tgl@sss.pgh.pa.us       18803                 :            125 :                 expr = (Node *) expression_planner((Expr *) expr);
                              18804                 :                : 
                              18805                 :                :                 /*
                              18806                 :                :                  * Partition expressions cannot contain mutable functions,
                              18807                 :                :                  * because a given row must always map to the same partition
                              18808                 :                :                  * as long as there is no change in the partition boundary
                              18809                 :                :                  * structure.
                              18810                 :                :                  */
                              18811         [ +  + ]:            125 :                 if (contain_mutable_functions(expr))
                              18812         [ +  - ]:              3 :                     ereport(ERROR,
                              18813                 :                :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18814                 :                :                              errmsg("functions in partition key expression must be marked IMMUTABLE")));
                              18815                 :                : 
                              18816                 :                :                 /*
                              18817                 :                :                  * While it is not exactly *wrong* for a partition expression
                              18818                 :                :                  * to be a constant, it seems better to reject such keys.
                              18819                 :                :                  */
 2513                         18820         [ +  + ]:            122 :                 if (IsA(expr, Const))
                              18821         [ +  - ]:              6 :                     ereport(ERROR,
                              18822                 :                :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              18823                 :                :                              errmsg("cannot use constant expression as partition key")));
                              18824                 :                :             }
                              18825                 :                :         }
                              18826                 :                : 
                              18827                 :                :         /*
                              18828                 :                :          * Apply collation override if any
                              18829                 :                :          */
 2685 rhaas@postgresql.org    18830         [ +  + ]:           2606 :         if (pelem->collation)
                              18831                 :             15 :             attcollation = get_collation_oid(pelem->collation, false);
                              18832                 :                : 
                              18833                 :                :         /*
                              18834                 :                :          * Check we have a collation iff it's a collatable type.  The only
                              18835                 :                :          * expected failures here are (1) COLLATE applied to a noncollatable
                              18836                 :                :          * type, or (2) partition expression had an unresolved collation. But
                              18837                 :                :          * we might as well code this to be a complete consistency check.
                              18838                 :                :          */
                              18839         [ +  + ]:           2606 :         if (type_is_collatable(atttype))
                              18840                 :                :         {
                              18841         [ -  + ]:            313 :             if (!OidIsValid(attcollation))
 2685 rhaas@postgresql.org    18842         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              18843                 :                :                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
                              18844                 :                :                          errmsg("could not determine which collation to use for partition expression"),
                              18845                 :                :                          errhint("Use the COLLATE clause to set the collation explicitly.")));
                              18846                 :                :         }
                              18847                 :                :         else
                              18848                 :                :         {
 2685 rhaas@postgresql.org    18849         [ -  + ]:CBC        2293 :             if (OidIsValid(attcollation))
 2685 rhaas@postgresql.org    18850         [ #  # ]:UBC           0 :                 ereport(ERROR,
                              18851                 :                :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
                              18852                 :                :                          errmsg("collations are not supported by type %s",
                              18853                 :                :                                 format_type_be(atttype))));
                              18854                 :                :         }
                              18855                 :                : 
 2685 rhaas@postgresql.org    18856                 :CBC        2606 :         partcollation[attn] = attcollation;
                              18857                 :                : 
                              18858                 :                :         /*
                              18859                 :                :          * Identify the appropriate operator class.  For list and range
                              18860                 :                :          * partitioning, we use a btree operator class; hash partitioning uses
                              18861                 :                :          * a hash operator class.
                              18862                 :                :          */
 2348                         18863         [ +  + ]:           2606 :         if (strategy == PARTITION_STRATEGY_HASH)
                              18864                 :            138 :             am_oid = HASH_AM_OID;
                              18865                 :                :         else
                              18866                 :           2468 :             am_oid = BTREE_AM_OID;
                              18867                 :                : 
 2685                         18868         [ +  + ]:           2606 :         if (!pelem->opclass)
                              18869                 :                :         {
 2348                         18870                 :           2540 :             partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
                              18871                 :                : 
 2685                         18872         [ +  + ]:           2540 :             if (!OidIsValid(partopclass[attn]))
                              18873                 :                :             {
 2348                         18874         [ -  + ]:              6 :                 if (strategy == PARTITION_STRATEGY_HASH)
 2348 rhaas@postgresql.org    18875         [ #  # ]:UBC           0 :                     ereport(ERROR,
                              18876                 :                :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
                              18877                 :                :                              errmsg("data type %s has no default operator class for access method \"%s\"",
                              18878                 :                :                                     format_type_be(atttype), "hash"),
                              18879                 :                :                              errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
                              18880                 :                :                 else
 2348 rhaas@postgresql.org    18881         [ +  - ]:CBC           6 :                     ereport(ERROR,
                              18882                 :                :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
                              18883                 :                :                              errmsg("data type %s has no default operator class for access method \"%s\"",
                              18884                 :                :                                     format_type_be(atttype), "btree"),
                              18885                 :                :                              errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
                              18886                 :                :             }
                              18887                 :                :         }
                              18888                 :                :         else
 2685                         18889         [ +  + ]:             66 :             partopclass[attn] = ResolveOpClass(pelem->opclass,
                              18890                 :                :                                                atttype,
                              18891                 :                :                                                am_oid == HASH_AM_OID ? "hash" : "btree",
                              18892                 :                :                                                am_oid);
                              18893                 :                : 
                              18894                 :           2594 :         attn++;
                              18895                 :                :     }
                              18896                 :           2366 : }
                              18897                 :                : 
                              18898                 :                : /*
                              18899                 :                :  * PartConstraintImpliedByRelConstraint
                              18900                 :                :  *      Do scanrel's existing constraints imply the partition constraint?
                              18901                 :                :  *
                              18902                 :                :  * "Existing constraints" include its check constraints and column-level
                              18903                 :                :  * not-null constraints.  partConstraint describes the partition constraint,
                              18904                 :                :  * in implicit-AND form.
                              18905                 :                :  */
                              18906                 :                : bool
 2432                         18907                 :           1517 : PartConstraintImpliedByRelConstraint(Relation scanrel,
                              18908                 :                :                                      List *partConstraint)
                              18909                 :                : {
                              18910                 :           1517 :     List       *existConstraint = NIL;
                              18911                 :           1517 :     TupleConstr *constr = RelationGetDescr(scanrel)->constr;
                              18912                 :                :     int         i;
                              18913                 :                : 
                              18914   [ +  +  +  + ]:           1517 :     if (constr && constr->has_not_null)
                              18915                 :                :     {
                              18916                 :            357 :         int         natts = scanrel->rd_att->natts;
                              18917                 :                : 
                              18918         [ +  + ]:           1155 :         for (i = 1; i <= natts; i++)
                              18919                 :                :         {
 2429 andres@anarazel.de      18920                 :            798 :             Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
                              18921                 :                : 
 2432 rhaas@postgresql.org    18922   [ +  +  +  - ]:            798 :             if (att->attnotnull && !att->attisdropped)
                              18923                 :                :             {
                              18924                 :            466 :                 NullTest   *ntest = makeNode(NullTest);
                              18925                 :                : 
                              18926                 :            466 :                 ntest->arg = (Expr *) makeVar(1,
                              18927                 :                :                                               i,
                              18928                 :                :                                               att->atttypid,
                              18929                 :                :                                               att->atttypmod,
                              18930                 :                :                                               att->attcollation,
                              18931                 :                :                                               0);
                              18932                 :            466 :                 ntest->nulltesttype = IS_NOT_NULL;
                              18933                 :                : 
                              18934                 :                :                 /*
                              18935                 :                :                  * argisrow=false is correct even for a composite column,
                              18936                 :                :                  * because attnotnull does not represent a SQL-spec IS NOT
                              18937                 :                :                  * NULL test in such a case, just IS DISTINCT FROM NULL.
                              18938                 :                :                  */
                              18939                 :            466 :                 ntest->argisrow = false;
                              18940                 :            466 :                 ntest->location = -1;
                              18941                 :            466 :                 existConstraint = lappend(existConstraint, ntest);
                              18942                 :                :             }
                              18943                 :                :         }
                              18944                 :                :     }
                              18945                 :                : 
 1859                         18946                 :           1517 :     return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
                              18947                 :                : }
                              18948                 :                : 
                              18949                 :                : /*
                              18950                 :                :  * ConstraintImpliedByRelConstraint
                              18951                 :                :  *      Do scanrel's existing constraints imply the given constraint?
                              18952                 :                :  *
                              18953                 :                :  * testConstraint is the constraint to validate. provenConstraint is a
                              18954                 :                :  * caller-provided list of conditions which this function may assume
                              18955                 :                :  * to be true. Both provenConstraint and testConstraint must be in
                              18956                 :                :  * implicit-AND form, must only contain immutable clauses, and must
                              18957                 :                :  * contain only Vars with varno = 1.
                              18958                 :                :  */
                              18959                 :                : bool
                              18960                 :           2183 : ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
                              18961                 :                : {
 1789 tgl@sss.pgh.pa.us       18962                 :           2183 :     List       *existConstraint = list_copy(provenConstraint);
 1859 rhaas@postgresql.org    18963                 :           2183 :     TupleConstr *constr = RelationGetDescr(scanrel)->constr;
                              18964                 :                :     int         num_check,
                              18965                 :                :                 i;
                              18966                 :                : 
 2432                         18967         [ +  + ]:           2183 :     num_check = (constr != NULL) ? constr->num_check : 0;
                              18968         [ +  + ]:           2458 :     for (i = 0; i < num_check; i++)
                              18969                 :                :     {
                              18970                 :                :         Node       *cexpr;
                              18971                 :                : 
                              18972                 :                :         /*
                              18973                 :                :          * If this constraint hasn't been fully validated yet, we must ignore
                              18974                 :                :          * it here.
                              18975                 :                :          */
                              18976         [ +  + ]:            275 :         if (!constr->check[i].ccvalid)
                              18977                 :              3 :             continue;
                              18978                 :                : 
                              18979                 :            272 :         cexpr = stringToNode(constr->check[i].ccbin);
                              18980                 :                : 
                              18981                 :                :         /*
                              18982                 :                :          * Run each expression through const-simplification and
                              18983                 :                :          * canonicalization.  It is necessary, because we will be comparing it
                              18984                 :                :          * to similarly-processed partition constraint expressions, and may
                              18985                 :                :          * fail to detect valid matches without this.
                              18986                 :                :          */
                              18987                 :            272 :         cexpr = eval_const_expressions(NULL, cexpr);
 2226 tgl@sss.pgh.pa.us       18988                 :            272 :         cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
                              18989                 :                : 
 2432 rhaas@postgresql.org    18990                 :            272 :         existConstraint = list_concat(existConstraint,
                              18991                 :            272 :                                       make_ands_implicit((Expr *) cexpr));
                              18992                 :                :     }
                              18993                 :                : 
                              18994                 :                :     /*
                              18995                 :                :      * Try to make the proof.  Since we are comparing CHECK constraints, we
                              18996                 :                :      * need to use weak implication, i.e., we assume existConstraint is
                              18997                 :                :      * not-false and try to prove the same for testConstraint.
                              18998                 :                :      *
                              18999                 :                :      * Note that predicate_implied_by assumes its first argument is known
                              19000                 :                :      * immutable.  That should always be true for both NOT NULL and partition
                              19001                 :                :      * constraints, so we don't test it here.
                              19002                 :                :      */
 1859                         19003                 :           2183 :     return predicate_implied_by(testConstraint, existConstraint, true);
                              19004                 :                : }
                              19005                 :                : 
                              19006                 :                : /*
                              19007                 :                :  * QueuePartitionConstraintValidation
                              19008                 :                :  *
                              19009                 :                :  * Add an entry to wqueue to have the given partition constraint validated by
                              19010                 :                :  * Phase 3, for the given relation, and all its children.
                              19011                 :                :  *
                              19012                 :                :  * We first verify whether the given constraint is implied by pre-existing
                              19013                 :                :  * relation constraints; if it is, there's no need to scan the table to
                              19014                 :                :  * validate, so don't queue in that case.
                              19015                 :                :  */
                              19016                 :                : static void
 2195 alvherre@alvh.no-ip.    19017                 :           1202 : QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
                              19018                 :                :                                    List *partConstraint,
                              19019                 :                :                                    bool validate_default)
                              19020                 :                : {
                              19021                 :                :     /*
                              19022                 :                :      * Based on the table's existing constraints, determine whether or not we
                              19023                 :                :      * may skip scanning the table.
                              19024                 :                :      */
 2432 rhaas@postgresql.org    19025         [ +  + ]:           1202 :     if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
                              19026                 :                :     {
 2383                         19027         [ +  + ]:             45 :         if (!validate_default)
 1681 tgl@sss.pgh.pa.us       19028         [ +  + ]:             34 :             ereport(DEBUG1,
                              19029                 :                :                     (errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints",
                              19030                 :                :                                      RelationGetRelationName(scanrel))));
                              19031                 :                :         else
                              19032         [ +  + ]:             11 :             ereport(DEBUG1,
                              19033                 :                :                     (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
                              19034                 :                :                                      RelationGetRelationName(scanrel))));
 2432 rhaas@postgresql.org    19035                 :             45 :         return;
                              19036                 :                :     }
                              19037                 :                : 
                              19038                 :                :     /*
                              19039                 :                :      * Constraints proved insufficient. For plain relations, queue a
                              19040                 :                :      * validation item now; for partitioned tables, recurse to process each
                              19041                 :                :      * partition.
                              19042                 :                :      */
 2195 alvherre@alvh.no-ip.    19043         [ +  + ]:           1157 :     if (scanrel->rd_rel->relkind == RELKIND_RELATION)
                              19044                 :                :     {
                              19045                 :                :         AlteredTableInfo *tab;
                              19046                 :                : 
                              19047                 :                :         /* Grab a work queue entry. */
                              19048                 :            960 :         tab = ATGetQueueEntry(wqueue, scanrel);
                              19049         [ -  + ]:            960 :         Assert(tab->partition_constraint == NULL);
                              19050                 :            960 :         tab->partition_constraint = (Expr *) linitial(partConstraint);
                              19051                 :            960 :         tab->validate_default = validate_default;
                              19052                 :                :     }
                              19053         [ +  + ]:            197 :     else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              19054                 :                :     {
 1088                         19055                 :            173 :         PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true);
                              19056                 :                :         int         i;
                              19057                 :                : 
 2195                         19058         [ +  + ]:            370 :         for (i = 0; i < partdesc->nparts; i++)
                              19059                 :                :         {
                              19060                 :                :             Relation    part_rel;
                              19061                 :                :             List       *thisPartConstraint;
                              19062                 :                : 
                              19063                 :                :             /*
                              19064                 :                :              * This is the minimum lock we need to prevent deadlocks.
                              19065                 :                :              */
 1910 andres@anarazel.de      19066                 :            197 :             part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
                              19067                 :                : 
                              19068                 :                :             /*
                              19069                 :                :              * Adjust the constraint for scanrel so that it matches this
                              19070                 :                :              * partition's attribute numbers.
                              19071                 :                :              */
                              19072                 :                :             thisPartConstraint =
 2195 alvherre@alvh.no-ip.    19073                 :            197 :                 map_partition_varattnos(partConstraint, 1,
                              19074                 :                :                                         part_rel, scanrel);
                              19075                 :                : 
                              19076                 :            197 :             QueuePartitionConstraintValidation(wqueue, part_rel,
                              19077                 :                :                                                thisPartConstraint,
                              19078                 :                :                                                validate_default);
 1910 andres@anarazel.de      19079                 :            197 :             table_close(part_rel, NoLock);  /* keep lock till commit */
                              19080                 :                :         }
                              19081                 :                :     }
                              19082                 :                : }
                              19083                 :                : 
                              19084                 :                : /*
                              19085                 :                :  * attachPartitionTable: attach a new partition to the partitioned table
                              19086                 :                :  *
                              19087                 :                :  * wqueue: the ALTER TABLE work queue; can be NULL when not running as part
                              19088                 :                :  *   of an ALTER TABLE sequence.
                              19089                 :                :  * rel: partitioned relation;
                              19090                 :                :  * attachrel: relation of attached partition;
                              19091                 :                :  * bound: bounds of attached relation.
                              19092                 :                :  */
                              19093                 :                : static void
    7 akorotkov@postgresql    19094                 :GNC        1223 : attachPartitionTable(List **wqueue, Relation rel, Relation attachrel, PartitionBoundSpec *bound)
                              19095                 :                : {
                              19096                 :                :     /* OK to create inheritance.  Rest of the checks performed there */
                              19097                 :           1223 :     CreateInheritance(attachrel, rel, true);
                              19098                 :                : 
                              19099                 :                :     /* Update the pg_class entry. */
                              19100                 :           1187 :     StorePartitionBound(attachrel, rel, bound);
                              19101                 :                : 
                              19102                 :                :     /* Ensure there exists a correct set of indexes in the partition. */
                              19103                 :           1187 :     AttachPartitionEnsureIndexes(wqueue, rel, attachrel);
                              19104                 :                : 
                              19105                 :                :     /* and triggers */
                              19106                 :           1169 :     CloneRowTriggersToPartition(rel, attachrel);
                              19107                 :                : 
                              19108                 :                :     /*
                              19109                 :                :      * Clone foreign key constraints.  Callee is responsible for setting up
                              19110                 :                :      * for phase 3 constraint verification.
                              19111                 :                :      */
                              19112                 :           1166 :     CloneForeignKeyConstraints(wqueue, rel, attachrel);
                              19113                 :           1166 : }
                              19114                 :                : 
                              19115                 :                : /*
                              19116                 :                :  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
                              19117                 :                :  *
                              19118                 :                :  * Return the address of the newly attached partition.
                              19119                 :                :  */
                              19120                 :                : static ObjectAddress
 1299 tgl@sss.pgh.pa.us       19121                 :CBC        1088 : ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd,
                              19122                 :                :                       AlterTableUtilityContext *context)
                              19123                 :                : {
                              19124                 :                :     Relation    attachrel,
                              19125                 :                :                 catalog;
                              19126                 :                :     List       *attachrel_children;
                              19127                 :                :     List       *partConstraint;
                              19128                 :                :     SysScanDesc scan;
                              19129                 :                :     ScanKeyData skey;
                              19130                 :                :     AttrNumber  attno;
                              19131                 :                :     int         natts;
                              19132                 :                :     TupleDesc   tupleDesc;
                              19133                 :                :     ObjectAddress address;
                              19134                 :                :     const char *trigger_name;
                              19135                 :                :     Oid         defaultPartOid;
                              19136                 :                :     List       *partBoundConstraint;
                              19137                 :           1088 :     ParseState *pstate = make_parsestate(NULL);
                              19138                 :                : 
                              19139                 :           1088 :     pstate->p_sourcetext = context->queryString;
                              19140                 :                : 
                              19141                 :                :     /*
                              19142                 :                :      * We must lock the default partition if one exists, because attaching a
                              19143                 :                :      * new partition will change its partition constraint.
                              19144                 :                :      */
                              19145                 :                :     defaultPartOid =
 1088 alvherre@alvh.no-ip.    19146                 :           1088 :         get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
 2410 rhaas@postgresql.org    19147         [ +  + ]:           1088 :     if (OidIsValid(defaultPartOid))
                              19148                 :             91 :         LockRelationOid(defaultPartOid, AccessExclusiveLock);
                              19149                 :                : 
 1910 andres@anarazel.de      19150                 :           1088 :     attachrel = table_openrv(cmd->name, AccessExclusiveLock);
                              19151                 :                : 
                              19152                 :                :     /*
                              19153                 :                :      * XXX I think it'd be a good idea to grab locks on all tables referenced
                              19154                 :                :      * by FKs at this point also.
                              19155                 :                :      */
                              19156                 :                : 
                              19157                 :                :     /*
                              19158                 :                :      * Must be owner of both parent and source table -- parent was checked by
                              19159                 :                :      * ATSimplePermissions call in ATPrepCmd
                              19160                 :                :      */
 1011 peter@eisentraut.org    19161                 :           1085 :     ATSimplePermissions(AT_AttachPartition, attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
                              19162                 :                : 
                              19163                 :                :     /* A partition can only have one parent */
 2446 rhaas@postgresql.org    19164         [ +  + ]:           1082 :     if (attachrel->rd_rel->relispartition)
 2685                         19165         [ +  - ]:              3 :         ereport(ERROR,
                              19166                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19167                 :                :                  errmsg("\"%s\" is already a partition",
                              19168                 :                :                         RelationGetRelationName(attachrel))));
                              19169                 :                : 
 2446                         19170         [ +  + ]:           1079 :     if (OidIsValid(attachrel->rd_rel->reloftype))
 2685                         19171         [ +  - ]:              3 :         ereport(ERROR,
                              19172                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19173                 :                :                  errmsg("cannot attach a typed table as partition")));
                              19174                 :                : 
                              19175                 :                :     /*
                              19176                 :                :      * Table being attached should not already be part of inheritance; either
                              19177                 :                :      * as a child table...
                              19178                 :                :      */
 1910 andres@anarazel.de      19179                 :           1076 :     catalog = table_open(InheritsRelationId, AccessShareLock);
 2685 rhaas@postgresql.org    19180                 :           1076 :     ScanKeyInit(&skey,
                              19181                 :                :                 Anum_pg_inherits_inhrelid,
                              19182                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              19183                 :                :                 ObjectIdGetDatum(RelationGetRelid(attachrel)));
                              19184                 :           1076 :     scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
                              19185                 :                :                               NULL, 1, &skey);
                              19186         [ +  + ]:           1076 :     if (HeapTupleIsValid(systable_getnext(scan)))
                              19187         [ +  - ]:              3 :         ereport(ERROR,
                              19188                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19189                 :                :                  errmsg("cannot attach inheritance child as partition")));
                              19190                 :           1073 :     systable_endscan(scan);
                              19191                 :                : 
                              19192                 :                :     /* ...or as a parent table (except the case when it is partitioned) */
                              19193                 :           1073 :     ScanKeyInit(&skey,
                              19194                 :                :                 Anum_pg_inherits_inhparent,
                              19195                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              19196                 :                :                 ObjectIdGetDatum(RelationGetRelid(attachrel)));
                              19197                 :           1073 :     scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
                              19198                 :                :                               1, &skey);
                              19199         [ +  + ]:           1073 :     if (HeapTupleIsValid(systable_getnext(scan)) &&
 2446                         19200         [ +  + ]:            124 :         attachrel->rd_rel->relkind == RELKIND_RELATION)
 2685                         19201         [ +  - ]:              3 :         ereport(ERROR,
                              19202                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19203                 :                :                  errmsg("cannot attach inheritance parent as partition")));
                              19204                 :           1070 :     systable_endscan(scan);
 1910 andres@anarazel.de      19205                 :           1070 :     table_close(catalog, AccessShareLock);
                              19206                 :                : 
                              19207                 :                :     /*
                              19208                 :                :      * Prevent circularity by seeing if rel is a partition of attachrel. (In
                              19209                 :                :      * particular, this disallows making a rel a partition of itself.)
                              19210                 :                :      *
                              19211                 :                :      * We do that by checking if rel is a member of the list of attachrel's
                              19212                 :                :      * partitions provided the latter is partitioned at all.  We want to avoid
                              19213                 :                :      * having to construct this list again, so we request the strongest lock
                              19214                 :                :      * on all partitions.  We need the strongest lock, because we may decide
                              19215                 :                :      * to scan them if we find out that the table being attached (or its leaf
                              19216                 :                :      * partitions) may contain rows that violate the partition constraint. If
                              19217                 :                :      * the table has a constraint that would prevent such rows, which by
                              19218                 :                :      * definition is present in all the partitions, we need not scan the
                              19219                 :                :      * table, nor its partitions.  But we cannot risk a deadlock by taking a
                              19220                 :                :      * weaker lock now and the stronger one only when needed.
                              19221                 :                :      */
 2446 rhaas@postgresql.org    19222                 :           1070 :     attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
                              19223                 :                :                                              AccessExclusiveLock, NULL);
                              19224         [ +  + ]:           1070 :     if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
 2685                         19225         [ +  - ]:              6 :         ereport(ERROR,
                              19226                 :                :                 (errcode(ERRCODE_DUPLICATE_TABLE),
                              19227                 :                :                  errmsg("circular inheritance not allowed"),
                              19228                 :                :                  errdetail("\"%s\" is already a child of \"%s\".",
                              19229                 :                :                            RelationGetRelationName(rel),
                              19230                 :                :                            RelationGetRelationName(attachrel))));
                              19231                 :                : 
                              19232                 :                :     /* If the parent is permanent, so must be all of its partitions. */
 2125 michael@paquier.xyz     19233         [ +  + ]:           1064 :     if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
                              19234         [ +  + ]:           1052 :         attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
                              19235         [ +  - ]:              3 :         ereport(ERROR,
                              19236                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19237                 :                :                  errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
                              19238                 :                :                         RelationGetRelationName(rel))));
                              19239                 :                : 
                              19240                 :                :     /* Temp parent cannot have a partition that is itself not a temp */
 2685 rhaas@postgresql.org    19241         [ +  + ]:           1061 :     if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
 2446                         19242         [ +  + ]:             12 :         attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
 2685                         19243         [ +  - ]:              9 :         ereport(ERROR,
                              19244                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19245                 :                :                  errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
                              19246                 :                :                         RelationGetRelationName(rel))));
                              19247                 :                : 
                              19248                 :                :     /* If the parent is temp, it must belong to this session */
                              19249         [ +  + ]:           1052 :     if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              19250         [ -  + ]:              3 :         !rel->rd_islocaltemp)
 2685 rhaas@postgresql.org    19251         [ #  # ]:UBC           0 :         ereport(ERROR,
                              19252                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19253                 :                :                  errmsg("cannot attach as partition of temporary relation of another session")));
                              19254                 :                : 
                              19255                 :                :     /* Ditto for the partition */
 2446 rhaas@postgresql.org    19256         [ +  + ]:CBC        1052 :     if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                              19257         [ -  + ]:              3 :         !attachrel->rd_islocaltemp)
 2685 rhaas@postgresql.org    19258         [ #  # ]:UBC           0 :         ereport(ERROR,
                              19259                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19260                 :                :                  errmsg("cannot attach temporary relation of another session as partition")));
                              19261                 :                : 
                              19262                 :                :     /*
                              19263                 :                :      * Check if attachrel has any identity columns or any columns that aren't
                              19264                 :                :      * in the parent.
                              19265                 :                :      */
 2446 rhaas@postgresql.org    19266                 :CBC        1052 :     tupleDesc = RelationGetDescr(attachrel);
 2685                         19267                 :           1052 :     natts = tupleDesc->natts;
                              19268         [ +  + ]:           3622 :     for (attno = 1; attno <= natts; attno++)
                              19269                 :                :     {
 2429 andres@anarazel.de      19270                 :           2588 :         Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
 2685 rhaas@postgresql.org    19271                 :           2588 :         char       *attributeName = NameStr(attribute->attname);
                              19272                 :                : 
                              19273                 :                :         /* Ignore dropped */
                              19274         [ +  + ]:           2588 :         if (attribute->attisdropped)
                              19275                 :            296 :             continue;
                              19276                 :                : 
   89 peter@eisentraut.org    19277         [ +  + ]:GNC        2292 :         if (attribute->attidentity)
                              19278         [ +  - ]:              9 :             ereport(ERROR,
                              19279                 :                :                     errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19280                 :                :                     errmsg("table \"%s\" being attached contains an identity column \"%s\"",
                              19281                 :                :                            RelationGetRelationName(attachrel), attributeName),
                              19282                 :                :                     errdetail("The new partition may not contain an identity column."));
                              19283                 :                : 
                              19284                 :                :         /* Try to find the column in parent (matching on column name) */
 2670 rhaas@postgresql.org    19285         [ +  + ]:CBC        2283 :         if (!SearchSysCacheExists2(ATTNAME,
                              19286                 :                :                                    ObjectIdGetDatum(RelationGetRelid(rel)),
                              19287                 :                :                                    CStringGetDatum(attributeName)))
 2685                         19288         [ +  - ]:              9 :             ereport(ERROR,
                              19289                 :                :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
                              19290                 :                :                      errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
                              19291                 :                :                             RelationGetRelationName(attachrel), attributeName,
                              19292                 :                :                             RelationGetRelationName(rel)),
                              19293                 :                :                      errdetail("The new partition may contain only the columns present in parent.")));
                              19294                 :                :     }
                              19295                 :                : 
                              19296                 :                :     /*
                              19297                 :                :      * If child_rel has row-level triggers with transition tables, we
                              19298                 :                :      * currently don't allow it to become a partition.  See also prohibitions
                              19299                 :                :      * in ATExecAddInherit() and CreateTrigger().
                              19300                 :                :      */
 2446                         19301                 :           1034 :     trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
 2482 rhodiumtoad@postgres    19302         [ +  + ]:           1034 :     if (trigger_name != NULL)
                              19303         [ +  - ]:              3 :         ereport(ERROR,
                              19304                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              19305                 :                :                  errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
                              19306                 :                :                         trigger_name, RelationGetRelationName(attachrel)),
                              19307                 :                :                  errdetail("ROW triggers with transition tables are not supported on partitions.")));
                              19308                 :                : 
                              19309                 :                :     /*
                              19310                 :                :      * Check that the new partition's bound is valid and does not overlap any
                              19311                 :                :      * of existing partitions of the parent - note that it does not return on
                              19312                 :                :      * error.
                              19313                 :                :      */
 2446 rhaas@postgresql.org    19314                 :           1031 :     check_new_partition_bound(RelationGetRelationName(attachrel), rel,
                              19315                 :                :                               cmd->bound, pstate);
                              19316                 :                : 
                              19317                 :                :     /* Attach a new partition to the partitioned table. */
    7 akorotkov@postgresql    19318                 :GNC        1013 :     attachPartitionTable(wqueue, rel, attachrel, cmd->bound);
                              19319                 :                : 
                              19320                 :                :     /*
                              19321                 :                :      * Generate partition constraint from the partition bound specification.
                              19322                 :                :      * If the parent itself is a partition, make sure to include its
                              19323                 :                :      * constraint as well.
                              19324                 :                :      */
 1005 john.naylor@postgres    19325                 :CBC         956 :     partBoundConstraint = get_qual_from_partbound(rel, cmd->bound);
 2410 rhaas@postgresql.org    19326                 :            956 :     partConstraint = list_concat(partBoundConstraint,
 2657                         19327                 :            956 :                                  RelationGetPartitionQual(rel));
                              19328                 :                : 
                              19329                 :                :     /* Skip validation if there are no constraints to validate. */
 2410                         19330         [ +  + ]:            956 :     if (partConstraint)
                              19331                 :                :     {
                              19332                 :                :         /*
                              19333                 :                :          * Run the partition quals through const-simplification similar to
                              19334                 :                :          * check constraints.  We skip canonicalize_qual, though, because
                              19335                 :                :          * partition quals should be in canonical form already.
                              19336                 :                :          */
                              19337                 :                :         partConstraint =
                              19338                 :            932 :             (List *) eval_const_expressions(NULL,
                              19339                 :                :                                             (Node *) partConstraint);
                              19340                 :                : 
                              19341                 :                :         /* XXX this sure looks wrong */
                              19342                 :            932 :         partConstraint = list_make1(make_ands_explicit(partConstraint));
                              19343                 :                : 
                              19344                 :                :         /*
                              19345                 :                :          * Adjust the generated constraint to match this partition's attribute
                              19346                 :                :          * numbers.
                              19347                 :                :          */
                              19348                 :            932 :         partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
                              19349                 :                :                                                  rel);
                              19350                 :                : 
                              19351                 :                :         /* Validate partition constraints against the table being attached. */
 2195 alvherre@alvh.no-ip.    19352                 :            932 :         QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
                              19353                 :                :                                            false);
                              19354                 :                :     }
                              19355                 :                : 
                              19356                 :                :     /*
                              19357                 :                :      * If we're attaching a partition other than the default partition and a
                              19358                 :                :      * default one exists, then that partition's partition constraint changes,
                              19359                 :                :      * so add an entry to the work queue to validate it, too.  (We must not do
                              19360                 :                :      * this when the partition being attached is the default one; we already
                              19361                 :                :      * did it above!)
                              19362                 :                :      */
 2410 rhaas@postgresql.org    19363         [ +  + ]:            956 :     if (OidIsValid(defaultPartOid))
                              19364                 :                :     {
                              19365                 :                :         Relation    defaultrel;
                              19366                 :                :         List       *defPartConstraint;
                              19367                 :                : 
 2195 alvherre@alvh.no-ip.    19368         [ -  + ]:             73 :         Assert(!cmd->bound->is_default);
                              19369                 :                : 
                              19370                 :                :         /* we already hold a lock on the default partition */
 1910 andres@anarazel.de      19371                 :             73 :         defaultrel = table_open(defaultPartOid, NoLock);
                              19372                 :                :         defPartConstraint =
 2410 rhaas@postgresql.org    19373                 :             73 :             get_proposed_default_constraint(partBoundConstraint);
                              19374                 :                : 
                              19375                 :                :         /*
                              19376                 :                :          * Map the Vars in the constraint expression from rel's attnos to
                              19377                 :                :          * defaultrel's.
                              19378                 :                :          */
                              19379                 :                :         defPartConstraint =
 1752 alvherre@alvh.no-ip.    19380                 :             73 :             map_partition_varattnos(defPartConstraint,
                              19381                 :                :                                     1, defaultrel, rel);
 2195                         19382                 :             73 :         QueuePartitionConstraintValidation(wqueue, defaultrel,
                              19383                 :                :                                            defPartConstraint, true);
                              19384                 :                : 
                              19385                 :                :         /* keep our lock until commit. */
 1910 andres@anarazel.de      19386                 :             73 :         table_close(defaultrel, NoLock);
                              19387                 :                :     }
                              19388                 :                : 
 2446 rhaas@postgresql.org    19389                 :            956 :     ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
                              19390                 :                : 
                              19391                 :                :     /*
                              19392                 :                :      * If the partition we just attached is partitioned itself, invalidate
                              19393                 :                :      * relcache for all descendent partitions too to ensure that their
                              19394                 :                :      * rd_partcheck expression trees are rebuilt; partitions already locked at
                              19395                 :                :      * the beginning of this function.
                              19396                 :                :      */
  909 alvherre@alvh.no-ip.    19397         [ +  + ]:            956 :     if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              19398                 :                :     {
                              19399                 :                :         ListCell   *l;
                              19400                 :                : 
                              19401   [ +  -  +  +  :            498 :         foreach(l, attachrel_children)
                                              +  + ]
                              19402                 :                :         {
                              19403                 :            337 :             CacheInvalidateRelcacheByRelid(lfirst_oid(l));
                              19404                 :                :         }
                              19405                 :                :     }
                              19406                 :                : 
                              19407                 :                :     /* keep our lock until commit */
 1910 andres@anarazel.de      19408                 :            956 :     table_close(attachrel, NoLock);
                              19409                 :                : 
 2685 rhaas@postgresql.org    19410                 :            956 :     return address;
                              19411                 :                : }
                              19412                 :                : 
                              19413                 :                : /*
                              19414                 :                :  * AttachPartitionEnsureIndexes
                              19415                 :                :  *      subroutine for ATExecAttachPartition to create/match indexes
                              19416                 :                :  *
                              19417                 :                :  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
                              19418                 :                :  * PARTITION: every partition must have an index attached to each index on the
                              19419                 :                :  * partitioned table.
                              19420                 :                :  */
                              19421                 :                : static void
  233 alvherre@alvh.no-ip.    19422                 :GNC        1187 : AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel)
                              19423                 :                : {
                              19424                 :                :     List       *idxes;
                              19425                 :                :     List       *attachRelIdxs;
                              19426                 :                :     Relation   *attachrelIdxRels;
                              19427                 :                :     IndexInfo **attachInfos;
                              19428                 :                :     ListCell   *cell;
                              19429                 :                :     MemoryContext cxt;
                              19430                 :                :     MemoryContext oldcxt;
                              19431                 :                : 
 2277 alvherre@alvh.no-ip.    19432                 :CBC        1187 :     cxt = AllocSetContextCreate(CurrentMemoryContext,
                              19433                 :                :                                 "AttachPartitionEnsureIndexes",
                              19434                 :                :                                 ALLOCSET_DEFAULT_SIZES);
                              19435                 :           1187 :     oldcxt = MemoryContextSwitchTo(cxt);
                              19436                 :                : 
                              19437                 :           1187 :     idxes = RelationGetIndexList(rel);
                              19438                 :           1187 :     attachRelIdxs = RelationGetIndexList(attachrel);
                              19439                 :           1187 :     attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
                              19440                 :           1187 :     attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
                              19441                 :                : 
                              19442                 :                :     /* Build arrays of all existing indexes and their IndexInfos */
                              19443   [ +  +  +  +  :           1351 :     foreach(cell, attachRelIdxs)
                                              +  + ]
                              19444                 :                :     {
                              19445                 :            164 :         Oid         cldIdxId = lfirst_oid(cell);
  233 alvherre@alvh.no-ip.    19446                 :GNC         164 :         int         i = foreach_current_index(cell);
                              19447                 :                : 
 2277 alvherre@alvh.no-ip.    19448                 :CBC         164 :         attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
                              19449                 :            164 :         attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
                              19450                 :                :     }
                              19451                 :                : 
                              19452                 :                :     /*
                              19453                 :                :      * If we're attaching a foreign table, we must fail if any of the indexes
                              19454                 :                :      * is a constraint index; otherwise, there's nothing to do here.  Do this
                              19455                 :                :      * before starting work, to avoid wasting the effort of building a few
                              19456                 :                :      * non-unique indexes before coming across a unique one.
                              19457                 :                :      */
 1754                         19458         [ +  + ]:           1187 :     if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
                              19459                 :                :     {
                              19460   [ +  +  +  +  :             43 :         foreach(cell, idxes)
                                              +  + ]
                              19461                 :                :         {
                              19462                 :             18 :             Oid         idx = lfirst_oid(cell);
                              19463                 :             18 :             Relation    idxRel = index_open(idx, AccessShareLock);
                              19464                 :                : 
                              19465         [ +  + ]:             18 :             if (idxRel->rd_index->indisunique ||
                              19466         [ -  + ]:             12 :                 idxRel->rd_index->indisprimary)
                              19467         [ +  - ]:              6 :                 ereport(ERROR,
                              19468                 :                :                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                              19469                 :                :                          errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
                              19470                 :                :                                 RelationGetRelationName(attachrel),
                              19471                 :                :                                 RelationGetRelationName(rel)),
                              19472                 :                :                          errdetail("Partitioned table \"%s\" contains unique indexes.",
                              19473                 :                :                                    RelationGetRelationName(rel))));
                              19474                 :             12 :             index_close(idxRel, AccessShareLock);
                              19475                 :                :         }
                              19476                 :                : 
                              19477                 :             25 :         goto out;
                              19478                 :                :     }
                              19479                 :                : 
                              19480                 :                :     /*
                              19481                 :                :      * For each index on the partitioned table, find a matching one in the
                              19482                 :                :      * partition-to-be; if one is not found, create one.
                              19483                 :                :      */
 2277                         19484   [ +  +  +  +  :           1454 :     foreach(cell, idxes)
                                              +  + ]
                              19485                 :                :     {
                              19486                 :            310 :         Oid         idx = lfirst_oid(cell);
                              19487                 :            310 :         Relation    idxRel = index_open(idx, AccessShareLock);
                              19488                 :                :         IndexInfo  *info;
                              19489                 :                :         AttrMap    *attmap;
                              19490                 :            310 :         bool        found = false;
                              19491                 :                :         Oid         constraintOid;
                              19492                 :                : 
                              19493                 :                :         /*
                              19494                 :                :          * Ignore indexes in the partitioned table other than partitioned
                              19495                 :                :          * indexes.
                              19496                 :                :          */
                              19497         [ -  + ]:            310 :         if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
                              19498                 :                :         {
 2277 alvherre@alvh.no-ip.    19499                 :UBC           0 :             index_close(idxRel, AccessShareLock);
                              19500                 :              0 :             continue;
                              19501                 :                :         }
                              19502                 :                : 
                              19503                 :                :         /* construct an indexinfo to compare existing indexes against */
 2277 alvherre@alvh.no-ip.    19504                 :CBC         310 :         info = BuildIndexInfo(idxRel);
 1579 michael@paquier.xyz     19505                 :            310 :         attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
                              19506                 :                :                                        RelationGetDescr(rel),
                              19507                 :                :                                        false);
 2246 alvherre@alvh.no-ip.    19508                 :            310 :         constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
                              19509                 :                : 
                              19510                 :                :         /*
                              19511                 :                :          * Scan the list of existing indexes in the partition-to-be, and mark
                              19512                 :                :          * the first matching, valid, unattached one we find, if any, as
                              19513                 :                :          * partition of the parent index.  If we find one, we're done.
                              19514                 :                :          */
  233 alvherre@alvh.no-ip.    19515         [ +  + ]:GNC         340 :         for (int i = 0; i < list_length(attachRelIdxs); i++)
                              19516                 :                :         {
 2180 tgl@sss.pgh.pa.us       19517                 :CBC         125 :             Oid         cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
                              19518                 :            125 :             Oid         cldConstrOid = InvalidOid;
                              19519                 :                : 
                              19520                 :                :             /* does this index have a parent?  if so, can't use it */
 2195 alvherre@alvh.no-ip.    19521         [ +  + ]:            125 :             if (attachrelIdxRels[i]->rd_rel->relispartition)
 2277                         19522                 :              6 :                 continue;
                              19523                 :                : 
                              19524                 :                :             /* If this index is invalid, can't use it */
  291 michael@paquier.xyz     19525         [ +  + ]:            119 :             if (!attachrelIdxRels[i]->rd_index->indisvalid)
                              19526                 :              3 :                 continue;
                              19527                 :                : 
 2277 alvherre@alvh.no-ip.    19528         [ +  + ]:            116 :             if (CompareIndexInfo(attachInfos[i], info,
                              19529                 :            116 :                                  attachrelIdxRels[i]->rd_indcollation,
 2277 alvherre@alvh.no-ip.    19530                 :GIC         116 :                                  idxRel->rd_indcollation,
 2277 alvherre@alvh.no-ip.    19531                 :CBC         116 :                                  attachrelIdxRels[i]->rd_opfamily,
 2277 alvherre@alvh.no-ip.    19532                 :GIC         116 :                                  idxRel->rd_opfamily,
                              19533                 :                :                                  attmap))
                              19534                 :                :             {
                              19535                 :                :                 /*
                              19536                 :                :                  * If this index is being created in the parent because of a
                              19537                 :                :                  * constraint, then the child needs to have a constraint also,
                              19538                 :                :                  * so look for one.  If there is no such constraint, this
                              19539                 :                :                  * index is no good, so keep looking.
                              19540                 :                :                  */
 2246 alvherre@alvh.no-ip.    19541         [ +  + ]:CBC          98 :                 if (OidIsValid(constraintOid))
                              19542                 :                :                 {
                              19543                 :                :                     cldConstrOid =
                              19544                 :             55 :                         get_relation_idx_constraint_oid(RelationGetRelid(attachrel),
                              19545                 :                :                                                         cldIdxId);
                              19546                 :                :                     /* no dice */
                              19547         [ +  + ]:             55 :                     if (!OidIsValid(cldConstrOid))
                              19548                 :              3 :                         continue;
                              19549                 :                :                 }
                              19550                 :                : 
                              19551                 :                :                 /* bingo. */
 2277                         19552                 :             95 :                 IndexSetParentIndex(attachrelIdxRels[i], idx);
 2246                         19553         [ +  + ]:             95 :                 if (OidIsValid(constraintOid))
 1889 tgl@sss.pgh.pa.us       19554                 :             52 :                     ConstraintSetParentConstraint(cldConstrOid, constraintOid,
                              19555                 :                :                                                   RelationGetRelid(attachrel));
 2277 alvherre@alvh.no-ip.    19556                 :             95 :                 found = true;
                              19557                 :                : 
 1838                         19558                 :             95 :                 CommandCounterIncrement();
 2277                         19559                 :             95 :                 break;
                              19560                 :                :             }
                              19561                 :                :         }
                              19562                 :                : 
                              19563                 :                :         /*
                              19564                 :                :          * If no suitable index was found in the partition-to-be, create one
                              19565                 :                :          * now.
                              19566                 :                :          */
                              19567         [ +  + ]:            310 :         if (!found)
                              19568                 :                :         {
                              19569                 :                :             IndexStmt  *stmt;
                              19570                 :                :             Oid         conOid;
                              19571                 :                : 
 1818 tgl@sss.pgh.pa.us       19572                 :            215 :             stmt = generateClonedIndexStmt(NULL,
                              19573                 :                :                                            idxRel, attmap,
                              19574                 :                :                                            &conOid);
                              19575                 :                : 
                              19576                 :                :             /*
                              19577                 :                :              * If the index is a primary key, mark all columns as NOT NULL if
                              19578                 :                :              * they aren't already.
                              19579                 :                :              */
  233 alvherre@alvh.no-ip.    19580         [ +  + ]:GNC         215 :             if (stmt->primary)
                              19581                 :                :             {
                              19582                 :            107 :                 MemoryContextSwitchTo(oldcxt);
                              19583         [ +  + ]:            220 :                 for (int j = 0; j < info->ii_NumIndexKeyAttrs; j++)
                              19584                 :                :                 {
                              19585                 :                :                     AttrNumber  childattno;
                              19586                 :                : 
                              19587                 :            113 :                     childattno = get_attnum(RelationGetRelid(attachrel),
                              19588                 :            113 :                                             get_attname(RelationGetRelid(rel),
                              19589                 :            113 :                                                         info->ii_IndexAttrNumbers[j],
                              19590                 :                :                                                         false));
                              19591                 :            113 :                     set_attnotnull(wqueue, attachrel, childattno,
                              19592                 :                :                                    true, AccessExclusiveLock);
                              19593                 :                :                 }
                              19594                 :            107 :                 MemoryContextSwitchTo(cxt);
                              19595                 :                :             }
                              19596                 :                : 
 2277 alvherre@alvh.no-ip.    19597                 :CBC         215 :             DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid,
                              19598                 :                :                         RelationGetRelid(idxRel),
                              19599                 :                :                         conOid,
                              19600                 :                :                         -1,
                              19601                 :                :                         true, false, false, false, false);
                              19602                 :                :         }
                              19603                 :                : 
                              19604                 :            298 :         index_close(idxRel, AccessShareLock);
                              19605                 :                :     }
                              19606                 :                : 
 1754                         19607                 :           1169 : out:
                              19608                 :                :     /* Clean up. */
  233 alvherre@alvh.no-ip.    19609         [ +  + ]:GNC        1327 :     for (int i = 0; i < list_length(attachRelIdxs); i++)
 2277 alvherre@alvh.no-ip.    19610                 :CBC         158 :         index_close(attachrelIdxRels[i], AccessShareLock);
                              19611                 :           1169 :     MemoryContextSwitchTo(oldcxt);
                              19612                 :           1169 :     MemoryContextDelete(cxt);
                              19613                 :           1169 : }
                              19614                 :                : 
                              19615                 :                : /*
                              19616                 :                :  * CloneRowTriggersToPartition
                              19617                 :                :  *      subroutine for ATExecAttachPartition/DefineRelation to create row
                              19618                 :                :  *      triggers on partitions
                              19619                 :                :  */
                              19620                 :                : static void
 2214                         19621                 :           1382 : CloneRowTriggersToPartition(Relation parent, Relation partition)
                              19622                 :                : {
                              19623                 :                :     Relation    pg_trigger;
                              19624                 :                :     ScanKeyData key;
                              19625                 :                :     SysScanDesc scan;
                              19626                 :                :     HeapTuple   tuple;
                              19627                 :                :     MemoryContext perTupCxt;
                              19628                 :                : 
                              19629                 :           1382 :     ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
                              19630                 :                :                 F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
 1910 andres@anarazel.de      19631                 :           1382 :     pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
 2214 alvherre@alvh.no-ip.    19632                 :           1382 :     scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
                              19633                 :                :                               true, NULL, 1, &key);
                              19634                 :                : 
                              19635                 :           1382 :     perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
                              19636                 :                :                                       "clone trig", ALLOCSET_SMALL_SIZES);
                              19637                 :                : 
                              19638         [ +  + ]:           2172 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
                              19639                 :                :     {
 1777 tgl@sss.pgh.pa.us       19640                 :            793 :         Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
                              19641                 :                :         CreateTrigStmt *trigStmt;
 2214 alvherre@alvh.no-ip.    19642                 :            793 :         Node       *qual = NULL;
                              19643                 :                :         Datum       value;
                              19644                 :                :         bool        isnull;
                              19645                 :            793 :         List       *cols = NIL;
 1741                         19646                 :            793 :         List       *trigargs = NIL;
                              19647                 :                :         MemoryContext oldcxt;
                              19648                 :                : 
                              19649                 :                :         /*
                              19650                 :                :          * Ignore statement-level triggers; those are not cloned.
                              19651                 :                :          */
 2214                         19652         [ +  + ]:            793 :         if (!TRIGGER_FOR_ROW(trigForm->tgtype))
 2214 alvherre@alvh.no-ip.    19653                 :GBC         703 :             continue;
                              19654                 :                : 
                              19655                 :                :         /*
                              19656                 :                :          * Don't clone internal triggers, because the constraint cloning code
                              19657                 :                :          * will.
                              19658                 :                :          */
  830 alvherre@alvh.no-ip.    19659         [ +  + ]:CBC         781 :         if (trigForm->tgisinternal)
 2203                         19660                 :            691 :             continue;
                              19661                 :                : 
                              19662                 :                :         /*
                              19663                 :                :          * Complain if we find an unexpected trigger type.
                              19664                 :                :          */
 1488                         19665         [ +  + ]:             90 :         if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
                              19666         [ -  + ]:             81 :             !TRIGGER_FOR_AFTER(trigForm->tgtype))
 2214 alvherre@alvh.no-ip.    19667         [ #  # ]:UBC           0 :             elog(ERROR, "unexpected trigger \"%s\" found",
                              19668                 :                :                  NameStr(trigForm->tgname));
                              19669                 :                : 
                              19670                 :                :         /* Use short-lived context for CREATE TRIGGER */
 1777 tgl@sss.pgh.pa.us       19671                 :CBC          90 :         oldcxt = MemoryContextSwitchTo(perTupCxt);
                              19672                 :                : 
                              19673                 :                :         /*
                              19674                 :                :          * If there is a WHEN clause, generate a 'cooked' version of it that's
                              19675                 :                :          * appropriate for the partition.
                              19676                 :                :          */
 2214 alvherre@alvh.no-ip.    19677                 :             90 :         value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
                              19678                 :                :                              RelationGetDescr(pg_trigger), &isnull);
                              19679         [ +  + ]:             90 :         if (!isnull)
                              19680                 :                :         {
                              19681                 :              3 :             qual = stringToNode(TextDatumGetCString(value));
                              19682                 :              3 :             qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
                              19683                 :                :                                                     partition, parent);
                              19684                 :              3 :             qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
                              19685                 :                :                                                     partition, parent);
                              19686                 :                :         }
                              19687                 :                : 
                              19688                 :                :         /*
                              19689                 :                :          * If there is a column list, transform it to a list of column names.
                              19690                 :                :          * Note we don't need to map this list in any way ...
                              19691                 :                :          */
                              19692         [ +  + ]:             90 :         if (trigForm->tgattr.dim1 > 0)
                              19693                 :                :         {
                              19694                 :                :             int         i;
                              19695                 :                : 
                              19696         [ +  + ]:              6 :             for (i = 0; i < trigForm->tgattr.dim1; i++)
                              19697                 :                :             {
                              19698                 :                :                 Form_pg_attribute col;
                              19699                 :                : 
                              19700                 :              3 :                 col = TupleDescAttr(parent->rd_att,
                              19701                 :                :                                     trigForm->tgattr.values[i] - 1);
 2183                         19702                 :              3 :                 cols = lappend(cols,
                              19703                 :              3 :                                makeString(pstrdup(NameStr(col->attname))));
                              19704                 :                :             }
                              19705                 :                :         }
                              19706                 :                : 
                              19707                 :                :         /* Reconstruct trigger arguments list. */
 1741                         19708         [ +  + ]:             90 :         if (trigForm->tgnargs > 0)
                              19709                 :                :         {
                              19710                 :                :             char       *p;
                              19711                 :                : 
                              19712                 :             18 :             value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
                              19713                 :                :                                  RelationGetDescr(pg_trigger), &isnull);
                              19714         [ -  + ]:             18 :             if (isnull)
 1741 alvherre@alvh.no-ip.    19715         [ #  # ]:UBC           0 :                 elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
                              19716                 :                :                      NameStr(trigForm->tgname), RelationGetRelationName(partition));
                              19717                 :                : 
 1741 alvherre@alvh.no-ip.    19718         [ +  - ]:CBC          18 :             p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
                              19719                 :                : 
                              19720         [ +  + ]:             42 :             for (int i = 0; i < trigForm->tgnargs; i++)
                              19721                 :                :             {
                              19722                 :             24 :                 trigargs = lappend(trigargs, makeString(pstrdup(p)));
                              19723                 :             24 :                 p += strlen(p) + 1;
                              19724                 :                :             }
                              19725                 :                :         }
                              19726                 :                : 
 2214                         19727                 :             90 :         trigStmt = makeNode(CreateTrigStmt);
 1247 tgl@sss.pgh.pa.us       19728                 :             90 :         trigStmt->replace = false;
                              19729                 :             90 :         trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
 2214 alvherre@alvh.no-ip.    19730                 :             90 :         trigStmt->trigname = NameStr(trigForm->tgname);
                              19731                 :             90 :         trigStmt->relation = NULL;
                              19732                 :             90 :         trigStmt->funcname = NULL;   /* passed separately */
 1741                         19733                 :             90 :         trigStmt->args = trigargs;
 2214                         19734                 :             90 :         trigStmt->row = true;
                              19735                 :             90 :         trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
                              19736                 :             90 :         trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
                              19737                 :             90 :         trigStmt->columns = cols;
                              19738                 :             90 :         trigStmt->whenClause = NULL; /* passed separately */
                              19739                 :             90 :         trigStmt->transitionRels = NIL; /* not supported at present */
                              19740                 :             90 :         trigStmt->deferrable = trigForm->tgdeferrable;
                              19741                 :             90 :         trigStmt->initdeferred = trigForm->tginitdeferred;
                              19742                 :             90 :         trigStmt->constrrel = NULL; /* passed separately */
                              19743                 :                : 
 1003                         19744                 :             90 :         CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
                              19745                 :                :                               trigForm->tgconstrrelid, InvalidOid, InvalidOid,
                              19746                 :                :                               trigForm->tgfoid, trigForm->oid, qual,
                              19747                 :             90 :                               false, true, trigForm->tgenabled);
                              19748                 :                : 
 1777 tgl@sss.pgh.pa.us       19749                 :             87 :         MemoryContextSwitchTo(oldcxt);
 2214 alvherre@alvh.no-ip.    19750                 :             87 :         MemoryContextReset(perTupCxt);
                              19751                 :                :     }
                              19752                 :                : 
                              19753                 :           1379 :     MemoryContextDelete(perTupCxt);
                              19754                 :                : 
                              19755                 :           1379 :     systable_endscan(scan);
 1910 andres@anarazel.de      19756                 :           1379 :     table_close(pg_trigger, RowExclusiveLock);
 2214 alvherre@alvh.no-ip.    19757                 :           1379 : }
                              19758                 :                : 
                              19759                 :                : /*
                              19760                 :                :  * ALTER TABLE DETACH PARTITION
                              19761                 :                :  *
                              19762                 :                :  * Return the address of the relation that is no longer a partition of rel.
                              19763                 :                :  *
                              19764                 :                :  * If concurrent mode is requested, we run in two transactions.  A side-
                              19765                 :                :  * effect is that this command cannot run in a multi-part ALTER TABLE.
                              19766                 :                :  * Currently, that's enforced by the grammar.
                              19767                 :                :  *
                              19768                 :                :  * The strategy for concurrency is to first modify the partition's
                              19769                 :                :  * pg_inherit catalog row to make it visible to everyone that the
                              19770                 :                :  * partition is detached, lock the partition against writes, and commit
                              19771                 :                :  * the transaction; anyone who requests the partition descriptor from
                              19772                 :                :  * that point onwards has to ignore such a partition.  In a second
                              19773                 :                :  * transaction, we wait until all transactions that could have seen the
                              19774                 :                :  * partition as attached are gone, then we remove the rest of partition
                              19775                 :                :  * metadata (pg_inherits and pg_class.relpartbounds).
                              19776                 :                :  */
                              19777                 :                : static ObjectAddress
 1116                         19778                 :            258 : ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel,
                              19779                 :                :                       RangeVar *name, bool concurrent)
                              19780                 :                : {
                              19781                 :                :     Relation    partRel;
                              19782                 :                :     ObjectAddress address;
                              19783                 :                :     Oid         defaultPartOid;
                              19784                 :                : 
                              19785                 :                :     /*
                              19786                 :                :      * We must lock the default partition, because detaching this partition
                              19787                 :                :      * will change its partition constraint.
                              19788                 :                :      */
                              19789                 :                :     defaultPartOid =
 1088                         19790                 :            258 :         get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
 2410 rhaas@postgresql.org    19791         [ +  + ]:            258 :     if (OidIsValid(defaultPartOid))
                              19792                 :                :     {
                              19793                 :                :         /*
                              19794                 :                :          * Concurrent detaching when a default partition exists is not
                              19795                 :                :          * supported. The main problem is that the default partition
                              19796                 :                :          * constraint would change.  And there's a definitional problem: what
                              19797                 :                :          * should happen to the tuples that are being inserted that belong to
                              19798                 :                :          * the partition being detached?  Putting them on the partition being
                              19799                 :                :          * detached would be wrong, since they'd become "lost" after the
                              19800                 :                :          * detaching completes but we cannot put them in the default partition
                              19801                 :                :          * either until we alter its partition constraint.
                              19802                 :                :          *
                              19803                 :                :          * I think we could solve this problem if we effected the constraint
                              19804                 :                :          * change before committing the first transaction.  But the lock would
                              19805                 :                :          * have to remain AEL and it would cause concurrent query planning to
                              19806                 :                :          * be blocked, so changing it that way would be even worse.
                              19807                 :                :          */
 1116 alvherre@alvh.no-ip.    19808         [ +  + ]:             56 :         if (concurrent)
                              19809         [ +  - ]:              6 :             ereport(ERROR,
                              19810                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19811                 :                :                      errmsg("cannot detach partitions concurrently when a default partition exists")));
 2410 rhaas@postgresql.org    19812                 :             50 :         LockRelationOid(defaultPartOid, AccessExclusiveLock);
                              19813                 :                :     }
                              19814                 :                : 
                              19815                 :                :     /*
                              19816                 :                :      * In concurrent mode, the partition is locked with share-update-exclusive
                              19817                 :                :      * in the first transaction.  This allows concurrent transactions to be
                              19818                 :                :      * doing DML to the partition.
                              19819                 :                :      */
 1116 alvherre@alvh.no-ip.    19820         [ +  + ]:            252 :     partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock :
                              19821                 :                :                            AccessExclusiveLock);
                              19822                 :                : 
                              19823                 :                :     /*
                              19824                 :                :      * Check inheritance conditions and either delete the pg_inherits row (in
                              19825                 :                :      * non-concurrent mode) or just set the inhdetachpending flag.
                              19826                 :                :      */
                              19827         [ +  + ]:            246 :     if (!concurrent)
                              19828                 :            173 :         RemoveInheritance(partRel, rel, false);
                              19829                 :                :     else
                              19830                 :             73 :         MarkInheritDetached(partRel, rel);
                              19831                 :                : 
                              19832                 :                :     /*
                              19833                 :                :      * Ensure that foreign keys still hold after this detach.  This keeps
                              19834                 :                :      * locks on the referencing tables, which prevents concurrent transactions
                              19835                 :                :      * from adding rows that we wouldn't see.  For this to work in concurrent
                              19836                 :                :      * mode, it is critical that the partition appears as no longer attached
                              19837                 :                :      * for the RI queries as soon as the first transaction commits.
                              19838                 :                :      */
 1838                         19839                 :            236 :     ATDetachCheckNoForeignKeyRefs(partRel);
                              19840                 :                : 
                              19841                 :                :     /*
                              19842                 :                :      * Concurrent mode has to work harder; first we add a new constraint to
                              19843                 :                :      * the partition that matches the partition constraint.  Then we close our
                              19844                 :                :      * existing transaction, and in a new one wait for all processes to catch
                              19845                 :                :      * up on the catalog updates we've done so far; at that point we can
                              19846                 :                :      * complete the operation.
                              19847                 :                :      */
 1116                         19848         [ +  + ]:            219 :     if (concurrent)
                              19849                 :                :     {
                              19850                 :                :         Oid         partrelid,
                              19851                 :                :                     parentrelid;
                              19852                 :                :         LOCKTAG     tag;
                              19853                 :                :         char       *parentrelname;
                              19854                 :                :         char       *partrelname;
                              19855                 :                : 
                              19856                 :                :         /*
                              19857                 :                :          * Add a new constraint to the partition being detached, which
                              19858                 :                :          * supplants the partition constraint (unless there is one already).
                              19859                 :                :          */
                              19860                 :             70 :         DetachAddConstraintIfNeeded(wqueue, partRel);
                              19861                 :                : 
                              19862                 :                :         /*
                              19863                 :                :          * We're almost done now; the only traces that remain are the
                              19864                 :                :          * pg_inherits tuple and the partition's relpartbounds.  Before we can
                              19865                 :                :          * remove those, we need to wait until all transactions that know that
                              19866                 :                :          * this is a partition are gone.
                              19867                 :                :          */
                              19868                 :                : 
                              19869                 :                :         /*
                              19870                 :                :          * Remember relation OIDs to re-acquire them later; and relation names
                              19871                 :                :          * too, for error messages if something is dropped in between.
                              19872                 :                :          */
                              19873                 :             70 :         partrelid = RelationGetRelid(partRel);
                              19874                 :             70 :         parentrelid = RelationGetRelid(rel);
                              19875                 :             70 :         parentrelname = MemoryContextStrdup(PortalContext,
                              19876                 :             70 :                                             RelationGetRelationName(rel));
                              19877                 :             70 :         partrelname = MemoryContextStrdup(PortalContext,
                              19878                 :             70 :                                           RelationGetRelationName(partRel));
                              19879                 :                : 
                              19880                 :                :         /* Invalidate relcache entries for the parent -- must be before close */
                              19881                 :             70 :         CacheInvalidateRelcache(rel);
                              19882                 :                : 
                              19883                 :             70 :         table_close(partRel, NoLock);
                              19884                 :             70 :         table_close(rel, NoLock);
                              19885                 :             70 :         tab->rel = NULL;
                              19886                 :                : 
                              19887                 :                :         /* Make updated catalog entry visible */
                              19888                 :             70 :         PopActiveSnapshot();
                              19889                 :             70 :         CommitTransactionCommand();
                              19890                 :                : 
                              19891                 :             70 :         StartTransactionCommand();
                              19892                 :                : 
                              19893                 :                :         /*
                              19894                 :                :          * Now wait.  This ensures that all queries that were planned
                              19895                 :                :          * including the partition are finished before we remove the rest of
                              19896                 :                :          * catalog entries.  We don't need or indeed want to acquire this
                              19897                 :                :          * lock, though -- that would block later queries.
                              19898                 :                :          *
                              19899                 :                :          * We don't need to concern ourselves with waiting for a lock on the
                              19900                 :                :          * partition itself, since we will acquire AccessExclusiveLock below.
                              19901                 :                :          */
                              19902                 :             70 :         SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid);
                              19903                 :             70 :         WaitForLockersMultiple(list_make1(&tag), AccessExclusiveLock, false);
                              19904                 :                : 
                              19905                 :                :         /*
                              19906                 :                :          * Now acquire locks in both relations again.  Note they may have been
                              19907                 :                :          * removed in the meantime, so care is required.
                              19908                 :                :          */
                              19909                 :             45 :         rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock);
                              19910                 :             45 :         partRel = try_relation_open(partrelid, AccessExclusiveLock);
                              19911                 :                : 
                              19912                 :                :         /* If the relations aren't there, something bad happened; bail out */
                              19913         [ -  + ]:             45 :         if (rel == NULL)
                              19914                 :                :         {
 1116 alvherre@alvh.no-ip.    19915         [ #  # ]:UBC           0 :             if (partRel != NULL)    /* shouldn't happen */
                              19916         [ #  # ]:              0 :                 elog(WARNING, "dangling partition \"%s\" remains, can't fix",
                              19917                 :                :                      partrelname);
                              19918         [ #  # ]:              0 :             ereport(ERROR,
                              19919                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19920                 :                :                      errmsg("partitioned table \"%s\" was removed concurrently",
                              19921                 :                :                             parentrelname)));
                              19922                 :                :         }
 1116 alvherre@alvh.no-ip.    19923         [ -  + ]:CBC          45 :         if (partRel == NULL)
 1116 alvherre@alvh.no-ip.    19924         [ #  # ]:UBC           0 :             ereport(ERROR,
                              19925                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              19926                 :                :                      errmsg("partition \"%s\" was removed concurrently", partrelname)));
                              19927                 :                : 
 1116 alvherre@alvh.no-ip.    19928                 :CBC          45 :         tab->rel = rel;
                              19929                 :                :     }
                              19930                 :                : 
                              19931                 :                :     /* Do the final part of detaching */
                              19932                 :            194 :     DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
                              19933                 :                : 
                              19934                 :            193 :     ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
                              19935                 :                : 
                              19936                 :                :     /* keep our lock until commit */
                              19937                 :            193 :     table_close(partRel, NoLock);
                              19938                 :                : 
                              19939                 :            193 :     return address;
                              19940                 :                : }
                              19941                 :                : 
                              19942                 :                : /*
                              19943                 :                :  * Second part of ALTER TABLE .. DETACH.
                              19944                 :                :  *
                              19945                 :                :  * This is separate so that it can be run independently when the second
                              19946                 :                :  * transaction of the concurrent algorithm fails (crash or abort).
                              19947                 :                :  */
                              19948                 :                : static void
                              19949                 :            345 : DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
                              19950                 :                :                         Oid defaultPartOid)
                              19951                 :                : {
                              19952                 :                :     Relation    classRel;
                              19953                 :                :     List       *fks;
                              19954                 :                :     ListCell   *cell;
                              19955                 :                :     List       *indexes;
                              19956                 :                :     Datum       new_val[Natts_pg_class];
                              19957                 :                :     bool        new_null[Natts_pg_class],
                              19958                 :                :                 new_repl[Natts_pg_class];
                              19959                 :                :     HeapTuple   tuple,
                              19960                 :                :                 newtuple;
  830                         19961                 :            345 :     Relation    trigrel = NULL;
                              19962                 :                : 
 1116                         19963         [ +  + ]:            345 :     if (concurrent)
                              19964                 :                :     {
                              19965                 :                :         /*
                              19966                 :                :          * We can remove the pg_inherits row now. (In the non-concurrent case,
                              19967                 :                :          * this was already done).
                              19968                 :                :          */
                              19969                 :             52 :         RemoveInheritance(partRel, rel, true);
                              19970                 :                :     }
                              19971                 :                : 
                              19972                 :                :     /* Drop any triggers that were cloned on creation/attach. */
 1454                         19973                 :            345 :     DropClonedTriggersFromPartition(RelationGetRelid(partRel));
                              19974                 :                : 
                              19975                 :                :     /*
                              19976                 :                :      * Detach any foreign keys that are inherited.  This includes creating
                              19977                 :                :      * additional action triggers.
                              19978                 :                :      */
 2011                         19979                 :            345 :     fks = copyObject(RelationGetFKeyList(partRel));
  830                         19980         [ +  + ]:            345 :     if (fks != NIL)
                              19981                 :             27 :         trigrel = table_open(TriggerRelationId, RowExclusiveLock);
 2011                         19982   [ +  +  +  +  :            387 :     foreach(cell, fks)
                                              +  + ]
                              19983                 :                :     {
                              19984                 :             42 :         ForeignKeyCacheInfo *fk = lfirst(cell);
                              19985                 :                :         HeapTuple   contup;
                              19986                 :                :         Form_pg_constraint conform;
                              19987                 :                :         Constraint *fkconstraint;
                              19988                 :                :         Oid         insertTriggerOid,
                              19989                 :                :                     updateTriggerOid;
                              19990                 :                : 
                              19991                 :             42 :         contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
 1806 tgl@sss.pgh.pa.us       19992         [ -  + ]:             42 :         if (!HeapTupleIsValid(contup))
 2011 alvherre@alvh.no-ip.    19993         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
 1910 alvherre@alvh.no-ip.    19994                 :CBC          42 :         conform = (Form_pg_constraint) GETSTRUCT(contup);
                              19995                 :                : 
                              19996                 :                :         /* consider only the inherited foreign keys */
                              19997         [ +  - ]:             42 :         if (conform->contype != CONSTRAINT_FOREIGN ||
                              19998         [ +  + ]:             42 :             !OidIsValid(conform->conparentid))
                              19999                 :                :         {
                              20000                 :              9 :             ReleaseSysCache(contup);
                              20001                 :              9 :             continue;
                              20002                 :                :         }
                              20003                 :                : 
                              20004                 :                :         /* unset conparentid and adjust conislocal, coninhcount, etc. */
 1889 tgl@sss.pgh.pa.us       20005                 :             33 :         ConstraintSetParentConstraint(fk->conoid, InvalidOid, InvalidOid);
                              20006                 :                : 
                              20007                 :                :         /*
                              20008                 :                :          * Also, look up the partition's "check" triggers corresponding to the
                              20009                 :                :          * constraint being detached and detach them from the parent triggers.
                              20010                 :                :          */
  830 alvherre@alvh.no-ip.    20011                 :             33 :         GetForeignKeyCheckTriggers(trigrel,
                              20012                 :                :                                    fk->conoid, fk->confrelid, fk->conrelid,
                              20013                 :                :                                    &insertTriggerOid, &updateTriggerOid);
                              20014         [ -  + ]:             33 :         Assert(OidIsValid(insertTriggerOid));
                              20015                 :             33 :         TriggerSetParentTrigger(trigrel, insertTriggerOid, InvalidOid,
                              20016                 :                :                                 RelationGetRelid(partRel));
                              20017         [ -  + ]:             33 :         Assert(OidIsValid(updateTriggerOid));
                              20018                 :             33 :         TriggerSetParentTrigger(trigrel, updateTriggerOid, InvalidOid,
                              20019                 :                :                                 RelationGetRelid(partRel));
                              20020                 :                : 
                              20021                 :                :         /*
                              20022                 :                :          * Make the action triggers on the referenced relation.  When this was
                              20023                 :                :          * a partition the action triggers pointed to the parent rel (they
                              20024                 :                :          * still do), but now we need separate ones of our own.
                              20025                 :                :          */
 1910                         20026                 :             33 :         fkconstraint = makeNode(Constraint);
  528                         20027                 :             33 :         fkconstraint->contype = CONSTRAINT_FOREIGN;
 1910                         20028                 :             33 :         fkconstraint->conname = pstrdup(NameStr(conform->conname));
                              20029                 :             33 :         fkconstraint->deferrable = conform->condeferrable;
                              20030                 :             33 :         fkconstraint->initdeferred = conform->condeferred;
  528                         20031                 :             33 :         fkconstraint->location = -1;
                              20032                 :             33 :         fkconstraint->pktable = NULL;
                              20033                 :             33 :         fkconstraint->fk_attrs = NIL;
                              20034                 :             33 :         fkconstraint->pk_attrs = NIL;
                              20035                 :             33 :         fkconstraint->fk_matchtype = conform->confmatchtype;
                              20036                 :             33 :         fkconstraint->fk_upd_action = conform->confupdtype;
                              20037                 :             33 :         fkconstraint->fk_del_action = conform->confdeltype;
                              20038                 :             33 :         fkconstraint->fk_del_set_cols = NIL;
                              20039                 :             33 :         fkconstraint->old_conpfeqop = NIL;
                              20040                 :             33 :         fkconstraint->old_pktable_oid = InvalidOid;
                              20041                 :             33 :         fkconstraint->skip_validation = false;
                              20042                 :             33 :         fkconstraint->initially_valid = true;
                              20043                 :                : 
 1910                         20044                 :             33 :         createForeignKeyActionTriggers(partRel, conform->confrelid,
                              20045                 :                :                                        fkconstraint, fk->conoid,
                              20046                 :                :                                        conform->conindid,
                              20047                 :                :                                        InvalidOid, InvalidOid,
                              20048                 :                :                                        NULL, NULL);
                              20049                 :                : 
 2011                         20050                 :             33 :         ReleaseSysCache(contup);
                              20051                 :                :     }
                              20052                 :            345 :     list_free_deep(fks);
  830                         20053         [ +  + ]:            345 :     if (trigrel)
                              20054                 :             27 :         table_close(trigrel, RowExclusiveLock);
                              20055                 :                : 
                              20056                 :                :     /*
                              20057                 :                :      * Any sub-constraints that are in the referenced-side of a larger
                              20058                 :                :      * constraint have to be removed.  This partition is no longer part of the
                              20059                 :                :      * key space of the constraint.
                              20060                 :                :      */
 1838                         20061   [ +  +  +  +  :            366 :     foreach(cell, GetParentedForeignKeyRefs(partRel))
                                              +  + ]
                              20062                 :                :     {
                              20063                 :             22 :         Oid         constrOid = lfirst_oid(cell);
                              20064                 :                :         ObjectAddress constraint;
                              20065                 :                : 
                              20066                 :             22 :         ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
                              20067                 :             22 :         deleteDependencyRecordsForClass(ConstraintRelationId,
                              20068                 :                :                                         constrOid,
                              20069                 :                :                                         ConstraintRelationId,
                              20070                 :                :                                         DEPENDENCY_INTERNAL);
                              20071                 :             22 :         CommandCounterIncrement();
                              20072                 :                : 
                              20073                 :             22 :         ObjectAddressSet(constraint, ConstraintRelationId, constrOid);
                              20074                 :             22 :         performDeletion(&constraint, DROP_RESTRICT, 0);
                              20075                 :                :     }
                              20076                 :                : 
                              20077                 :                :     /* Now we can detach indexes */
 1116                         20078                 :            344 :     indexes = RelationGetIndexList(partRel);
                              20079   [ +  +  +  +  :            501 :     foreach(cell, indexes)
                                              +  + ]
                              20080                 :                :     {
                              20081                 :            157 :         Oid         idxid = lfirst_oid(cell);
                              20082                 :                :         Relation    idx;
                              20083                 :                :         Oid         constrOid;
                              20084                 :                : 
                              20085         [ +  + ]:            157 :         if (!has_superclass(idxid))
                              20086                 :              6 :             continue;
                              20087                 :                : 
                              20088         [ -  + ]:            151 :         Assert((IndexGetRelation(get_partition_parent(idxid, false), false) ==
                              20089                 :                :                 RelationGetRelid(rel)));
                              20090                 :                : 
                              20091                 :            151 :         idx = index_open(idxid, AccessExclusiveLock);
                              20092                 :            151 :         IndexSetParentIndex(idx, InvalidOid);
                              20093                 :                : 
                              20094                 :                :         /* If there's a constraint associated with the index, detach it too */
                              20095                 :            151 :         constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel),
                              20096                 :                :                                                     idxid);
                              20097         [ +  + ]:            151 :         if (OidIsValid(constrOid))
                              20098                 :             60 :             ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
                              20099                 :                : 
                              20100                 :            151 :         index_close(idx, NoLock);
                              20101                 :                :     }
                              20102                 :                : 
                              20103                 :                :     /* Update pg_class tuple */
                              20104                 :            344 :     classRel = table_open(RelationRelationId, RowExclusiveLock);
                              20105                 :            344 :     tuple = SearchSysCacheCopy1(RELOID,
                              20106                 :                :                                 ObjectIdGetDatum(RelationGetRelid(partRel)));
                              20107         [ -  + ]:            344 :     if (!HeapTupleIsValid(tuple))
 1116 alvherre@alvh.no-ip.    20108         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for relation %u",
                              20109                 :                :              RelationGetRelid(partRel));
 1116 alvherre@alvh.no-ip.    20110         [ -  + ]:CBC         344 :     Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
                              20111                 :                : 
                              20112                 :                :     /* Clear relpartbound and reset relispartition */
                              20113                 :            344 :     memset(new_val, 0, sizeof(new_val));
                              20114                 :            344 :     memset(new_null, false, sizeof(new_null));
                              20115                 :            344 :     memset(new_repl, false, sizeof(new_repl));
                              20116                 :            344 :     new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
                              20117                 :            344 :     new_null[Anum_pg_class_relpartbound - 1] = true;
                              20118                 :            344 :     new_repl[Anum_pg_class_relpartbound - 1] = true;
                              20119                 :            344 :     newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
                              20120                 :                :                                  new_val, new_null, new_repl);
                              20121                 :                : 
                              20122                 :            344 :     ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
                              20123                 :            344 :     CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
                              20124                 :            344 :     heap_freetuple(newtuple);
                              20125                 :            344 :     table_close(classRel, RowExclusiveLock);
                              20126                 :                : 
                              20127                 :                :     /*
                              20128                 :                :      * Drop identity property from all identity columns of partition.
                              20129                 :                :      */
   89 peter@eisentraut.org    20130         [ +  + ]:GNC        1226 :     for (int attno = 0; attno < RelationGetNumberOfAttributes(partRel); attno++)
                              20131                 :                :     {
                              20132                 :            882 :         Form_pg_attribute attr = TupleDescAttr(partRel->rd_att, attno);
                              20133                 :                : 
                              20134   [ +  +  +  + ]:            882 :         if (!attr->attisdropped && attr->attidentity)
                              20135                 :             15 :             ATExecDropIdentity(partRel, NameStr(attr->attname), false,
                              20136                 :                :                                AccessExclusiveLock, true, true);
                              20137                 :                :     }
                              20138                 :                : 
 1116 alvherre@alvh.no-ip.    20139         [ +  + ]:CBC         344 :     if (OidIsValid(defaultPartOid))
                              20140                 :                :     {
                              20141                 :                :         /*
                              20142                 :                :          * If the relation being detached is the default partition itself,
                              20143                 :                :          * remove it from the parent's pg_partitioned_table entry.
                              20144                 :                :          *
                              20145                 :                :          * If not, we must invalidate default partition's relcache entry, as
                              20146                 :                :          * in StorePartitionBound: its partition constraint depends on every
                              20147                 :                :          * other partition's partition constraint.
                              20148                 :                :          */
                              20149         [ +  + ]:            116 :         if (RelationGetRelid(partRel) == defaultPartOid)
                              20150                 :             19 :             update_default_partition_oid(RelationGetRelid(rel), InvalidOid);
                              20151                 :                :         else
                              20152                 :             97 :             CacheInvalidateRelcacheByRelid(defaultPartOid);
                              20153                 :                :     }
                              20154                 :                : 
                              20155                 :                :     /*
                              20156                 :                :      * Invalidate the parent's relcache so that the partition is no longer
                              20157                 :                :      * included in its partition descriptor.
                              20158                 :                :      */
 2685 rhaas@postgresql.org    20159                 :            344 :     CacheInvalidateRelcache(rel);
                              20160                 :                : 
                              20161                 :                :     /*
                              20162                 :                :      * If the partition we just detached is partitioned itself, invalidate
                              20163                 :                :      * relcache for all descendent partitions too to ensure that their
                              20164                 :                :      * rd_partcheck expression trees are rebuilt; must lock partitions before
                              20165                 :                :      * doing so, using the same lockmode as what partRel has been locked with
                              20166                 :                :      * by the caller.
                              20167                 :                :      */
  909 alvherre@alvh.no-ip.    20168         [ +  + ]:            344 :     if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                              20169                 :                :     {
                              20170                 :                :         List       *children;
                              20171                 :                : 
                              20172                 :             25 :         children = find_all_inheritors(RelationGetRelid(partRel),
                              20173                 :                :                                        AccessExclusiveLock, NULL);
                              20174   [ +  -  +  +  :             81 :         foreach(cell, children)
                                              +  + ]
                              20175                 :                :         {
                              20176                 :             56 :             CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
                              20177                 :                :         }
                              20178                 :                :     }
 1116                         20179                 :            344 : }
                              20180                 :                : 
                              20181                 :                : /*
                              20182                 :                :  * ALTER TABLE ... DETACH PARTITION ... FINALIZE
                              20183                 :                :  *
                              20184                 :                :  * To use when a DETACH PARTITION command previously did not run to
                              20185                 :                :  * completion; this completes the detaching process.
                              20186                 :                :  */
                              20187                 :                : static ObjectAddress
                              20188                 :              7 : ATExecDetachPartitionFinalize(Relation rel, RangeVar *name)
                              20189                 :                : {
                              20190                 :                :     Relation    partRel;
                              20191                 :                :     ObjectAddress address;
                              20192                 :              7 :     Snapshot    snap = GetActiveSnapshot();
                              20193                 :                : 
                              20194                 :              7 :     partRel = table_openrv(name, AccessExclusiveLock);
                              20195                 :                : 
                              20196                 :                :     /*
                              20197                 :                :      * Wait until existing snapshots are gone.  This is important if the
                              20198                 :                :      * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the
                              20199                 :                :      * user could immediately run DETACH FINALIZE without actually waiting for
                              20200                 :                :      * existing transactions.  We must not complete the detach action until
                              20201                 :                :      * all such queries are complete (otherwise we would present them with an
                              20202                 :                :      * inconsistent view of catalogs).
                              20203                 :                :      */
                              20204                 :              7 :     WaitForOlderSnapshots(snap->xmin, false);
                              20205                 :                : 
                              20206                 :              7 :     DetachPartitionFinalize(rel, partRel, true, InvalidOid);
                              20207                 :                : 
 2685 rhaas@postgresql.org    20208                 :              7 :     ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
                              20209                 :                : 
 1910 andres@anarazel.de      20210                 :              7 :     table_close(partRel, NoLock);
                              20211                 :                : 
 2685 rhaas@postgresql.org    20212                 :              7 :     return address;
                              20213                 :                : }
                              20214                 :                : 
                              20215                 :                : /*
                              20216                 :                :  * DetachAddConstraintIfNeeded
                              20217                 :                :  *      Subroutine for ATExecDetachPartition.  Create a constraint that
                              20218                 :                :  *      takes the place of the partition constraint, but avoid creating
                              20219                 :                :  *      a dupe if an constraint already exists which implies the needed
                              20220                 :                :  *      constraint.
                              20221                 :                :  */
                              20222                 :                : static void
 1116 alvherre@alvh.no-ip.    20223                 :             70 : DetachAddConstraintIfNeeded(List **wqueue, Relation partRel)
                              20224                 :                : {
                              20225                 :                :     List       *constraintExpr;
                              20226                 :                : 
 1089                         20227                 :             70 :     constraintExpr = RelationGetPartitionQual(partRel);
                              20228                 :             70 :     constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr);
                              20229                 :                : 
                              20230                 :                :     /*
                              20231                 :                :      * Avoid adding a new constraint if the needed constraint is implied by an
                              20232                 :                :      * existing constraint
                              20233                 :                :      */
                              20234         [ +  + ]:             70 :     if (!PartConstraintImpliedByRelConstraint(partRel, constraintExpr))
                              20235                 :                :     {
                              20236                 :                :         AlteredTableInfo *tab;
                              20237                 :                :         Constraint *n;
                              20238                 :                : 
                              20239                 :             67 :         tab = ATGetQueueEntry(wqueue, partRel);
                              20240                 :                : 
                              20241                 :                :         /* Add constraint on partition, equivalent to the partition constraint */
                              20242                 :             67 :         n = makeNode(Constraint);
                              20243                 :             67 :         n->contype = CONSTR_CHECK;
                              20244                 :             67 :         n->conname = NULL;
                              20245                 :             67 :         n->location = -1;
                              20246                 :             67 :         n->is_no_inherit = false;
                              20247                 :             67 :         n->raw_expr = NULL;
                              20248                 :             67 :         n->cooked_expr = nodeToString(make_ands_explicit(constraintExpr));
                              20249                 :             67 :         n->initially_valid = true;
                              20250                 :             67 :         n->skip_validation = true;
                              20251                 :                :         /* It's a re-add, since it nominally already exists */
  233 alvherre@alvh.no-ip.    20252                 :GNC          67 :         ATAddCheckNNConstraint(wqueue, tab, partRel, n,
                              20253                 :                :                                true, false, true, ShareUpdateExclusiveLock);
                              20254                 :                :     }
 1116 alvherre@alvh.no-ip.    20255                 :CBC          70 : }
                              20256                 :                : 
                              20257                 :                : /*
                              20258                 :                :  * DropClonedTriggersFromPartition
                              20259                 :                :  *      subroutine for ATExecDetachPartition to remove any triggers that were
                              20260                 :                :  *      cloned to the partition when it was created-as-partition or attached.
                              20261                 :                :  *      This undoes what CloneRowTriggersToPartition did.
                              20262                 :                :  */
                              20263                 :                : static void
 1454                         20264                 :            345 : DropClonedTriggersFromPartition(Oid partitionId)
                              20265                 :                : {
                              20266                 :                :     ScanKeyData skey;
                              20267                 :                :     SysScanDesc scan;
                              20268                 :                :     HeapTuple   trigtup;
                              20269                 :                :     Relation    tgrel;
                              20270                 :                :     ObjectAddresses *objects;
                              20271                 :                : 
                              20272                 :            345 :     objects = new_object_addresses();
                              20273                 :                : 
                              20274                 :                :     /*
                              20275                 :                :      * Scan pg_trigger to search for all triggers on this rel.
                              20276                 :                :      */
                              20277                 :            345 :     ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
                              20278                 :                :                 F_OIDEQ, ObjectIdGetDatum(partitionId));
                              20279                 :            345 :     tgrel = table_open(TriggerRelationId, RowExclusiveLock);
                              20280                 :            345 :     scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
                              20281                 :                :                               true, NULL, 1, &skey);
                              20282         [ +  + ]:            494 :     while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
                              20283                 :                :     {
                              20284                 :            149 :         Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup);
                              20285                 :                :         ObjectAddress trig;
                              20286                 :                : 
                              20287                 :                :         /* Ignore triggers that weren't cloned */
                              20288         [ +  + ]:            149 :         if (!OidIsValid(pg_trigger->tgparentid))
                              20289                 :            128 :             continue;
                              20290                 :                : 
                              20291                 :                :         /*
                              20292                 :                :          * Ignore internal triggers that are implementation objects of foreign
                              20293                 :                :          * keys, because these will be detached when the foreign keys
                              20294                 :                :          * themselves are.
                              20295                 :                :          */
  830                         20296         [ +  + ]:            131 :         if (OidIsValid(pg_trigger->tgconstrrelid))
                              20297                 :            110 :             continue;
                              20298                 :                : 
                              20299                 :                :         /*
                              20300                 :                :          * This is ugly, but necessary: remove the dependency markings on the
                              20301                 :                :          * trigger so that it can be removed.
                              20302                 :                :          */
 1454                         20303                 :             21 :         deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
                              20304                 :                :                                         TriggerRelationId,
                              20305                 :                :                                         DEPENDENCY_PARTITION_PRI);
                              20306                 :             21 :         deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
                              20307                 :                :                                         RelationRelationId,
                              20308                 :                :                                         DEPENDENCY_PARTITION_SEC);
                              20309                 :                : 
                              20310                 :                :         /* remember this trigger to remove it below */
                              20311                 :             21 :         ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid);
                              20312                 :             21 :         add_exact_object_address(&trig, objects);
                              20313                 :                :     }
                              20314                 :                : 
                              20315                 :                :     /* make the dependency removal visible to the deletion below */
                              20316                 :            345 :     CommandCounterIncrement();
                              20317                 :            345 :     performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
                              20318                 :                : 
                              20319                 :                :     /* done */
                              20320                 :            345 :     free_object_addresses(objects);
                              20321                 :            345 :     systable_endscan(scan);
                              20322                 :            345 :     table_close(tgrel, RowExclusiveLock);
                              20323                 :            345 : }
                              20324                 :                : 
                              20325                 :                : /*
                              20326                 :                :  * Before acquiring lock on an index, acquire the same lock on the owning
                              20327                 :                :  * table.
                              20328                 :                :  */
                              20329                 :                : struct AttachIndexCallbackState
                              20330                 :                : {
                              20331                 :                :     Oid         partitionOid;
                              20332                 :                :     Oid         parentTblOid;
                              20333                 :                :     bool        lockedParentTbl;
                              20334                 :                : };
                              20335                 :                : 
                              20336                 :                : static void
 2277                         20337                 :            203 : RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
                              20338                 :                :                                void *arg)
                              20339                 :                : {
                              20340                 :                :     struct AttachIndexCallbackState *state;
                              20341                 :                :     Form_pg_class classform;
                              20342                 :                :     HeapTuple   tuple;
                              20343                 :                : 
                              20344                 :            203 :     state = (struct AttachIndexCallbackState *) arg;
                              20345                 :                : 
                              20346         [ +  + ]:            203 :     if (!state->lockedParentTbl)
                              20347                 :                :     {
                              20348                 :            186 :         LockRelationOid(state->parentTblOid, AccessShareLock);
                              20349                 :            186 :         state->lockedParentTbl = true;
                              20350                 :                :     }
                              20351                 :                : 
                              20352                 :                :     /*
                              20353                 :                :      * If we previously locked some other heap, and the name we're looking up
                              20354                 :                :      * no longer refers to an index on that relation, release the now-useless
                              20355                 :                :      * lock.  XXX maybe we should do *after* we verify whether the index does
                              20356                 :                :      * not actually belong to the same relation ...
                              20357                 :                :      */
                              20358   [ +  +  -  + ]:            203 :     if (relOid != oldRelOid && OidIsValid(state->partitionOid))
                              20359                 :                :     {
 2277 alvherre@alvh.no-ip.    20360                 :UBC           0 :         UnlockRelationOid(state->partitionOid, AccessShareLock);
                              20361                 :              0 :         state->partitionOid = InvalidOid;
                              20362                 :                :     }
                              20363                 :                : 
                              20364                 :                :     /* Didn't find a relation, so no need for locking or permission checks. */
 2277 alvherre@alvh.no-ip.    20365         [ +  + ]:CBC         203 :     if (!OidIsValid(relOid))
                              20366                 :              4 :         return;
                              20367                 :                : 
                              20368                 :            199 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
                              20369         [ -  + ]:            199 :     if (!HeapTupleIsValid(tuple))
 2277 alvherre@alvh.no-ip.    20370                 :UBC           0 :         return;                 /* concurrently dropped, so nothing to do */
 2277 alvherre@alvh.no-ip.    20371                 :CBC         199 :     classform = (Form_pg_class) GETSTRUCT(tuple);
                              20372         [ +  + ]:            199 :     if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
                              20373         [ +  + ]:            152 :         classform->relkind != RELKIND_INDEX)
                              20374         [ +  - ]:              3 :         ereport(ERROR,
                              20375                 :                :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              20376                 :                :                  errmsg("\"%s\" is not an index", rv->relname)));
                              20377                 :            196 :     ReleaseSysCache(tuple);
                              20378                 :                : 
                              20379                 :                :     /*
                              20380                 :                :      * Since we need only examine the heap's tupledesc, an access share lock
                              20381                 :                :      * on it (preventing any DDL) is sufficient.
                              20382                 :                :      */
                              20383                 :            196 :     state->partitionOid = IndexGetRelation(relOid, false);
                              20384                 :            196 :     LockRelationOid(state->partitionOid, AccessShareLock);
                              20385                 :                : }
                              20386                 :                : 
                              20387                 :                : /*
                              20388                 :                :  * ALTER INDEX i1 ATTACH PARTITION i2
                              20389                 :                :  */
                              20390                 :                : static ObjectAddress
                              20391                 :            186 : ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
                              20392                 :                : {
                              20393                 :                :     Relation    partIdx;
                              20394                 :                :     Relation    partTbl;
                              20395                 :                :     Relation    parentTbl;
                              20396                 :                :     ObjectAddress address;
                              20397                 :                :     Oid         partIdxId;
                              20398                 :                :     Oid         currParent;
                              20399                 :                :     struct AttachIndexCallbackState state;
                              20400                 :                : 
                              20401                 :                :     /*
                              20402                 :                :      * We need to obtain lock on the index 'name' to modify it, but we also
                              20403                 :                :      * need to read its owning table's tuple descriptor -- so we need to lock
                              20404                 :                :      * both.  To avoid deadlocks, obtain lock on the table before doing so on
                              20405                 :                :      * the index.  Furthermore, we need to examine the parent table of the
                              20406                 :                :      * partition, so lock that one too.
                              20407                 :                :      */
                              20408                 :            186 :     state.partitionOid = InvalidOid;
                              20409                 :            186 :     state.parentTblOid = parentIdx->rd_index->indrelid;
                              20410                 :            186 :     state.lockedParentTbl = false;
                              20411                 :                :     partIdxId =
 2207 andres@anarazel.de      20412                 :            186 :         RangeVarGetRelidExtended(name, AccessExclusiveLock, 0,
                              20413                 :                :                                  RangeVarCallbackForAttachIndex,
                              20414                 :                :                                  (void *) &state);
                              20415                 :                :     /* Not there? */
 2277 alvherre@alvh.no-ip.    20416         [ -  + ]:            180 :     if (!OidIsValid(partIdxId))
 2277 alvherre@alvh.no-ip.    20417         [ #  # ]:UBC           0 :         ereport(ERROR,
                              20418                 :                :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                              20419                 :                :                  errmsg("index \"%s\" does not exist", name->relname)));
                              20420                 :                : 
                              20421                 :                :     /* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
 2277 alvherre@alvh.no-ip.    20422                 :CBC         180 :     partIdx = relation_open(partIdxId, AccessExclusiveLock);
                              20423                 :                : 
                              20424                 :                :     /* we already hold locks on both tables, so this is safe: */
                              20425                 :            180 :     parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
                              20426                 :            180 :     partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
                              20427                 :                : 
                              20428                 :            180 :     ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
                              20429                 :                : 
                              20430                 :                :     /* Silently do nothing if already in the right state */
 2195                         20431                 :            360 :     currParent = partIdx->rd_rel->relispartition ?
 1116                         20432         [ +  + ]:            180 :         get_partition_parent(partIdxId, false) : InvalidOid;
 2277                         20433         [ +  + ]:            180 :     if (currParent != RelationGetRelid(parentIdx))
                              20434                 :                :     {
                              20435                 :                :         IndexInfo  *childInfo;
                              20436                 :                :         IndexInfo  *parentInfo;
                              20437                 :                :         AttrMap    *attmap;
                              20438                 :                :         bool        found;
                              20439                 :                :         int         i;
                              20440                 :                :         PartitionDesc partDesc;
                              20441                 :                :         Oid         constraintOid,
 2246                         20442                 :            174 :                     cldConstrId = InvalidOid;
                              20443                 :                : 
                              20444                 :                :         /*
                              20445                 :                :          * If this partition already has an index attached, refuse the
                              20446                 :                :          * operation.
                              20447                 :                :          */
 2277                         20448                 :            174 :         refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
                              20449                 :                : 
                              20450         [ -  + ]:            171 :         if (OidIsValid(currParent))
 2277 alvherre@alvh.no-ip.    20451         [ #  # ]:UBC           0 :             ereport(ERROR,
                              20452                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              20453                 :                :                      errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              20454                 :                :                             RelationGetRelationName(partIdx),
                              20455                 :                :                             RelationGetRelationName(parentIdx)),
                              20456                 :                :                      errdetail("Index \"%s\" is already attached to another index.",
                              20457                 :                :                                RelationGetRelationName(partIdx))));
                              20458                 :                : 
                              20459                 :                :         /* Make sure it indexes a partition of the other index's table */
 1088 alvherre@alvh.no-ip.    20460                 :CBC         171 :         partDesc = RelationGetPartitionDesc(parentTbl, true);
 2277                         20461                 :            171 :         found = false;
                              20462         [ +  + ]:            266 :         for (i = 0; i < partDesc->nparts; i++)
                              20463                 :                :         {
                              20464         [ +  + ]:            263 :             if (partDesc->oids[i] == state.partitionOid)
                              20465                 :                :             {
                              20466                 :            168 :                 found = true;
                              20467                 :            168 :                 break;
                              20468                 :                :             }
                              20469                 :                :         }
                              20470         [ +  + ]:            171 :         if (!found)
                              20471         [ +  - ]:              3 :             ereport(ERROR,
                              20472                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              20473                 :                :                      errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              20474                 :                :                             RelationGetRelationName(partIdx),
                              20475                 :                :                             RelationGetRelationName(parentIdx)),
                              20476                 :                :                      errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
                              20477                 :                :                                RelationGetRelationName(partIdx),
                              20478                 :                :                                RelationGetRelationName(parentTbl))));
                              20479                 :                : 
                              20480                 :                :         /* Ensure the indexes are compatible */
                              20481                 :            168 :         childInfo = BuildIndexInfo(partIdx);
                              20482                 :            168 :         parentInfo = BuildIndexInfo(parentIdx);
 1579 michael@paquier.xyz     20483                 :            168 :         attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
                              20484                 :                :                                        RelationGetDescr(parentTbl),
                              20485                 :                :                                        false);
 2277 alvherre@alvh.no-ip.    20486         [ +  + ]:            168 :         if (!CompareIndexInfo(childInfo, parentInfo,
 2277 alvherre@alvh.no-ip.    20487                 :GIC         168 :                               partIdx->rd_indcollation,
                              20488                 :            168 :                               parentIdx->rd_indcollation,
                              20489                 :            168 :                               partIdx->rd_opfamily,
                              20490                 :            168 :                               parentIdx->rd_opfamily,
                              20491                 :                :                               attmap))
 2277 alvherre@alvh.no-ip.    20492         [ +  - ]:CBC          21 :             ereport(ERROR,
                              20493                 :                :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              20494                 :                :                      errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              20495                 :                :                             RelationGetRelationName(partIdx),
                              20496                 :                :                             RelationGetRelationName(parentIdx)),
                              20497                 :                :                      errdetail("The index definitions do not match.")));
                              20498                 :                : 
                              20499                 :                :         /*
                              20500                 :                :          * If there is a constraint in the parent, make sure there is one in
                              20501                 :                :          * the child too.
                              20502                 :                :          */
 2246                         20503                 :            147 :         constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
                              20504                 :                :                                                         RelationGetRelid(parentIdx));
                              20505                 :                : 
                              20506         [ +  + ]:            147 :         if (OidIsValid(constraintOid))
                              20507                 :                :         {
                              20508                 :             58 :             cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
                              20509                 :                :                                                           partIdxId);
                              20510         [ +  + ]:             58 :             if (!OidIsValid(cldConstrId))
                              20511         [ +  - ]:              3 :                 ereport(ERROR,
                              20512                 :                :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                              20513                 :                :                          errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              20514                 :                :                                 RelationGetRelationName(partIdx),
                              20515                 :                :                                 RelationGetRelationName(parentIdx)),
                              20516                 :                :                          errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
                              20517                 :                :                                    RelationGetRelationName(parentIdx),
                              20518                 :                :                                    RelationGetRelationName(parentTbl),
                              20519                 :                :                                    RelationGetRelationName(partIdx))));
                              20520                 :                :         }
                              20521                 :                : 
                              20522                 :                :         /*
                              20523                 :                :          * If it's a primary key, make sure the columns in the partition are
                              20524                 :                :          * NOT NULL.
                              20525                 :                :          */
  233 alvherre@alvh.no-ip.    20526         [ +  + ]:GNC         144 :         if (parentIdx->rd_index->indisprimary)
                              20527                 :             49 :             verifyPartitionIndexNotNull(childInfo, partTbl);
                              20528                 :                : 
                              20529                 :                :         /* All good -- do it */
 2277 alvherre@alvh.no-ip.    20530                 :CBC         141 :         IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
 2246                         20531         [ +  + ]:            141 :         if (OidIsValid(constraintOid))
 1889 tgl@sss.pgh.pa.us       20532                 :             52 :             ConstraintSetParentConstraint(cldConstrId, constraintOid,
                              20533                 :                :                                           RelationGetRelid(partTbl));
                              20534                 :                : 
 1579 michael@paquier.xyz     20535                 :            141 :         free_attrmap(attmap);
                              20536                 :                : 
 2277 alvherre@alvh.no-ip.    20537                 :            141 :         validatePartitionedIndex(parentIdx, parentTbl);
                              20538                 :                :     }
                              20539                 :                : 
                              20540                 :            147 :     relation_close(parentTbl, AccessShareLock);
                              20541                 :                :     /* keep these locks till commit */
                              20542                 :            147 :     relation_close(partTbl, NoLock);
                              20543                 :            147 :     relation_close(partIdx, NoLock);
                              20544                 :                : 
                              20545                 :            147 :     return address;
                              20546                 :                : }
                              20547                 :                : 
                              20548                 :                : /*
                              20549                 :                :  * Verify whether the given partition already contains an index attached
                              20550                 :                :  * to the given partitioned index.  If so, raise an error.
                              20551                 :                :  */
                              20552                 :                : static void
                              20553                 :            174 : refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
                              20554                 :                : {
                              20555                 :                :     Oid         existingIdx;
                              20556                 :                : 
 1852                         20557                 :            174 :     existingIdx = index_get_partition(partitionTbl,
                              20558                 :                :                                       RelationGetRelid(parentIdx));
                              20559         [ +  + ]:            174 :     if (OidIsValid(existingIdx))
                              20560         [ +  - ]:              3 :         ereport(ERROR,
                              20561                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                              20562                 :                :                  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
                              20563                 :                :                         RelationGetRelationName(partIdx),
                              20564                 :                :                         RelationGetRelationName(parentIdx)),
                              20565                 :                :                  errdetail("Another index is already attached for partition \"%s\".",
                              20566                 :                :                            RelationGetRelationName(partitionTbl))));
 2277                         20567                 :            171 : }
                              20568                 :                : 
                              20569                 :                : /*
                              20570                 :                :  * Verify whether the set of attached partition indexes to a parent index on
                              20571                 :                :  * a partitioned table is complete.  If it is, mark the parent index valid.
                              20572                 :                :  *
                              20573                 :                :  * This should be called each time a partition index is attached.
                              20574                 :                :  */
                              20575                 :                : static void
                              20576                 :            162 : validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
                              20577                 :                : {
                              20578                 :                :     Relation    inheritsRel;
                              20579                 :                :     SysScanDesc scan;
                              20580                 :                :     ScanKeyData key;
 2180 tgl@sss.pgh.pa.us       20581                 :            162 :     int         tuples = 0;
                              20582                 :                :     HeapTuple   inhTup;
                              20583                 :            162 :     bool        updated = false;
                              20584                 :                : 
 2277 alvherre@alvh.no-ip.    20585         [ -  + ]:            162 :     Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
                              20586                 :                : 
                              20587                 :                :     /*
                              20588                 :                :      * Scan pg_inherits for this parent index.  Count each valid index we find
                              20589                 :                :      * (verifying the pg_index entry for each), and if we reach the total
                              20590                 :                :      * amount we expect, we can mark this parent index as valid.
                              20591                 :                :      */
 1910 andres@anarazel.de      20592                 :            162 :     inheritsRel = table_open(InheritsRelationId, AccessShareLock);
 2277 alvherre@alvh.no-ip.    20593                 :            162 :     ScanKeyInit(&key, Anum_pg_inherits_inhparent,
                              20594                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                              20595                 :                :                 ObjectIdGetDatum(RelationGetRelid(partedIdx)));
                              20596                 :            162 :     scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
                              20597                 :                :                               NULL, 1, &key);
                              20598         [ +  + ]:            420 :     while ((inhTup = systable_getnext(scan)) != NULL)
                              20599                 :                :     {
                              20600                 :            258 :         Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
                              20601                 :                :         HeapTuple   indTup;
                              20602                 :                :         Form_pg_index indexForm;
                              20603                 :                : 
                              20604                 :            258 :         indTup = SearchSysCache1(INDEXRELID,
                              20605                 :                :                                  ObjectIdGetDatum(inhForm->inhrelid));
 1806 tgl@sss.pgh.pa.us       20606         [ -  + ]:            258 :         if (!HeapTupleIsValid(indTup))
 1806 tgl@sss.pgh.pa.us       20607         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
 2277 alvherre@alvh.no-ip.    20608                 :CBC         258 :         indexForm = (Form_pg_index) GETSTRUCT(indTup);
 1935 peter_e@gmx.net         20609         [ +  + ]:            258 :         if (indexForm->indisvalid)
 2277 alvherre@alvh.no-ip.    20610                 :            229 :             tuples += 1;
                              20611                 :            258 :         ReleaseSysCache(indTup);
                              20612                 :                :     }
                              20613                 :                : 
                              20614                 :                :     /* Done with pg_inherits */
                              20615                 :            162 :     systable_endscan(scan);
 1910 andres@anarazel.de      20616                 :            162 :     table_close(inheritsRel, AccessShareLock);
                              20617                 :                : 
                              20618                 :                :     /*
                              20619                 :                :      * If we found as many inherited indexes as the partitioned table has
                              20620                 :                :      * partitions, we're good; update pg_index to set indisvalid.
                              20621                 :                :      */
 1088 alvherre@alvh.no-ip.    20622         [ +  + ]:            162 :     if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts)
                              20623                 :                :     {
                              20624                 :                :         Relation    idxRel;
                              20625                 :                :         HeapTuple   indTup;
                              20626                 :                :         Form_pg_index indexForm;
                              20627                 :                : 
 1910 andres@anarazel.de      20628                 :             81 :         idxRel = table_open(IndexRelationId, RowExclusiveLock);
  275 michael@paquier.xyz     20629                 :             81 :         indTup = SearchSysCacheCopy1(INDEXRELID,
                              20630                 :                :                                      ObjectIdGetDatum(RelationGetRelid(partedIdx)));
                              20631         [ -  + ]:             81 :         if (!HeapTupleIsValid(indTup))
  275 michael@paquier.xyz     20632         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for index %u",
                              20633                 :                :                  RelationGetRelid(partedIdx));
  275 michael@paquier.xyz     20634                 :CBC          81 :         indexForm = (Form_pg_index) GETSTRUCT(indTup);
                              20635                 :                : 
                              20636                 :             81 :         indexForm->indisvalid = true;
 2277 alvherre@alvh.no-ip.    20637                 :             81 :         updated = true;
                              20638                 :                : 
  275 michael@paquier.xyz     20639                 :             81 :         CatalogTupleUpdate(idxRel, &indTup->t_self, indTup);
                              20640                 :                : 
 1910 andres@anarazel.de      20641                 :             81 :         table_close(idxRel, RowExclusiveLock);
  275 michael@paquier.xyz     20642                 :             81 :         heap_freetuple(indTup);
                              20643                 :                :     }
                              20644                 :                : 
                              20645                 :                :     /*
                              20646                 :                :      * If this index is in turn a partition of a larger index, validating it
                              20647                 :                :      * might cause the parent to become valid also.  Try that.
                              20648                 :                :      */
 2195 alvherre@alvh.no-ip.    20649   [ +  +  +  + ]:            162 :     if (updated && partedIdx->rd_rel->relispartition)
                              20650                 :                :     {
                              20651                 :                :         Oid         parentIdxId,
                              20652                 :                :                     parentTblId;
                              20653                 :                :         Relation    parentIdx,
                              20654                 :                :                     parentTbl;
                              20655                 :                : 
                              20656                 :                :         /* make sure we see the validation we just did */
 2277                         20657                 :             21 :         CommandCounterIncrement();
                              20658                 :                : 
 1116                         20659                 :             21 :         parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false);
                              20660                 :             21 :         parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false);
 2277                         20661                 :             21 :         parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
                              20662                 :             21 :         parentTbl = relation_open(parentTblId, AccessExclusiveLock);
                              20663         [ -  + ]:             21 :         Assert(!parentIdx->rd_index->indisvalid);
                              20664                 :                : 
                              20665                 :             21 :         validatePartitionedIndex(parentIdx, parentTbl);
                              20666                 :                : 
                              20667                 :             21 :         relation_close(parentIdx, AccessExclusiveLock);
                              20668                 :             21 :         relation_close(parentTbl, AccessExclusiveLock);
                              20669                 :                :     }
                              20670                 :            162 : }
                              20671                 :                : 
                              20672                 :                : /*
                              20673                 :                :  * When attaching an index as a partition of a partitioned index which is a
                              20674                 :                :  * primary key, verify that all the columns in the partition are marked NOT
                              20675                 :                :  * NULL.
                              20676                 :                :  */
                              20677                 :                : static void
  233 alvherre@alvh.no-ip.    20678                 :GNC          49 : verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partition)
                              20679                 :                : {
                              20680         [ +  + ]:             96 :     for (int i = 0; i < iinfo->ii_NumIndexKeyAttrs; i++)
                              20681                 :                :     {
                              20682                 :             50 :         Form_pg_attribute att = TupleDescAttr(RelationGetDescr(partition),
                              20683                 :                :                                               iinfo->ii_IndexAttrNumbers[i] - 1);
                              20684                 :                : 
                              20685         [ +  + ]:             50 :         if (!att->attnotnull)
                              20686         [ +  - ]:              3 :             ereport(ERROR,
                              20687                 :                :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                              20688                 :                :                     errmsg("invalid primary key definition"),
                              20689                 :                :                     errdetail("Column \"%s\" of relation \"%s\" is not marked NOT NULL.",
                              20690                 :                :                               NameStr(att->attname),
                              20691                 :                :                               RelationGetRelationName(partition)));
                              20692                 :                :     }
                              20693                 :             46 : }
                              20694                 :                : 
                              20695                 :                : /*
                              20696                 :                :  * Return an OID list of constraints that reference the given relation
                              20697                 :                :  * that are marked as having a parent constraints.
                              20698                 :                :  */
                              20699                 :                : static List *
 1838 alvherre@alvh.no-ip.    20700                 :CBC         581 : GetParentedForeignKeyRefs(Relation partition)
                              20701                 :                : {
                              20702                 :                :     Relation    pg_constraint;
                              20703                 :                :     HeapTuple   tuple;
                              20704                 :                :     SysScanDesc scan;
                              20705                 :                :     ScanKeyData key[2];
                              20706                 :            581 :     List       *constraints = NIL;
                              20707                 :                : 
                              20708                 :                :     /*
                              20709                 :                :      * If no indexes, or no columns are referenceable by FKs, we can avoid the
                              20710                 :                :      * scan.
                              20711                 :                :      */
                              20712   [ +  +  +  + ]:            822 :     if (RelationGetIndexList(partition) == NIL ||
                              20713                 :            241 :         bms_is_empty(RelationGetIndexAttrBitmap(partition,
                              20714                 :                :                                                 INDEX_ATTR_BITMAP_KEY)))
                              20715                 :            463 :         return NIL;
                              20716                 :                : 
                              20717                 :                :     /* Search for constraints referencing this table */
                              20718                 :            118 :     pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
                              20719                 :            118 :     ScanKeyInit(&key[0],
                              20720                 :                :                 Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
                              20721                 :                :                 F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition)));
                              20722                 :            118 :     ScanKeyInit(&key[1],
                              20723                 :                :                 Anum_pg_constraint_contype, BTEqualStrategyNumber,
                              20724                 :                :                 F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
                              20725                 :                : 
                              20726                 :                :     /* XXX This is a seqscan, as we don't have a usable index */
                              20727                 :            118 :     scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key);
                              20728         [ +  + ]:            183 :     while ((tuple = systable_getnext(scan)) != NULL)
                              20729                 :                :     {
                              20730                 :             65 :         Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              20731                 :                : 
                              20732                 :                :         /*
                              20733                 :                :          * We only need to process constraints that are part of larger ones.
                              20734                 :                :          */
                              20735         [ -  + ]:             65 :         if (!OidIsValid(constrForm->conparentid))
 1838 alvherre@alvh.no-ip.    20736                 :UBC           0 :             continue;
                              20737                 :                : 
 1838 alvherre@alvh.no-ip.    20738                 :CBC          65 :         constraints = lappend_oid(constraints, constrForm->oid);
                              20739                 :                :     }
                              20740                 :                : 
                              20741                 :            118 :     systable_endscan(scan);
                              20742                 :            118 :     table_close(pg_constraint, AccessShareLock);
                              20743                 :                : 
                              20744                 :            118 :     return constraints;
                              20745                 :                : }
                              20746                 :                : 
                              20747                 :                : /*
                              20748                 :                :  * During DETACH PARTITION, verify that any foreign keys pointing to the
                              20749                 :                :  * partitioned table would not become invalid.  An error is raised if any
                              20750                 :                :  * referenced values exist.
                              20751                 :                :  */
                              20752                 :                : static void
                              20753                 :            236 : ATDetachCheckNoForeignKeyRefs(Relation partition)
                              20754                 :                : {
                              20755                 :                :     List       *constraints;
                              20756                 :                :     ListCell   *cell;
                              20757                 :                : 
                              20758                 :            236 :     constraints = GetParentedForeignKeyRefs(partition);
                              20759                 :                : 
                              20760   [ +  +  +  +  :            262 :     foreach(cell, constraints)
                                              +  + ]
                              20761                 :                :     {
                              20762                 :             43 :         Oid         constrOid = lfirst_oid(cell);
                              20763                 :                :         HeapTuple   tuple;
                              20764                 :                :         Form_pg_constraint constrForm;
                              20765                 :                :         Relation    rel;
  638 peter@eisentraut.org    20766                 :             43 :         Trigger     trig = {0};
                              20767                 :                : 
 1838 alvherre@alvh.no-ip.    20768                 :             43 :         tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
                              20769         [ -  + ]:             43 :         if (!HeapTupleIsValid(tuple))
 1838 alvherre@alvh.no-ip.    20770         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for constraint %u", constrOid);
 1838 alvherre@alvh.no-ip.    20771                 :CBC          43 :         constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
                              20772                 :                : 
                              20773         [ -  + ]:             43 :         Assert(OidIsValid(constrForm->conparentid));
                              20774         [ -  + ]:             43 :         Assert(constrForm->confrelid == RelationGetRelid(partition));
                              20775                 :                : 
                              20776                 :                :         /* prevent data changes into the referencing table until commit */
                              20777                 :             43 :         rel = table_open(constrForm->conrelid, ShareLock);
                              20778                 :                : 
                              20779                 :             43 :         trig.tgoid = InvalidOid;
                              20780                 :             43 :         trig.tgname = NameStr(constrForm->conname);
                              20781                 :             43 :         trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
                              20782                 :             43 :         trig.tgisinternal = true;
                              20783                 :             43 :         trig.tgconstrrelid = RelationGetRelid(partition);
                              20784                 :             43 :         trig.tgconstrindid = constrForm->conindid;
                              20785                 :             43 :         trig.tgconstraint = constrForm->oid;
                              20786                 :             43 :         trig.tgdeferrable = false;
                              20787                 :             43 :         trig.tginitdeferred = false;
                              20788                 :                :         /* we needn't fill in remaining fields */
                              20789                 :                : 
                              20790                 :             43 :         RI_PartitionRemove_Check(&trig, rel, partition);
                              20791                 :                : 
                              20792                 :             26 :         ReleaseSysCache(tuple);
                              20793                 :                : 
                              20794                 :             26 :         table_close(rel, NoLock);
                              20795                 :                :     }
                              20796                 :            219 : }
                              20797                 :                : 
                              20798                 :                : /*
                              20799                 :                :  * resolve column compression specification to compression method.
                              20800                 :                :  */
                              20801                 :                : static char
  229 peter@eisentraut.org    20802                 :GNC      107084 : GetAttributeCompression(Oid atttypid, const char *compression)
                              20803                 :                : {
                              20804                 :                :     char        cmethod;
                              20805                 :                : 
 1053 tgl@sss.pgh.pa.us       20806   [ +  +  +  + ]:CBC      107084 :     if (compression == NULL || strcmp(compression, "default") == 0)
                              20807                 :         107013 :         return InvalidCompressionMethod;
                              20808                 :                : 
                              20809                 :                :     /*
                              20810                 :                :      * To specify a nondefault method, the column data type must be toastable.
                              20811                 :                :      * Note this says nothing about whether the column's attstorage setting
                              20812                 :                :      * permits compression; we intentionally allow attstorage and
                              20813                 :                :      * attcompression to be independent.  But with a non-toastable type,
                              20814                 :                :      * attstorage could not be set to a value that would permit compression.
                              20815                 :                :      *
                              20816                 :                :      * We don't actually need to enforce this, since nothing bad would happen
                              20817                 :                :      * if attcompression were non-default; it would never be consulted.  But
                              20818                 :                :      * it seems more user-friendly to complain about a certainly-useless
                              20819                 :                :      * attempt to set the property.
                              20820                 :                :      */
                              20821         [ +  + ]:             71 :     if (!TypeIsToastable(atttypid))
 1122 rhaas@postgresql.org    20822         [ +  - ]:              3 :         ereport(ERROR,
                              20823                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              20824                 :                :                  errmsg("column data type %s does not support compression",
                              20825                 :                :                         format_type_be(atttypid))));
                              20826                 :                : 
 1119                         20827                 :             68 :     cmethod = CompressionNameToMethod(compression);
                              20828         [ +  + ]:             68 :     if (!CompressionMethodIsValid(cmethod))
                              20829         [ +  - ]:              6 :         ereport(ERROR,
                              20830                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                              20831                 :                :                  errmsg("invalid compression method \"%s\"", compression)));
                              20832                 :                : 
 1122                         20833                 :             62 :     return cmethod;
                              20834                 :                : }
                              20835                 :                : 
                              20836                 :                : /*
                              20837                 :                :  * resolve column storage specification
                              20838                 :                :  */
                              20839                 :                : static char
  641 peter@eisentraut.org    20840                 :            121 : GetAttributeStorage(Oid atttypid, const char *storagemode)
                              20841                 :                : {
                              20842                 :            121 :     char        cstorage = 0;
                              20843                 :                : 
                              20844         [ +  + ]:            121 :     if (pg_strcasecmp(storagemode, "plain") == 0)
                              20845                 :             25 :         cstorage = TYPSTORAGE_PLAIN;
                              20846         [ +  + ]:             96 :     else if (pg_strcasecmp(storagemode, "external") == 0)
                              20847                 :             78 :         cstorage = TYPSTORAGE_EXTERNAL;
                              20848         [ +  + ]:             18 :     else if (pg_strcasecmp(storagemode, "extended") == 0)
                              20849                 :              8 :         cstorage = TYPSTORAGE_EXTENDED;
                              20850         [ +  + ]:             10 :     else if (pg_strcasecmp(storagemode, "main") == 0)
                              20851                 :              7 :         cstorage = TYPSTORAGE_MAIN;
  521 tgl@sss.pgh.pa.us       20852         [ +  - ]:              3 :     else if (pg_strcasecmp(storagemode, "default") == 0)
                              20853                 :              3 :         cstorage = get_typstorage(atttypid);
                              20854                 :                :     else
  641 peter@eisentraut.org    20855         [ #  # ]:UBC           0 :         ereport(ERROR,
                              20856                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                              20857                 :                :                  errmsg("invalid storage type \"%s\"",
                              20858                 :                :                         storagemode)));
                              20859                 :                : 
                              20860                 :                :     /*
                              20861                 :                :      * safety check: do not allow toasted storage modes unless column datatype
                              20862                 :                :      * is TOAST-aware.
                              20863                 :                :      */
  641 peter@eisentraut.org    20864   [ +  +  +  + ]:CBC         121 :     if (!(cstorage == TYPSTORAGE_PLAIN || TypeIsToastable(atttypid)))
                              20865         [ +  - ]:              3 :         ereport(ERROR,
                              20866                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                              20867                 :                :                  errmsg("column data type %s can only have storage PLAIN",
                              20868                 :                :                         format_type_be(atttypid))));
                              20869                 :                : 
                              20870                 :            118 :     return cstorage;
                              20871                 :                : }
                              20872                 :                : 
                              20873                 :                : /*
                              20874                 :                :  * Struct with context of new partition for insert rows from splited partition
                              20875                 :                :  */
                              20876                 :                : typedef struct SplitPartitionContext
                              20877                 :                : {
                              20878                 :                :     ExprState  *partqualstate;  /* expression for checking slot for partition
                              20879                 :                :                                  * (NULL for DEFAULT partition) */
                              20880                 :                :     BulkInsertState bistate;    /* state of bulk inserts for partition */
                              20881                 :                :     TupleTableSlot *dstslot;    /* slot for inserting row into partition */
                              20882                 :                :     Relation    partRel;        /* relation for partition */
                              20883                 :                : } SplitPartitionContext;
                              20884                 :                : 
                              20885                 :                : 
                              20886                 :                : /*
                              20887                 :                :  * createSplitPartitionContext: create context for partition and fill it
                              20888                 :                :  */
                              20889                 :                : static SplitPartitionContext *
    7 akorotkov@postgresql    20890                 :GNC         201 : createSplitPartitionContext(Relation partRel)
                              20891                 :                : {
                              20892                 :                :     SplitPartitionContext *pc;
                              20893                 :                : 
                              20894                 :            201 :     pc = (SplitPartitionContext *) palloc0(sizeof(SplitPartitionContext));
                              20895                 :            201 :     pc->partRel = partRel;
                              20896                 :                : 
                              20897                 :                :     /*
                              20898                 :                :      * Prepare a BulkInsertState for table_tuple_insert. The FSM is empty, so
                              20899                 :                :      * don't bother using it.
                              20900                 :                :      */
                              20901                 :            201 :     pc->bistate = GetBulkInsertState();
                              20902                 :                : 
                              20903                 :                :     /* Create tuple slot for new partition. */
                              20904                 :            201 :     pc->dstslot = MakeSingleTupleTableSlot(RelationGetDescr(pc->partRel),
                              20905                 :                :                                            table_slot_callbacks(pc->partRel));
                              20906                 :            201 :     ExecStoreAllNullTuple(pc->dstslot);
                              20907                 :                : 
                              20908                 :            201 :     return pc;
                              20909                 :                : }
                              20910                 :                : 
                              20911                 :                : /*
                              20912                 :                :  * deleteSplitPartitionContext: delete context for partition
                              20913                 :                :  */
                              20914                 :                : static void
                              20915                 :            201 : deleteSplitPartitionContext(SplitPartitionContext *pc, int ti_options)
                              20916                 :                : {
                              20917                 :            201 :     ExecDropSingleTupleTableSlot(pc->dstslot);
                              20918                 :            201 :     FreeBulkInsertState(pc->bistate);
                              20919                 :                : 
                              20920                 :            201 :     table_finish_bulk_insert(pc->partRel, ti_options);
                              20921                 :                : 
                              20922                 :            201 :     pfree(pc);
                              20923                 :            201 : }
                              20924                 :                : 
                              20925                 :                : /*
                              20926                 :                :  * moveSplitTableRows: scan split partition (splitRel) of partitioned table
                              20927                 :                :  * (rel) and move rows into new partitions.
                              20928                 :                :  *
                              20929                 :                :  * New partitions description:
                              20930                 :                :  * partlist: list of pointers to SinglePartitionSpec structures.
                              20931                 :                :  * newPartRels: list of Relation's.
                              20932                 :                :  * defaultPartOid: oid of DEFAULT partition, for table rel.
                              20933                 :                :  */
                              20934                 :                : static void
                              20935                 :             57 : moveSplitTableRows(Relation rel, Relation splitRel, List *partlist, List *newPartRels, Oid defaultPartOid)
                              20936                 :                : {
                              20937                 :                :     /* The FSM is empty, so don't bother using it. */
                              20938                 :             57 :     int         ti_options = TABLE_INSERT_SKIP_FSM;
                              20939                 :                :     CommandId   mycid;
                              20940                 :                :     EState     *estate;
                              20941                 :                :     ListCell   *listptr,
                              20942                 :                :                *listptr2;
                              20943                 :                :     TupleTableSlot *srcslot;
                              20944                 :                :     ExprContext *econtext;
                              20945                 :                :     TableScanDesc scan;
                              20946                 :                :     Snapshot    snapshot;
                              20947                 :                :     MemoryContext oldCxt;
                              20948                 :             57 :     List       *partContexts = NIL;
                              20949                 :                :     TupleConversionMap *tuple_map;
                              20950                 :             57 :     SplitPartitionContext *defaultPartCtx = NULL,
                              20951                 :                :                *pc;
                              20952                 :             57 :     bool        isOldDefaultPart = false;
                              20953                 :                : 
                              20954                 :             57 :     mycid = GetCurrentCommandId(true);
                              20955                 :                : 
                              20956                 :             57 :     estate = CreateExecutorState();
                              20957                 :                : 
                              20958   [ +  -  +  +  :            234 :     forboth(listptr, partlist, listptr2, newPartRels)
                                     +  -  +  +  +  
                                        +  +  -  +  
                                                 + ]
                              20959                 :                :     {
                              20960                 :            177 :         SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
                              20961                 :                : 
                              20962                 :            177 :         pc = createSplitPartitionContext((Relation) lfirst(listptr2));
                              20963                 :                : 
                              20964         [ +  + ]:            177 :         if (sps->bound->is_default)
                              20965                 :                :         {
                              20966                 :                :             /* We should not create constraint for detached DEFAULT partition. */
                              20967                 :             15 :             defaultPartCtx = pc;
                              20968                 :                :         }
                              20969                 :                :         else
                              20970                 :                :         {
                              20971                 :                :             List       *partConstraint;
                              20972                 :                : 
                              20973                 :                :             /* Build expression execution states for partition check quals. */
                              20974                 :            162 :             partConstraint = get_qual_from_partbound(rel, sps->bound);
                              20975                 :                :             partConstraint =
                              20976                 :            162 :                 (List *) eval_const_expressions(NULL,
                              20977                 :                :                                                 (Node *) partConstraint);
                              20978                 :                :             /* Make boolean expression for ExecCheck(). */
                              20979                 :            162 :             partConstraint = list_make1(make_ands_explicit(partConstraint));
                              20980                 :                : 
                              20981                 :                :             /*
                              20982                 :                :              * Map the vars in the constraint expression from rel's attnos to
                              20983                 :                :              * splitRel's.
                              20984                 :                :              */
                              20985                 :            162 :             partConstraint = map_partition_varattnos(partConstraint,
                              20986                 :                :                                                      1, splitRel, rel);
                              20987                 :                : 
                              20988                 :            162 :             pc->partqualstate =
                              20989                 :            162 :                 ExecPrepareExpr((Expr *) linitial(partConstraint), estate);
                              20990         [ -  + ]:            162 :             Assert(pc->partqualstate != NULL);
                              20991                 :                :         }
                              20992                 :                : 
                              20993                 :                :         /* Store partition context into list. */
                              20994                 :            177 :         partContexts = lappend(partContexts, pc);
                              20995                 :                :     }
                              20996                 :                : 
                              20997                 :                :     /*
                              20998                 :                :      * Create partition context for DEFAULT partition. We can insert values
                              20999                 :                :      * into this partition in case spaces with values between new partitions.
                              21000                 :                :      */
                              21001   [ +  +  +  + ]:             57 :     if (!defaultPartCtx && OidIsValid(defaultPartOid))
                              21002                 :                :     {
                              21003                 :                :         /* Indicate that we allocate context for old DEFAULT partition */
                              21004                 :             24 :         isOldDefaultPart = true;
                              21005                 :             24 :         defaultPartCtx = createSplitPartitionContext(table_open(defaultPartOid, AccessExclusiveLock));
                              21006                 :                :     }
                              21007                 :                : 
                              21008         [ -  + ]:             57 :     econtext = GetPerTupleExprContext(estate);
                              21009                 :                : 
                              21010                 :                :     /* Create necessary tuple slot. */
                              21011                 :             57 :     srcslot = MakeSingleTupleTableSlot(RelationGetDescr(splitRel),
                              21012                 :                :                                        table_slot_callbacks(splitRel));
                              21013                 :                : 
                              21014                 :                :     /*
                              21015                 :                :      * Map computing for moving attributes of split partition to new partition
                              21016                 :                :      * (for first new partition but other new partitions can use the same
                              21017                 :                :      * map).
                              21018                 :                :      */
                              21019                 :             57 :     pc = (SplitPartitionContext *) lfirst(list_head(partContexts));
                              21020                 :             57 :     tuple_map = convert_tuples_by_name(RelationGetDescr(splitRel),
                              21021                 :             57 :                                        RelationGetDescr(pc->partRel));
                              21022                 :                : 
                              21023                 :                :     /* Scan through the rows. */
                              21024                 :             57 :     snapshot = RegisterSnapshot(GetLatestSnapshot());
                              21025                 :             57 :     scan = table_beginscan(splitRel, snapshot, 0, NULL);
                              21026                 :                : 
                              21027                 :                :     /*
                              21028                 :                :      * Switch to per-tuple memory context and reset it for each tuple
                              21029                 :                :      * produced, so we don't leak memory.
                              21030                 :                :      */
                              21031         [ +  - ]:             57 :     oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
                              21032                 :                : 
                              21033         [ +  + ]:            327 :     while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot))
                              21034                 :                :     {
                              21035                 :            270 :         bool        found = false;
                              21036                 :                :         TupleTableSlot *insertslot;
                              21037                 :                : 
                              21038                 :                :         /* Extract data from old tuple. */
                              21039                 :            270 :         slot_getallattrs(srcslot);
                              21040                 :                : 
                              21041                 :            270 :         econtext->ecxt_scantuple = srcslot;
                              21042                 :                : 
                              21043                 :                :         /* Search partition for current slot srcslot. */
                              21044   [ +  -  +  +  :            744 :         foreach(listptr, partContexts)
                                              +  + ]
                              21045                 :                :         {
                              21046                 :            687 :             pc = (SplitPartitionContext *) lfirst(listptr);
                              21047                 :                : 
                              21048   [ +  +  +  + ]:           1320 :             if (pc->partqualstate /* skip DEFAULT partition */ &&
                              21049                 :            633 :                 ExecCheck(pc->partqualstate, econtext))
                              21050                 :                :             {
                              21051                 :            213 :                 found = true;
                              21052                 :            213 :                 break;
                              21053                 :                :             }
                              21054                 :            474 :             ResetExprContext(econtext);
                              21055                 :                :         }
                              21056         [ +  + ]:            270 :         if (!found)
                              21057                 :                :         {
                              21058                 :                :             /* Use DEFAULT partition if it exists. */
                              21059         [ +  - ]:             57 :             if (defaultPartCtx)
                              21060                 :             57 :                 pc = defaultPartCtx;
                              21061                 :                :             else
    7 akorotkov@postgresql    21062         [ #  # ]:UNC           0 :                 ereport(ERROR,
                              21063                 :                :                         (errcode(ERRCODE_CHECK_VIOLATION),
                              21064                 :                :                          errmsg("can not find partition for split partition row"),
                              21065                 :                :                          errtable(splitRel)));
                              21066                 :                :         }
                              21067                 :                : 
    7 akorotkov@postgresql    21068         [ +  + ]:GNC         270 :         if (tuple_map)
                              21069                 :                :         {
                              21070                 :                :             /* Need to use map for copy attributes. */
                              21071                 :             12 :             insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, pc->dstslot);
                              21072                 :                :         }
                              21073                 :                :         else
                              21074                 :                :         {
                              21075                 :                :             /* Copy attributes directly. */
                              21076                 :            258 :             insertslot = pc->dstslot;
                              21077                 :                : 
                              21078                 :            258 :             ExecClearTuple(insertslot);
                              21079                 :                : 
                              21080                 :            258 :             memcpy(insertslot->tts_values, srcslot->tts_values,
                              21081                 :            258 :                    sizeof(Datum) * srcslot->tts_nvalid);
                              21082                 :            258 :             memcpy(insertslot->tts_isnull, srcslot->tts_isnull,
                              21083                 :            258 :                    sizeof(bool) * srcslot->tts_nvalid);
                              21084                 :                : 
                              21085                 :            258 :             ExecStoreVirtualTuple(insertslot);
                              21086                 :                :         }
                              21087                 :                : 
                              21088                 :                :         /* Write the tuple out to the new relation. */
    3                         21089                 :            270 :         table_tuple_insert(pc->partRel, insertslot, mycid,
                              21090                 :                :                            ti_options, pc->bistate);
                              21091                 :                : 
    7                         21092                 :            270 :         ResetExprContext(econtext);
                              21093                 :                : 
                              21094         [ -  + ]:            270 :         CHECK_FOR_INTERRUPTS();
                              21095                 :                :     }
                              21096                 :                : 
                              21097                 :             57 :     MemoryContextSwitchTo(oldCxt);
                              21098                 :                : 
                              21099                 :             57 :     table_endscan(scan);
                              21100                 :             57 :     UnregisterSnapshot(snapshot);
                              21101                 :                : 
                              21102         [ +  + ]:             57 :     if (tuple_map)
                              21103                 :              3 :         free_conversion_map(tuple_map);
                              21104                 :                : 
                              21105                 :             57 :     ExecDropSingleTupleTableSlot(srcslot);
                              21106                 :                : 
                              21107                 :             57 :     FreeExecutorState(estate);
                              21108                 :                : 
                              21109   [ +  -  +  +  :            234 :     foreach(listptr, partContexts)
                                              +  + ]
                              21110                 :            177 :         deleteSplitPartitionContext((SplitPartitionContext *) lfirst(listptr), ti_options);
                              21111                 :                : 
                              21112                 :                :     /* Need to close table and free buffers for DEFAULT partition. */
                              21113         [ +  + ]:             57 :     if (isOldDefaultPart)
                              21114                 :                :     {
                              21115                 :             24 :         Relation    defaultPartRel = defaultPartCtx->partRel;
                              21116                 :                : 
                              21117                 :             24 :         deleteSplitPartitionContext(defaultPartCtx, ti_options);
                              21118                 :                :         /* Keep the lock until commit. */
                              21119                 :             24 :         table_close(defaultPartRel, NoLock);
                              21120                 :                :     }
                              21121                 :             57 : }
                              21122                 :                : 
                              21123                 :                : /*
                              21124                 :                :  * createPartitionTable: create table for a new partition with given name
                              21125                 :                :  * (newPartName) like table (modelRelName)
                              21126                 :                :  *
                              21127                 :                :  * Emulates command: CREATE TABLE <newPartName> (LIKE <modelRelName>
                              21128                 :                :  * INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY)
                              21129                 :                :  */
                              21130                 :                : static void
                              21131                 :            210 : createPartitionTable(RangeVar *newPartName, RangeVar *modelRelName,
                              21132                 :                :                      AlterTableUtilityContext *context)
                              21133                 :                : {
                              21134                 :                :     CreateStmt *createStmt;
                              21135                 :                :     TableLikeClause *tlc;
                              21136                 :                :     PlannedStmt *wrapper;
                              21137                 :                : 
                              21138                 :            210 :     createStmt = makeNode(CreateStmt);
                              21139                 :            210 :     createStmt->relation = newPartName;
                              21140                 :            210 :     createStmt->tableElts = NIL;
                              21141                 :            210 :     createStmt->inhRelations = NIL;
                              21142                 :            210 :     createStmt->constraints = NIL;
                              21143                 :            210 :     createStmt->options = NIL;
                              21144                 :            210 :     createStmt->oncommit = ONCOMMIT_NOOP;
                              21145                 :            210 :     createStmt->tablespacename = NULL;
                              21146                 :            210 :     createStmt->if_not_exists = false;
                              21147                 :                : 
                              21148                 :            210 :     tlc = makeNode(TableLikeClause);
                              21149                 :            210 :     tlc->relation = modelRelName;
                              21150                 :                : 
                              21151                 :                :     /*
                              21152                 :                :      * Indexes will be inherited on "attach new partitions" stage, after data
                              21153                 :                :      * moving.
                              21154                 :                :      */
                              21155                 :            210 :     tlc->options = CREATE_TABLE_LIKE_ALL & ~(CREATE_TABLE_LIKE_INDEXES | CREATE_TABLE_LIKE_IDENTITY);
                              21156                 :            210 :     tlc->relationOid = InvalidOid;
                              21157                 :            210 :     createStmt->tableElts = lappend(createStmt->tableElts, tlc);
                              21158                 :                : 
                              21159                 :                :     /* Need to make a wrapper PlannedStmt. */
                              21160                 :            210 :     wrapper = makeNode(PlannedStmt);
                              21161                 :            210 :     wrapper->commandType = CMD_UTILITY;
                              21162                 :            210 :     wrapper->canSetTag = false;
                              21163                 :            210 :     wrapper->utilityStmt = (Node *) createStmt;
                              21164                 :            210 :     wrapper->stmt_location = context->pstmt->stmt_location;
                              21165                 :            210 :     wrapper->stmt_len = context->pstmt->stmt_len;
                              21166                 :                : 
                              21167                 :            210 :     ProcessUtility(wrapper,
                              21168                 :                :                    context->queryString,
                              21169                 :                :                    false,
                              21170                 :                :                    PROCESS_UTILITY_SUBCOMMAND,
                              21171                 :                :                    NULL,
                              21172                 :                :                    NULL,
                              21173                 :                :                    None_Receiver,
                              21174                 :                :                    NULL);
                              21175                 :            210 : }
                              21176                 :                : 
                              21177                 :                : /*
                              21178                 :                :  * ALTER TABLE <name> SPLIT PARTITION <partition-name> INTO <partition-list>
                              21179                 :                :  */
                              21180                 :                : static void
                              21181                 :             60 : ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab, Relation rel,
                              21182                 :                :                      PartitionCmd *cmd, AlterTableUtilityContext *context)
                              21183                 :                : {
                              21184                 :                :     Relation    splitRel;
                              21185                 :                :     Oid         splitRelOid;
                              21186                 :                :     char        relname[NAMEDATALEN];
                              21187                 :                :     Oid         namespaceId;
                              21188                 :                :     ListCell   *listptr,
                              21189                 :                :                *listptr2;
                              21190                 :             60 :     bool        isSameName = false;
                              21191                 :                :     char        tmpRelName[NAMEDATALEN];
                              21192                 :             60 :     List       *newPartRels = NIL;
                              21193                 :                :     ObjectAddress object;
                              21194                 :                :     RangeVar   *parentName;
                              21195                 :                :     Oid         defaultPartOid;
                              21196                 :                : 
                              21197                 :             60 :     defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
                              21198                 :                : 
                              21199                 :                :     /*
                              21200                 :                :      * We are going to detach and remove this partition: need to use exclusive
                              21201                 :                :      * lock for preventing DML-queries to the partition.
                              21202                 :                :      */
                              21203                 :             60 :     splitRel = table_openrv(cmd->name, AccessExclusiveLock);
                              21204                 :                : 
                              21205                 :             60 :     splitRelOid = RelationGetRelid(splitRel);
                              21206                 :                : 
                              21207                 :                :     /* Check descriptions of new partitions. */
                              21208   [ +  -  +  +  :            237 :     foreach(listptr, cmd->partlist)
                                              +  + ]
                              21209                 :                :     {
                              21210                 :                :         Oid         existing_relid;
                              21211                 :            180 :         SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
                              21212                 :                : 
                              21213                 :            180 :         strlcpy(relname, sps->name->relname, NAMEDATALEN);
                              21214                 :                : 
                              21215                 :                :         /*
                              21216                 :                :          * Look up the namespace in which we are supposed to create the
                              21217                 :                :          * partition, check we have permission to create there, lock it
                              21218                 :                :          * against concurrent drop, and mark stmt->relation as
                              21219                 :                :          * RELPERSISTENCE_TEMP if a temporary namespace is selected.
                              21220                 :                :          */
                              21221                 :                :         namespaceId =
                              21222                 :            180 :             RangeVarGetAndCheckCreationNamespace(sps->name, NoLock, NULL);
                              21223                 :                : 
                              21224                 :                :         /*
                              21225                 :                :          * This would fail later on anyway, if the relation already exists.
                              21226                 :                :          * But by catching it here we can emit a nicer error message.
                              21227                 :                :          */
                              21228                 :            180 :         existing_relid = get_relname_relid(relname, namespaceId);
                              21229   [ +  +  +  - ]:            180 :         if (existing_relid == splitRelOid && !isSameName)
                              21230                 :                :             /* One new partition can have the same name as split partition. */
                              21231                 :             12 :             isSameName = true;
                              21232         [ +  + ]:            168 :         else if (existing_relid != InvalidOid)
                              21233         [ +  - ]:              3 :             ereport(ERROR,
                              21234                 :                :                     (errcode(ERRCODE_DUPLICATE_TABLE),
                              21235                 :                :                      errmsg("relation \"%s\" already exists", relname)));
                              21236                 :                :     }
                              21237                 :                : 
                              21238                 :                :     /* Detach split partition. */
                              21239                 :             57 :     RemoveInheritance(splitRel, rel, false);
                              21240                 :                :     /* Do the final part of detaching. */
                              21241                 :             57 :     DetachPartitionFinalize(rel, splitRel, false, defaultPartOid);
                              21242                 :                : 
                              21243                 :                :     /*
                              21244                 :                :      * If new partition has the same name as split partition then we should
                              21245                 :                :      * rename split partition for reusing name.
                              21246                 :                :      */
                              21247         [ +  + ]:             57 :     if (isSameName)
                              21248                 :                :     {
                              21249                 :                :         /*
                              21250                 :                :          * We must bump the command counter to make the split partition tuple
                              21251                 :                :          * visible for renaming.
                              21252                 :                :          */
                              21253                 :             12 :         CommandCounterIncrement();
                              21254                 :                :         /* Rename partition. */
                              21255                 :             12 :         sprintf(tmpRelName, "split-%u-%X-tmp", RelationGetRelid(rel), MyProcPid);
                              21256                 :             12 :         RenameRelationInternal(splitRelOid, tmpRelName, false, false);
                              21257                 :                : 
                              21258                 :                :         /*
                              21259                 :                :          * We must bump the command counter to make the split partition tuple
                              21260                 :                :          * visible after renaming.
                              21261                 :                :          */
                              21262                 :             12 :         CommandCounterIncrement();
                              21263                 :                :     }
                              21264                 :                : 
                              21265                 :                :     /* Create new partitions (like split partition), without indexes. */
                              21266                 :             57 :     parentName = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
                              21267                 :             57 :                               RelationGetRelationName(rel), -1);
                              21268   [ +  -  +  +  :            234 :     foreach(listptr, cmd->partlist)
                                              +  + ]
                              21269                 :                :     {
                              21270                 :            177 :         SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
                              21271                 :                :         Relation    newPartRel;
                              21272                 :                : 
                              21273                 :            177 :         createPartitionTable(sps->name, parentName, context);
                              21274                 :                : 
                              21275                 :                :         /* Open the new partition and acquire exclusive lock on it. */
                              21276                 :            177 :         newPartRel = table_openrv(sps->name, AccessExclusiveLock);
                              21277                 :                : 
                              21278                 :            177 :         newPartRels = lappend(newPartRels, newPartRel);
                              21279                 :                :     }
                              21280                 :                : 
                              21281                 :                :     /* Copy data from split partition to new partitions. */
                              21282                 :             57 :     moveSplitTableRows(rel, splitRel, cmd->partlist, newPartRels, defaultPartOid);
                              21283                 :                :     /* Keep the lock until commit. */
                              21284                 :             57 :     table_close(splitRel, NoLock);
                              21285                 :                : 
                              21286                 :                :     /* Attach new partitions to partitioned table. */
                              21287   [ +  -  +  +  :            234 :     forboth(listptr, cmd->partlist, listptr2, newPartRels)
                                     +  -  +  +  +  
                                        +  +  -  +  
                                                 + ]
                              21288                 :                :     {
                              21289                 :            177 :         SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
                              21290                 :            177 :         Relation    newPartRel = (Relation) lfirst(listptr2);
                              21291                 :                : 
                              21292                 :                :         /* wqueue = NULL: verification for each cloned constraint is not need. */
                              21293                 :            177 :         attachPartitionTable(NULL, rel, newPartRel, sps->bound);
                              21294                 :                :         /* Keep the lock until commit. */
                              21295                 :            177 :         table_close(newPartRel, NoLock);
                              21296                 :                :     }
                              21297                 :                : 
                              21298                 :                :     /* Drop split partition. */
                              21299                 :             57 :     object.classId = RelationRelationId;
                              21300                 :             57 :     object.objectId = splitRelOid;
                              21301                 :             57 :     object.objectSubId = 0;
                              21302                 :                :     /* Probably DROP_CASCADE is not needed. */
                              21303                 :             57 :     performDeletion(&object, DROP_RESTRICT, 0);
                              21304                 :             57 : }
                              21305                 :                : 
                              21306                 :                : /*
                              21307                 :                :  * moveMergedTablesRows: scan partitions to be merged (mergingPartitionsList)
                              21308                 :                :  * of the partitioned table (rel) and move rows into the new partition
                              21309                 :                :  * (newPartRel).
                              21310                 :                :  */
                              21311                 :                : static void
                              21312                 :             33 : moveMergedTablesRows(Relation rel, List *mergingPartitionsList,
                              21313                 :                :                      Relation newPartRel)
                              21314                 :                : {
                              21315                 :                :     CommandId   mycid;
                              21316                 :                : 
                              21317                 :                :     /* The FSM is empty, so don't bother using it. */
                              21318                 :             33 :     int         ti_options = TABLE_INSERT_SKIP_FSM;
                              21319                 :                :     ListCell   *listptr;
                              21320                 :                :     BulkInsertState bistate;    /* state of bulk inserts for partition */
                              21321                 :                :     TupleTableSlot *dstslot;
                              21322                 :                : 
                              21323                 :             33 :     mycid = GetCurrentCommandId(true);
                              21324                 :                : 
                              21325                 :                :     /* Prepare a BulkInsertState for table_tuple_insert. */
                              21326                 :             33 :     bistate = GetBulkInsertState();
                              21327                 :                : 
                              21328                 :                :     /* Create necessary tuple slot. */
                              21329                 :             33 :     dstslot = MakeSingleTupleTableSlot(RelationGetDescr(newPartRel),
                              21330                 :                :                                        table_slot_callbacks(newPartRel));
                              21331                 :             33 :     ExecStoreAllNullTuple(dstslot);
                              21332                 :                : 
                              21333   [ +  -  +  +  :            120 :     foreach(listptr, mergingPartitionsList)
                                              +  + ]
                              21334                 :                :     {
                              21335                 :             87 :         Relation    mergingPartition = (Relation) lfirst(listptr);
                              21336                 :                :         TupleTableSlot *srcslot;
                              21337                 :                :         TupleConversionMap *tuple_map;
                              21338                 :                :         TableScanDesc scan;
                              21339                 :                :         Snapshot    snapshot;
                              21340                 :                : 
                              21341                 :                :         /* Create tuple slot for new partition. */
                              21342                 :             87 :         srcslot = MakeSingleTupleTableSlot(RelationGetDescr(mergingPartition),
                              21343                 :                :                                            table_slot_callbacks(mergingPartition));
                              21344                 :                : 
                              21345                 :                :         /*
                              21346                 :                :          * Map computing for moving attributes of merged partition to new
                              21347                 :                :          * partition.
                              21348                 :                :          */
                              21349                 :             87 :         tuple_map = convert_tuples_by_name(RelationGetDescr(mergingPartition),
                              21350                 :                :                                            RelationGetDescr(newPartRel));
                              21351                 :                : 
                              21352                 :                :         /* Scan through the rows. */
                              21353                 :             87 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
                              21354                 :             87 :         scan = table_beginscan(mergingPartition, snapshot, 0, NULL);
                              21355                 :                : 
                              21356         [ +  + ]:            327 :         while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot))
                              21357                 :                :         {
                              21358                 :                :             TupleTableSlot *insertslot;
                              21359                 :                : 
                              21360                 :                :             /* Extract data from old tuple. */
                              21361                 :            153 :             slot_getallattrs(srcslot);
                              21362                 :                : 
                              21363         [ +  + ]:            153 :             if (tuple_map)
                              21364                 :                :             {
                              21365                 :                :                 /* Need to use map for copy attributes. */
                              21366                 :             15 :                 insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, dstslot);
                              21367                 :                :             }
                              21368                 :                :             else
                              21369                 :                :             {
                              21370                 :                :                 /* Copy attributes directly. */
                              21371                 :            138 :                 insertslot = dstslot;
                              21372                 :                : 
                              21373                 :            138 :                 ExecClearTuple(insertslot);
                              21374                 :                : 
                              21375                 :            138 :                 memcpy(insertslot->tts_values, srcslot->tts_values,
                              21376                 :            138 :                        sizeof(Datum) * srcslot->tts_nvalid);
                              21377                 :            138 :                 memcpy(insertslot->tts_isnull, srcslot->tts_isnull,
                              21378                 :            138 :                        sizeof(bool) * srcslot->tts_nvalid);
                              21379                 :                : 
                              21380                 :            138 :                 ExecStoreVirtualTuple(insertslot);
                              21381                 :                :             }
                              21382                 :                : 
                              21383                 :                :             /* Write the tuple out to the new relation. */
    3                         21384                 :            153 :             table_tuple_insert(newPartRel, insertslot, mycid,
                              21385                 :                :                                ti_options, bistate);
                              21386                 :                : 
    7                         21387         [ -  + ]:            153 :             CHECK_FOR_INTERRUPTS();
                              21388                 :                :         }
                              21389                 :                : 
                              21390                 :             87 :         table_endscan(scan);
                              21391                 :             87 :         UnregisterSnapshot(snapshot);
                              21392                 :                : 
                              21393         [ +  + ]:             87 :         if (tuple_map)
                              21394                 :              9 :             free_conversion_map(tuple_map);
                              21395                 :                : 
                              21396                 :             87 :         ExecDropSingleTupleTableSlot(srcslot);
                              21397                 :                :     }
                              21398                 :                : 
                              21399                 :             33 :     ExecDropSingleTupleTableSlot(dstslot);
                              21400                 :             33 :     FreeBulkInsertState(bistate);
                              21401                 :                : 
                              21402                 :             33 :     table_finish_bulk_insert(newPartRel, ti_options);
                              21403                 :             33 : }
                              21404                 :                : 
                              21405                 :                : /*
                              21406                 :                :  * ALTER TABLE <name> MERGE PARTITIONS <partition-list> INTO <partition-name>
                              21407                 :                :  */
                              21408                 :                : static void
                              21409                 :             33 : ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
                              21410                 :                :                       PartitionCmd *cmd, AlterTableUtilityContext *context)
                              21411                 :                : {
                              21412                 :                :     Relation    newPartRel;
                              21413                 :                :     ListCell   *listptr;
                              21414                 :             33 :     List       *mergingPartitionsList = NIL;
                              21415                 :                :     Oid         defaultPartOid;
                              21416                 :                :     char        tmpRelName[NAMEDATALEN];
                              21417                 :             33 :     RangeVar   *mergePartName = cmd->name;
                              21418                 :             33 :     bool        isSameName = false;
                              21419                 :                : 
                              21420                 :                :     /*
                              21421                 :                :      * Lock all merged partitions, check them and create list with partitions
                              21422                 :                :      * contexts.
                              21423                 :                :      */
                              21424   [ +  -  +  +  :            120 :     foreach(listptr, cmd->partlist)
                                              +  + ]
                              21425                 :                :     {
                              21426                 :             87 :         RangeVar   *name = (RangeVar *) lfirst(listptr);
                              21427                 :                :         Relation    mergingPartition;
                              21428                 :                : 
                              21429                 :                :         /*
                              21430                 :                :          * We are going to detach and remove this partition: need to use
                              21431                 :                :          * exclusive lock for preventing DML-queries to the partition.
                              21432                 :                :          */
                              21433                 :             87 :         mergingPartition = table_openrv(name, AccessExclusiveLock);
                              21434                 :                : 
                              21435                 :                :         /*
                              21436                 :                :          * Checking that two partitions have the same name was before, in
                              21437                 :                :          * function transformPartitionCmdForMerge().
                              21438                 :                :          */
                              21439         [ +  + ]:             87 :         if (equal(name, cmd->name))
                              21440                 :                :             /* One new partition can have the same name as merged partition. */
                              21441                 :              3 :             isSameName = true;
                              21442                 :                : 
                              21443                 :                :         /* Store a next merging partition into the list. */
                              21444                 :             87 :         mergingPartitionsList = lappend(mergingPartitionsList,
                              21445                 :                :                                         mergingPartition);
                              21446                 :                :     }
                              21447                 :                : 
                              21448                 :                :     /* Detach all merged partitions. */
                              21449                 :                :     defaultPartOid =
                              21450                 :             33 :         get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
                              21451   [ +  -  +  +  :            120 :     foreach(listptr, mergingPartitionsList)
                                              +  + ]
                              21452                 :                :     {
                              21453                 :             87 :         Relation    mergingPartition = (Relation) lfirst(listptr);
                              21454                 :                : 
                              21455                 :                :         /* Remove the pg_inherits row first. */
                              21456                 :             87 :         RemoveInheritance(mergingPartition, rel, false);
                              21457                 :                :         /* Do the final part of detaching. */
                              21458                 :             87 :         DetachPartitionFinalize(rel, mergingPartition, false, defaultPartOid);
                              21459                 :                :     }
                              21460                 :                : 
                              21461                 :                :     /* Create table for new partition, use partitioned table as model. */
                              21462         [ +  + ]:             33 :     if (isSameName)
                              21463                 :                :     {
                              21464                 :                :         /* Create partition table with generated temparary name. */
                              21465                 :              3 :         sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid);
                              21466                 :              3 :         mergePartName = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
                              21467                 :                :                                      tmpRelName, -1);
                              21468                 :                :     }
                              21469                 :             33 :     createPartitionTable(mergePartName,
                              21470                 :             33 :                          makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
                              21471                 :             33 :                                       RelationGetRelationName(rel), -1),
                              21472                 :                :                          context);
                              21473                 :                : 
                              21474                 :                :     /*
                              21475                 :                :      * Open the new partition and acquire exclusive lock on it.  This will
                              21476                 :                :      * stop all the operations with partitioned table.  This might seem
                              21477                 :                :      * excessive, but this is the way we make sure nobody is planning queries
                              21478                 :                :      * involving merging partitions.
                              21479                 :                :      */
                              21480                 :             33 :     newPartRel = table_openrv(mergePartName, AccessExclusiveLock);
                              21481                 :                : 
                              21482                 :                :     /* Copy data from merged partitions to new partition. */
                              21483                 :             33 :     moveMergedTablesRows(rel, mergingPartitionsList, newPartRel);
                              21484                 :                : 
                              21485                 :                :     /*
                              21486                 :                :      * Attach a new partition to the partitioned table. wqueue = NULL:
                              21487                 :                :      * verification for each cloned constraint is not need.
                              21488                 :                :      */
                              21489                 :             33 :     attachPartitionTable(NULL, rel, newPartRel, cmd->bound);
                              21490                 :                : 
                              21491                 :                :     /* Unlock and drop merged partitions. */
                              21492   [ +  -  +  +  :            120 :     foreach(listptr, mergingPartitionsList)
                                              +  + ]
                              21493                 :                :     {
                              21494                 :                :         ObjectAddress object;
                              21495                 :             87 :         Relation    mergingPartition = (Relation) lfirst(listptr);
                              21496                 :                : 
                              21497                 :                :         /* Get relation id before table_close() call. */
                              21498                 :             87 :         object.objectId = RelationGetRelid(mergingPartition);
                              21499                 :             87 :         object.classId = RelationRelationId;
                              21500                 :             87 :         object.objectSubId = 0;
                              21501                 :                : 
                              21502                 :                :         /* Keep the lock until commit. */
                              21503                 :             87 :         table_close(mergingPartition, NoLock);
                              21504                 :                : 
                              21505                 :             87 :         performDeletion(&object, DROP_RESTRICT, 0);
                              21506                 :                :     }
                              21507                 :             33 :     list_free(mergingPartitionsList);
                              21508                 :                : 
                              21509                 :                :     /* Rename new partition if it is needed. */
                              21510         [ +  + ]:             33 :     if (isSameName)
                              21511                 :                :     {
                              21512                 :                :         /*
                              21513                 :                :          * We must bump the command counter to make the new partition tuple
                              21514                 :                :          * visible for rename.
                              21515                 :                :          */
                              21516                 :              3 :         CommandCounterIncrement();
                              21517                 :                :         /* Rename partition. */
                              21518                 :              3 :         RenameRelationInternal(RelationGetRelid(newPartRel),
                              21519                 :              3 :                                cmd->name->relname, false, false);
                              21520                 :                :     }
                              21521                 :                :     /* Keep the lock until commit. */
                              21522                 :             33 :     table_close(newPartRel, NoLock);
                              21523                 :             33 : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622