LCOV - code coverage report
Current view: top level - src/backend/parser - parse_utilcmd.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.6 % 1816 1663
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 33 33
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 70.8 % 1532 1085

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * parse_utilcmd.c
       4                 :             :  *    Perform parse analysis work for various utility commands
       5                 :             :  *
       6                 :             :  * Formerly we did this work during parse_analyze_*() in analyze.c.  However
       7                 :             :  * that is fairly unsafe in the presence of querytree caching, since any
       8                 :             :  * database state that we depend on in making the transformations might be
       9                 :             :  * obsolete by the time the utility command is executed; and utility commands
      10                 :             :  * have no infrastructure for holding locks or rechecking plan validity.
      11                 :             :  * Hence these functions are now called at the start of execution of their
      12                 :             :  * respective utility commands.
      13                 :             :  *
      14                 :             :  *
      15                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      16                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      17                 :             :  *
      18                 :             :  *  src/backend/parser/parse_utilcmd.c
      19                 :             :  *
      20                 :             :  *-------------------------------------------------------------------------
      21                 :             :  */
      22                 :             : 
      23                 :             : #include "postgres.h"
      24                 :             : 
      25                 :             : #include "access/amapi.h"
      26                 :             : #include "access/attmap.h"
      27                 :             : #include "access/htup_details.h"
      28                 :             : #include "access/relation.h"
      29                 :             : #include "access/reloptions.h"
      30                 :             : #include "access/table.h"
      31                 :             : #include "access/toast_compression.h"
      32                 :             : #include "catalog/dependency.h"
      33                 :             : #include "catalog/heap.h"
      34                 :             : #include "catalog/index.h"
      35                 :             : #include "catalog/namespace.h"
      36                 :             : #include "catalog/partition.h"
      37                 :             : #include "catalog/pg_am.h"
      38                 :             : #include "catalog/pg_collation.h"
      39                 :             : #include "catalog/pg_constraint.h"
      40                 :             : #include "catalog/pg_opclass.h"
      41                 :             : #include "catalog/pg_operator.h"
      42                 :             : #include "catalog/pg_statistic_ext.h"
      43                 :             : #include "catalog/pg_type.h"
      44                 :             : #include "commands/comment.h"
      45                 :             : #include "commands/defrem.h"
      46                 :             : #include "commands/sequence.h"
      47                 :             : #include "commands/tablecmds.h"
      48                 :             : #include "commands/tablespace.h"
      49                 :             : #include "miscadmin.h"
      50                 :             : #include "nodes/makefuncs.h"
      51                 :             : #include "nodes/nodeFuncs.h"
      52                 :             : #include "optimizer/optimizer.h"
      53                 :             : #include "parser/analyze.h"
      54                 :             : #include "parser/parse_clause.h"
      55                 :             : #include "parser/parse_coerce.h"
      56                 :             : #include "parser/parse_collate.h"
      57                 :             : #include "parser/parse_expr.h"
      58                 :             : #include "parser/parse_relation.h"
      59                 :             : #include "parser/parse_target.h"
      60                 :             : #include "parser/parse_type.h"
      61                 :             : #include "parser/parse_utilcmd.h"
      62                 :             : #include "parser/parser.h"
      63                 :             : #include "partitioning/partbounds.h"
      64                 :             : #include "partitioning/partdesc.h"
      65                 :             : #include "rewrite/rewriteManip.h"
      66                 :             : #include "utils/acl.h"
      67                 :             : #include "utils/builtins.h"
      68                 :             : #include "utils/lsyscache.h"
      69                 :             : #include "utils/partcache.h"
      70                 :             : #include "utils/rel.h"
      71                 :             : #include "utils/ruleutils.h"
      72                 :             : #include "utils/syscache.h"
      73                 :             : #include "utils/typcache.h"
      74                 :             : 
      75                 :             : 
      76                 :             : /* State shared by transformCreateStmt and its subroutines */
      77                 :             : typedef struct
      78                 :             : {
      79                 :             :     ParseState *pstate;         /* overall parser state */
      80                 :             :     const char *stmtType;       /* "CREATE [FOREIGN] TABLE" or "ALTER TABLE" */
      81                 :             :     RangeVar   *relation;       /* relation to create */
      82                 :             :     Relation    rel;            /* opened/locked rel, if ALTER */
      83                 :             :     List       *inhRelations;   /* relations to inherit from */
      84                 :             :     bool        isforeign;      /* true if CREATE/ALTER FOREIGN TABLE */
      85                 :             :     bool        isalter;        /* true if altering existing table */
      86                 :             :     List       *columns;        /* ColumnDef items */
      87                 :             :     List       *ckconstraints;  /* CHECK constraints */
      88                 :             :     List       *nnconstraints;  /* NOT NULL constraints */
      89                 :             :     List       *fkconstraints;  /* FOREIGN KEY constraints */
      90                 :             :     List       *ixconstraints;  /* index-creating constraints */
      91                 :             :     List       *likeclauses;    /* LIKE clauses that need post-processing */
      92                 :             :     List       *blist;          /* "before list" of things to do before
      93                 :             :                                  * creating the table */
      94                 :             :     List       *alist;          /* "after list" of things to do after creating
      95                 :             :                                  * the table */
      96                 :             :     IndexStmt  *pkey;           /* PRIMARY KEY index, if any */
      97                 :             :     bool        ispartitioned;  /* true if table is partitioned */
      98                 :             :     PartitionBoundSpec *partbound;  /* transformed FOR VALUES */
      99                 :             :     bool        ofType;         /* true if statement contains OF typename */
     100                 :             : } CreateStmtContext;
     101                 :             : 
     102                 :             : 
     103                 :             : static void transformColumnDefinition(CreateStmtContext *cxt,
     104                 :             :                                       ColumnDef *column);
     105                 :             : static void transformTableConstraint(CreateStmtContext *cxt,
     106                 :             :                                      Constraint *constraint);
     107                 :             : static void transformTableLikeClause(CreateStmtContext *cxt,
     108                 :             :                                      TableLikeClause *table_like_clause);
     109                 :             : static void transformOfType(CreateStmtContext *cxt,
     110                 :             :                             TypeName *ofTypename);
     111                 :             : static CreateStatsStmt *generateClonedExtStatsStmt(RangeVar *heapRel,
     112                 :             :                                                    Oid heapRelid,
     113                 :             :                                                    Oid source_statsid,
     114                 :             :                                                    const AttrMap *attmap);
     115                 :             : static List *get_collation(Oid collation, Oid actual_datatype);
     116                 :             : static List *get_opclass(Oid opclass, Oid actual_datatype);
     117                 :             : static void transformIndexConstraints(CreateStmtContext *cxt);
     118                 :             : static IndexStmt *transformIndexConstraint(Constraint *constraint,
     119                 :             :                                            CreateStmtContext *cxt);
     120                 :             : static void transformFKConstraints(CreateStmtContext *cxt,
     121                 :             :                                    bool skipValidation,
     122                 :             :                                    bool isAddConstraint);
     123                 :             : static void transformCheckConstraints(CreateStmtContext *cxt,
     124                 :             :                                       bool skipValidation);
     125                 :             : static void transformConstraintAttrs(ParseState *pstate,
     126                 :             :                                      List *constraintList);
     127                 :             : static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column);
     128                 :             : static void checkSchemaNameRV(ParseState *pstate, const char *context_schema,
     129                 :             :                               RangeVar *relation);
     130                 :             : static void checkSchemaNameList(const char *context_schema,
     131                 :             :                                 List *qualified_name);
     132                 :             : static CreateStmt *transformCreateSchemaCreateTable(ParseState *pstate,
     133                 :             :                                                     CreateStmt *stmt,
     134                 :             :                                                     List **fk_elements);
     135                 :             : static void transformPartitionCmd(CreateStmtContext *cxt, PartitionBoundSpec *bound);
     136                 :             : static List *transformPartitionRangeBounds(ParseState *pstate, List *blist,
     137                 :             :                                            Relation parent);
     138                 :             : static void validateInfiniteBounds(ParseState *pstate, List *blist);
     139                 :             : static Const *transformPartitionBoundValue(ParseState *pstate, Node *val,
     140                 :             :                                            const char *colName, Oid colType, int32 colTypmod,
     141                 :             :                                            Oid partCollation);
     142                 :             : 
     143                 :             : 
     144                 :             : /*
     145                 :             :  * transformCreateStmt -
     146                 :             :  *    parse analysis for CREATE TABLE
     147                 :             :  *
     148                 :             :  * Returns a List of utility commands to be done in sequence.  One of these
     149                 :             :  * will be the transformed CreateStmt, but there may be additional actions
     150                 :             :  * to be done before and after the actual DefineRelation() call.
     151                 :             :  * In addition to normal utility commands such as AlterTableStmt and
     152                 :             :  * IndexStmt, the result list may contain TableLikeClause(s), representing
     153                 :             :  * the need to perform additional parse analysis after DefineRelation().
     154                 :             :  *
     155                 :             :  * SQL allows constraints to be scattered all over, so thumb through
     156                 :             :  * the columns and collect all constraints into one place.
     157                 :             :  * If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
     158                 :             :  * then expand those into multiple IndexStmt blocks.
     159                 :             :  *    - thomas 1997-12-02
     160                 :             :  */
     161                 :             : List *
     162                 :       26778 : transformCreateStmt(CreateStmt *stmt, const char *queryString)
     163                 :             : {
     164                 :             :     ParseState *pstate;
     165                 :             :     CreateStmtContext cxt;
     166                 :             :     List       *result;
     167                 :             :     List       *save_alist;
     168                 :             :     ListCell   *elements;
     169                 :             :     Oid         namespaceid;
     170                 :             :     Oid         existing_relid;
     171                 :             :     ParseCallbackState pcbstate;
     172                 :             : 
     173                 :             :     /* Set up pstate */
     174                 :       26778 :     pstate = make_parsestate(NULL);
     175                 :       26778 :     pstate->p_sourcetext = queryString;
     176                 :             : 
     177                 :             :     /*
     178                 :             :      * Look up the creation namespace.  This also checks permissions on the
     179                 :             :      * target namespace, locks it against concurrent drops, checks for a
     180                 :             :      * preexisting relation in that namespace with the same name, and updates
     181                 :             :      * stmt->relation->relpersistence if the selected namespace is temporary.
     182                 :             :      */
     183                 :       26778 :     setup_parser_errposition_callback(&pcbstate, pstate,
     184                 :       26778 :                                       stmt->relation->location);
     185                 :             :     namespaceid =
     186                 :       26778 :         RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock,
     187                 :             :                                              &existing_relid);
     188                 :       26766 :     cancel_parser_errposition_callback(&pcbstate);
     189                 :             : 
     190                 :             :     /*
     191                 :             :      * If the relation already exists and the user specified "IF NOT EXISTS",
     192                 :             :      * bail out with a NOTICE.
     193                 :             :      */
     194   [ +  +  +  + ]:       26766 :     if (stmt->if_not_exists && OidIsValid(existing_relid))
     195                 :             :     {
     196                 :             :         /*
     197                 :             :          * If we are in an extension script, insist that the pre-existing
     198                 :             :          * object be a member of the extension, to avoid security risks.
     199                 :             :          */
     200                 :             :         ObjectAddress address;
     201                 :             : 
     202                 :           6 :         ObjectAddressSet(address, RelationRelationId, existing_relid);
     203                 :           6 :         checkMembershipInCurrentExtension(&address);
     204                 :             : 
     205                 :             :         /* OK to skip */
     206         [ +  + ]:           5 :         ereport(NOTICE,
     207                 :             :                 (errcode(ERRCODE_DUPLICATE_TABLE),
     208                 :             :                  errmsg("relation \"%s\" already exists, skipping",
     209                 :             :                         stmt->relation->relname)));
     210                 :           5 :         return NIL;
     211                 :             :     }
     212                 :             : 
     213                 :             :     /*
     214                 :             :      * If the target relation name isn't schema-qualified, make it so.  This
     215                 :             :      * prevents some corner cases in which added-on rewritten commands might
     216                 :             :      * think they should apply to other relations that have the same name and
     217                 :             :      * are earlier in the search path.  But a local temp table is effectively
     218                 :             :      * specified to be in pg_temp, so no need for anything extra in that case.
     219                 :             :      */
     220         [ +  + ]:       26760 :     if (stmt->relation->schemaname == NULL
     221         [ +  + ]:       25088 :         && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
     222                 :       23385 :         stmt->relation->schemaname = get_namespace_name(namespaceid);
     223                 :             : 
     224                 :             :     /* Set up CreateStmtContext */
     225                 :       26760 :     cxt.pstate = pstate;
     226         [ +  + ]:       26760 :     if (IsA(stmt, CreateForeignTableStmt))
     227                 :             :     {
     228                 :         304 :         cxt.stmtType = "CREATE FOREIGN TABLE";
     229                 :         304 :         cxt.isforeign = true;
     230                 :             :     }
     231                 :             :     else
     232                 :             :     {
     233                 :       26456 :         cxt.stmtType = "CREATE TABLE";
     234                 :       26456 :         cxt.isforeign = false;
     235                 :             :     }
     236                 :       26760 :     cxt.relation = stmt->relation;
     237                 :       26760 :     cxt.rel = NULL;
     238                 :       26760 :     cxt.inhRelations = stmt->inhRelations;
     239                 :       26760 :     cxt.isalter = false;
     240                 :       26760 :     cxt.columns = NIL;
     241                 :       26760 :     cxt.ckconstraints = NIL;
     242                 :       26760 :     cxt.nnconstraints = NIL;
     243                 :       26760 :     cxt.fkconstraints = NIL;
     244                 :       26760 :     cxt.ixconstraints = NIL;
     245                 :       26760 :     cxt.likeclauses = NIL;
     246                 :       26760 :     cxt.blist = NIL;
     247                 :       26760 :     cxt.alist = NIL;
     248                 :       26760 :     cxt.pkey = NULL;
     249                 :       26760 :     cxt.ispartitioned = stmt->partspec != NULL;
     250                 :       26760 :     cxt.partbound = stmt->partbound;
     251                 :       26760 :     cxt.ofType = (stmt->ofTypename != NULL);
     252                 :             : 
     253                 :             :     Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */
     254                 :             : 
     255         [ +  + ]:       26760 :     if (stmt->ofTypename)
     256                 :          81 :         transformOfType(&cxt, stmt->ofTypename);
     257                 :             : 
     258         [ +  + ]:       26748 :     if (stmt->partspec)
     259                 :             :     {
     260   [ +  +  +  + ]:        3672 :         if (stmt->inhRelations && !stmt->partbound)
     261         [ +  - ]:           4 :             ereport(ERROR,
     262                 :             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     263                 :             :                      errmsg("cannot create partitioned table as inheritance child")));
     264                 :             :     }
     265                 :             : 
     266                 :             :     /*
     267                 :             :      * Run through each primary element in the table creation clause. Separate
     268                 :             :      * column defs from constraints, and do preliminary analysis.
     269                 :             :      */
     270   [ +  +  +  +  :       73014 :     foreach(elements, stmt->tableElts)
                   +  + ]
     271                 :             :     {
     272                 :       46431 :         Node       *element = lfirst(elements);
     273                 :             : 
     274   [ +  +  +  - ]:       46431 :         switch (nodeTag(element))
     275                 :             :         {
     276                 :       43895 :             case T_ColumnDef:
     277                 :       43895 :                 transformColumnDefinition(&cxt, (ColumnDef *) element);
     278                 :       43750 :                 break;
     279                 :             : 
     280                 :        2011 :             case T_Constraint:
     281                 :        2011 :                 transformTableConstraint(&cxt, (Constraint *) element);
     282                 :        2003 :                 break;
     283                 :             : 
     284                 :         525 :             case T_TableLikeClause:
     285                 :         525 :                 transformTableLikeClause(&cxt, (TableLikeClause *) element);
     286                 :         517 :                 break;
     287                 :             : 
     288                 :           0 :             default:
     289         [ #  # ]:           0 :                 elog(ERROR, "unrecognized node type: %d",
     290                 :             :                      (int) nodeTag(element));
     291                 :             :                 break;
     292                 :             :         }
     293                 :             :     }
     294                 :             : 
     295                 :             :     /*
     296                 :             :      * Transfer anything we already have in cxt.alist into save_alist, to keep
     297                 :             :      * it separate from the output of transformIndexConstraints.  (This may
     298                 :             :      * not be necessary anymore, but we'll keep doing it to preserve the
     299                 :             :      * historical order of execution of the alist commands.)
     300                 :             :      */
     301                 :       26583 :     save_alist = cxt.alist;
     302                 :       26583 :     cxt.alist = NIL;
     303                 :             : 
     304                 :             :     Assert(stmt->constraints == NIL);
     305                 :             : 
     306                 :             :     /*
     307                 :             :      * Before processing index constraints, which could include a primary key,
     308                 :             :      * we must scan all not-null constraints to propagate the is_not_null flag
     309                 :             :      * to each corresponding ColumnDef.  This is necessary because table-level
     310                 :             :      * not-null constraints have not been marked in each ColumnDef, and the PK
     311                 :             :      * processing code needs to know whether one constraint has already been
     312                 :             :      * declared in order not to declare a redundant one.
     313                 :             :      */
     314   [ +  +  +  +  :       61069 :     foreach_node(Constraint, nn, cxt.nnconstraints)
                   +  + ]
     315                 :             :     {
     316                 :        7903 :         char       *colname = strVal(linitial(nn->keys));
     317                 :             : 
     318   [ +  +  +  +  :       18811 :         foreach_node(ColumnDef, cd, cxt.columns)
                   +  + ]
     319                 :             :         {
     320                 :             :             /* not our column? */
     321         [ +  + ]:       10891 :             if (strcmp(cd->colname, colname) != 0)
     322                 :        3005 :                 continue;
     323                 :             :             /* Already marked not-null? Nothing to do */
     324         [ +  + ]:        7886 :             if (cd->is_not_null)
     325                 :        7546 :                 break;
     326                 :             :             /* Bingo, we're done for this constraint */
     327                 :         340 :             cd->is_not_null = true;
     328                 :         340 :             break;
     329                 :             :         }
     330                 :             :     }
     331                 :             : 
     332                 :             :     /*
     333                 :             :      * Postprocess constraints that give rise to index definitions.
     334                 :             :      */
     335                 :       26583 :     transformIndexConstraints(&cxt);
     336                 :             : 
     337                 :             :     /*
     338                 :             :      * Re-consideration of LIKE clauses should happen after creation of
     339                 :             :      * indexes, but before creation of foreign keys.  This order is critical
     340                 :             :      * because a LIKE clause may attempt to create a primary key.  If there's
     341                 :             :      * also a pkey in the main CREATE TABLE list, creation of that will not
     342                 :             :      * check for a duplicate at runtime (since index_check_primary_key()
     343                 :             :      * expects that we rejected dups here).  Creation of the LIKE-generated
     344                 :             :      * pkey behaves like ALTER TABLE ADD, so it will check, but obviously that
     345                 :             :      * only works if it happens second.  On the other hand, we want to make
     346                 :             :      * pkeys before foreign key constraints, in case the user tries to make a
     347                 :             :      * self-referential FK.
     348                 :             :      */
     349                 :       26555 :     cxt.alist = list_concat(cxt.alist, cxt.likeclauses);
     350                 :             : 
     351                 :             :     /*
     352                 :             :      * Postprocess foreign-key constraints.
     353                 :             :      */
     354                 :       26555 :     transformFKConstraints(&cxt, true, false);
     355                 :             : 
     356                 :             :     /*
     357                 :             :      * Postprocess check constraints.
     358                 :             :      *
     359                 :             :      * For regular tables all constraints can be marked valid immediately,
     360                 :             :      * because the table is new therefore empty. Not so for foreign tables.
     361                 :             :      */
     362                 :       26555 :     transformCheckConstraints(&cxt, !cxt.isforeign);
     363                 :             : 
     364                 :             :     /*
     365                 :             :      * Output results.
     366                 :             :      */
     367                 :       26555 :     stmt->tableElts = cxt.columns;
     368                 :       26555 :     stmt->constraints = cxt.ckconstraints;
     369                 :       26555 :     stmt->nnconstraints = cxt.nnconstraints;
     370                 :             : 
     371                 :       26555 :     result = lappend(cxt.blist, stmt);
     372                 :       26555 :     result = list_concat(result, cxt.alist);
     373                 :       26555 :     result = list_concat(result, save_alist);
     374                 :             : 
     375                 :       26555 :     return result;
     376                 :             : }
     377                 :             : 
     378                 :             : /*
     379                 :             :  * generateSerialExtraStmts
     380                 :             :  *      Generate CREATE SEQUENCE and ALTER SEQUENCE ... OWNED BY statements
     381                 :             :  *      to create the sequence for a serial or identity column.
     382                 :             :  *
     383                 :             :  * This includes determining the name the sequence will have.  The caller
     384                 :             :  * can ask to get back the name components by passing non-null pointers
     385                 :             :  * for snamespace_p and sname_p.
     386                 :             :  */
     387                 :             : static void
     388                 :         879 : generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
     389                 :             :                          Oid seqtypid, List *seqoptions,
     390                 :             :                          bool for_identity, bool col_exists,
     391                 :             :                          char **snamespace_p, char **sname_p)
     392                 :             : {
     393                 :             :     ListCell   *option;
     394                 :         879 :     DefElem    *nameEl = NULL;
     395                 :         879 :     DefElem    *loggedEl = NULL;
     396                 :             :     Oid         snamespaceid;
     397                 :             :     char       *snamespace;
     398                 :             :     char       *sname;
     399                 :             :     char        seqpersistence;
     400                 :             :     CreateSeqStmt *seqstmt;
     401                 :             :     AlterSeqStmt *altseqstmt;
     402                 :             :     List       *attnamelist;
     403                 :             : 
     404                 :             :     /* Make a copy of this as we may end up modifying it in the code below */
     405                 :         879 :     seqoptions = list_copy(seqoptions);
     406                 :             : 
     407                 :             :     /*
     408                 :             :      * Check for non-SQL-standard options (not supported within CREATE
     409                 :             :      * SEQUENCE, because they'd be redundant), and remove them from the
     410                 :             :      * seqoptions list if found.
     411                 :             :      */
     412   [ +  +  +  +  :        1085 :     foreach(option, seqoptions)
                   +  + ]
     413                 :             :     {
     414                 :         206 :         DefElem    *defel = lfirst_node(DefElem, option);
     415                 :             : 
     416         [ +  + ]:         206 :         if (strcmp(defel->defname, "sequence_name") == 0)
     417                 :             :         {
     418         [ -  + ]:          22 :             if (nameEl)
     419                 :           0 :                 errorConflictingDefElem(defel, cxt->pstate);
     420                 :          22 :             nameEl = defel;
     421                 :          22 :             seqoptions = foreach_delete_current(seqoptions, option);
     422                 :             :         }
     423         [ +  + ]:         184 :         else if (strcmp(defel->defname, "logged") == 0 ||
     424         [ +  + ]:         183 :                  strcmp(defel->defname, "unlogged") == 0)
     425                 :             :         {
     426         [ -  + ]:           2 :             if (loggedEl)
     427                 :           0 :                 errorConflictingDefElem(defel, cxt->pstate);
     428                 :           2 :             loggedEl = defel;
     429                 :           2 :             seqoptions = foreach_delete_current(seqoptions, option);
     430                 :             :         }
     431                 :             :     }
     432                 :             : 
     433                 :             :     /*
     434                 :             :      * Determine namespace and name to use for the sequence.
     435                 :             :      */
     436         [ +  + ]:         879 :     if (nameEl)
     437                 :             :     {
     438                 :             :         /* Use specified name */
     439                 :          22 :         RangeVar   *rv = makeRangeVarFromNameList(castNode(List, nameEl->arg));
     440                 :             : 
     441                 :          22 :         snamespace = rv->schemaname;
     442         [ -  + ]:          22 :         if (!snamespace)
     443                 :             :         {
     444                 :             :             /* Given unqualified SEQUENCE NAME, select namespace */
     445         [ #  # ]:           0 :             if (cxt->rel)
     446                 :           0 :                 snamespaceid = RelationGetNamespace(cxt->rel);
     447                 :             :             else
     448                 :           0 :                 snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
     449                 :           0 :             snamespace = get_namespace_name(snamespaceid);
     450                 :             :         }
     451                 :          22 :         sname = rv->relname;
     452                 :             :     }
     453                 :             :     else
     454                 :             :     {
     455                 :             :         /*
     456                 :             :          * Generate a name.
     457                 :             :          *
     458                 :             :          * Although we use ChooseRelationName, it's not guaranteed that the
     459                 :             :          * selected sequence name won't conflict; given sufficiently long
     460                 :             :          * field names, two different serial columns in the same table could
     461                 :             :          * be assigned the same sequence name, and we'd not notice since we
     462                 :             :          * aren't creating the sequence quite yet.  In practice this seems
     463                 :             :          * quite unlikely to be a problem, especially since few people would
     464                 :             :          * need two serial columns in one table.
     465                 :             :          */
     466         [ +  + ]:         857 :         if (cxt->rel)
     467                 :         137 :             snamespaceid = RelationGetNamespace(cxt->rel);
     468                 :             :         else
     469                 :             :         {
     470                 :         720 :             snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
     471                 :         720 :             RangeVarAdjustRelationPersistence(cxt->relation, snamespaceid);
     472                 :             :         }
     473                 :         857 :         snamespace = get_namespace_name(snamespaceid);
     474                 :         857 :         sname = ChooseRelationName(cxt->relation->relname,
     475                 :         857 :                                    column->colname,
     476                 :             :                                    "seq",
     477                 :             :                                    snamespaceid,
     478                 :             :                                    false);
     479                 :             :     }
     480                 :             : 
     481         [ +  + ]:         879 :     ereport(DEBUG1,
     482                 :             :             (errmsg_internal("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
     483                 :             :                              cxt->stmtType, sname,
     484                 :             :                              cxt->relation->relname, column->colname)));
     485                 :             : 
     486                 :             :     /*
     487                 :             :      * Determine the persistence of the sequence.  By default we copy the
     488                 :             :      * persistence of the table, but if LOGGED or UNLOGGED was specified, use
     489                 :             :      * that (as long as the table isn't TEMP).
     490                 :             :      *
     491                 :             :      * For CREATE TABLE, we get the persistence from cxt->relation, which
     492                 :             :      * comes from the CreateStmt in progress.  For ALTER TABLE, the parser
     493                 :             :      * won't set cxt->relation->relpersistence, but we have cxt->rel as the
     494                 :             :      * existing table, so we copy the persistence from there.
     495                 :             :      */
     496         [ +  + ]:         879 :     seqpersistence = cxt->rel ? cxt->rel->rd_rel->relpersistence : cxt->relation->relpersistence;
     497         [ +  + ]:         879 :     if (loggedEl)
     498                 :             :     {
     499         [ -  + ]:           2 :         if (seqpersistence == RELPERSISTENCE_TEMP)
     500         [ #  # ]:           0 :             ereport(ERROR,
     501                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     502                 :             :                      errmsg("cannot set logged status of a temporary sequence"),
     503                 :             :                      parser_errposition(cxt->pstate, loggedEl->location)));
     504         [ +  + ]:           2 :         else if (strcmp(loggedEl->defname, "logged") == 0)
     505                 :           1 :             seqpersistence = RELPERSISTENCE_PERMANENT;
     506                 :             :         else
     507                 :           1 :             seqpersistence = RELPERSISTENCE_UNLOGGED;
     508                 :             :     }
     509                 :             : 
     510                 :             :     /*
     511                 :             :      * Build a CREATE SEQUENCE command to create the sequence object, and add
     512                 :             :      * it to the list of things to be done before this CREATE/ALTER TABLE.
     513                 :             :      */
     514                 :         879 :     seqstmt = makeNode(CreateSeqStmt);
     515                 :         879 :     seqstmt->for_identity = for_identity;
     516                 :         879 :     seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
     517                 :         879 :     seqstmt->sequence->relpersistence = seqpersistence;
     518                 :         879 :     seqstmt->options = seqoptions;
     519                 :             : 
     520                 :             :     /*
     521                 :             :      * If a sequence data type was specified, add it to the options.  Prepend
     522                 :             :      * to the list rather than append; in case a user supplied their own AS
     523                 :             :      * clause, the "redundant options" error will point to their occurrence,
     524                 :             :      * not our synthetic one.
     525                 :             :      */
     526         [ +  + ]:         879 :     if (seqtypid)
     527                 :         871 :         seqstmt->options = lcons(makeDefElem("as",
     528                 :         871 :                                              (Node *) makeTypeNameFromOid(seqtypid, -1),
     529                 :             :                                              -1),
     530                 :             :                                  seqstmt->options);
     531                 :             : 
     532                 :             :     /*
     533                 :             :      * If this is ALTER ADD COLUMN, make sure the sequence will be owned by
     534                 :             :      * the table's owner.  The current user might be someone else (perhaps a
     535                 :             :      * superuser, or someone who's only a member of the owning role), but the
     536                 :             :      * SEQUENCE OWNED BY mechanisms will bleat unless table and sequence have
     537                 :             :      * exactly the same owning role.
     538                 :             :      */
     539         [ +  + ]:         879 :     if (cxt->rel)
     540                 :         159 :         seqstmt->ownerId = cxt->rel->rd_rel->relowner;
     541                 :             :     else
     542                 :         720 :         seqstmt->ownerId = InvalidOid;
     543                 :             : 
     544                 :         879 :     cxt->blist = lappend(cxt->blist, seqstmt);
     545                 :             : 
     546                 :             :     /*
     547                 :             :      * Store the identity sequence name that we decided on.  ALTER TABLE ...
     548                 :             :      * ADD COLUMN ... IDENTITY needs this so that it can fill the new column
     549                 :             :      * with values from the sequence, while the association of the sequence
     550                 :             :      * with the table is not set until after the ALTER TABLE.
     551                 :             :      */
     552                 :         879 :     column->identitySequence = seqstmt->sequence;
     553                 :             : 
     554                 :             :     /*
     555                 :             :      * Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence as
     556                 :             :      * owned by this column, and add it to the appropriate list of things to
     557                 :             :      * be done along with this CREATE/ALTER TABLE.  In a CREATE or ALTER ADD
     558                 :             :      * COLUMN, it must be done after the statement because we don't know the
     559                 :             :      * column's attnum yet.  But if we do have the attnum (in AT_AddIdentity),
     560                 :             :      * we can do the marking immediately, which improves some ALTER TABLE
     561                 :             :      * behaviors.
     562                 :             :      */
     563                 :         879 :     altseqstmt = makeNode(AlterSeqStmt);
     564                 :         879 :     altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
     565                 :         879 :     attnamelist = list_make3(makeString(snamespace),
     566                 :             :                              makeString(cxt->relation->relname),
     567                 :             :                              makeString(column->colname));
     568                 :         879 :     altseqstmt->options = list_make1(makeDefElem("owned_by",
     569                 :             :                                                  (Node *) attnamelist, -1));
     570                 :         879 :     altseqstmt->for_identity = for_identity;
     571                 :             : 
     572         [ +  + ]:         879 :     if (col_exists)
     573                 :         103 :         cxt->blist = lappend(cxt->blist, altseqstmt);
     574                 :             :     else
     575                 :         776 :         cxt->alist = lappend(cxt->alist, altseqstmt);
     576                 :             : 
     577         [ +  + ]:         879 :     if (snamespace_p)
     578                 :         548 :         *snamespace_p = snamespace;
     579         [ +  + ]:         879 :     if (sname_p)
     580                 :         548 :         *sname_p = sname;
     581                 :         879 : }
     582                 :             : 
     583                 :             : /*
     584                 :             :  * transformColumnDefinition -
     585                 :             :  *      transform a single ColumnDef within CREATE TABLE
     586                 :             :  *      Also used in ALTER TABLE ADD COLUMN
     587                 :             :  */
     588                 :             : static void
     589                 :       45400 : transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
     590                 :             : {
     591                 :             :     bool        is_serial;
     592                 :             :     bool        saw_nullable;
     593                 :             :     bool        saw_default;
     594                 :             :     bool        saw_identity;
     595                 :             :     bool        saw_generated;
     596                 :       45400 :     bool        need_notnull = false;
     597                 :       45400 :     bool        disallow_noinherit_notnull = false;
     598                 :       45400 :     Constraint *notnull_constraint = NULL;
     599                 :             : 
     600                 :       45400 :     cxt->columns = lappend(cxt->columns, column);
     601                 :             : 
     602                 :             :     /* Check for SERIAL pseudo-types */
     603                 :       45400 :     is_serial = false;
     604         [ +  + ]:       45400 :     if (column->typeName
     605         [ +  + ]:       45180 :         && list_length(column->typeName->names) == 1
     606         [ +  - ]:       19049 :         && !column->typeName->pct_type)
     607                 :             :     {
     608                 :       19049 :         char       *typname = strVal(linitial(column->typeName->names));
     609                 :             : 
     610         [ +  + ]:       19049 :         if (strcmp(typname, "smallserial") == 0 ||
     611         [ +  + ]:       19044 :             strcmp(typname, "serial2") == 0)
     612                 :             :         {
     613                 :           9 :             is_serial = true;
     614                 :           9 :             column->typeName->names = NIL;
     615                 :           9 :             column->typeName->typeOid = INT2OID;
     616                 :             :         }
     617         [ +  + ]:       19040 :         else if (strcmp(typname, "serial") == 0 ||
     618         [ -  + ]:       18519 :                  strcmp(typname, "serial4") == 0)
     619                 :             :         {
     620                 :         521 :             is_serial = true;
     621                 :         521 :             column->typeName->names = NIL;
     622                 :         521 :             column->typeName->typeOid = INT4OID;
     623                 :             :         }
     624         [ +  + ]:       18519 :         else if (strcmp(typname, "bigserial") == 0 ||
     625         [ +  + ]:       18509 :                  strcmp(typname, "serial8") == 0)
     626                 :             :         {
     627                 :          18 :             is_serial = true;
     628                 :          18 :             column->typeName->names = NIL;
     629                 :          18 :             column->typeName->typeOid = INT8OID;
     630                 :             :         }
     631                 :             : 
     632                 :             :         /*
     633                 :             :          * We have to reject "serial[]" explicitly, because once we've set
     634                 :             :          * typeid, LookupTypeName won't notice arrayBounds.  We don't need any
     635                 :             :          * special coding for serial(typmod) though.
     636                 :             :          */
     637   [ +  +  -  + ]:       19049 :         if (is_serial && column->typeName->arrayBounds != NIL)
     638         [ #  # ]:           0 :             ereport(ERROR,
     639                 :             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     640                 :             :                      errmsg("array of serial is not implemented"),
     641                 :             :                      parser_errposition(cxt->pstate,
     642                 :             :                                         column->typeName->location)));
     643                 :             :     }
     644                 :             : 
     645                 :             :     /* Do necessary work on the column type declaration */
     646         [ +  + ]:       45400 :     if (column->typeName)
     647                 :       45180 :         transformColumnType(cxt, column);
     648                 :             : 
     649                 :             :     /* Special actions for SERIAL pseudo-types */
     650         [ +  + ]:       45375 :     if (is_serial)
     651                 :             :     {
     652                 :             :         char       *snamespace;
     653                 :             :         char       *sname;
     654                 :             :         char       *qstring;
     655                 :             :         A_Const    *snamenode;
     656                 :             :         TypeCast   *castnode;
     657                 :             :         FuncCall   *funccallnode;
     658                 :             :         Constraint *constraint;
     659                 :             : 
     660                 :         548 :         generateSerialExtraStmts(cxt, column,
     661                 :         548 :                                  column->typeName->typeOid, NIL,
     662                 :             :                                  false, false,
     663                 :             :                                  &snamespace, &sname);
     664                 :             : 
     665                 :             :         /*
     666                 :             :          * Create appropriate constraints for SERIAL.  We do this in full,
     667                 :             :          * rather than shortcutting, so that we will detect any conflicting
     668                 :             :          * constraints the user wrote (like a different DEFAULT).
     669                 :             :          *
     670                 :             :          * Create an expression tree representing the function call
     671                 :             :          * nextval('sequencename').  We cannot reduce the raw tree to cooked
     672                 :             :          * form until after the sequence is created, but there's no need to do
     673                 :             :          * so.
     674                 :             :          */
     675                 :         548 :         qstring = quote_qualified_identifier(snamespace, sname);
     676                 :         548 :         snamenode = makeNode(A_Const);
     677                 :         548 :         snamenode->val.node.type = T_String;
     678                 :         548 :         snamenode->val.sval.sval = qstring;
     679                 :         548 :         snamenode->location = -1;
     680                 :         548 :         castnode = makeNode(TypeCast);
     681                 :         548 :         castnode->typeName = SystemTypeName("regclass");
     682                 :         548 :         castnode->arg = (Node *) snamenode;
     683                 :         548 :         castnode->location = -1;
     684                 :         548 :         funccallnode = makeFuncCall(SystemFuncName("nextval"),
     685                 :             :                                     list_make1(castnode),
     686                 :             :                                     COERCE_EXPLICIT_CALL,
     687                 :             :                                     -1);
     688                 :         548 :         constraint = makeNode(Constraint);
     689                 :         548 :         constraint->contype = CONSTR_DEFAULT;
     690                 :         548 :         constraint->location = -1;
     691                 :         548 :         constraint->raw_expr = (Node *) funccallnode;
     692                 :         548 :         constraint->cooked_expr = NULL;
     693                 :         548 :         column->constraints = lappend(column->constraints, constraint);
     694                 :             : 
     695                 :             :         /* have a not-null constraint added later */
     696                 :         548 :         need_notnull = true;
     697                 :         548 :         disallow_noinherit_notnull = true;
     698                 :             :     }
     699                 :             : 
     700                 :             :     /* Process column constraints, if any... */
     701                 :       45375 :     transformConstraintAttrs(cxt->pstate, column->constraints);
     702                 :             : 
     703                 :             :     /*
     704                 :             :      * First, scan the column's constraints to see if a not-null constraint
     705                 :             :      * that we add must be prevented from being NO INHERIT.  This should be
     706                 :             :      * enforced only for PRIMARY KEY, not IDENTITY or SERIAL.  However, if the
     707                 :             :      * not-null constraint is specified as a table constraint rather than as a
     708                 :             :      * column constraint, AddRelationNotNullConstraints would raise an error
     709                 :             :      * if a NO INHERIT mismatch is found.  To avoid inconsistently disallowing
     710                 :             :      * it in the table constraint case but not the column constraint case, we
     711                 :             :      * disallow it here as well.  Maybe AddRelationNotNullConstraints can be
     712                 :             :      * improved someday, so that it doesn't complain, and then we can remove
     713                 :             :      * the restriction for SERIAL and IDENTITY here as well.
     714                 :             :      */
     715         [ +  + ]:       45359 :     if (!disallow_noinherit_notnull)
     716                 :             :     {
     717   [ +  +  +  +  :      101393 :         foreach_node(Constraint, constraint, column->constraints)
                   +  + ]
     718                 :             :         {
     719         [ +  + ]:       11771 :             switch (constraint->contype)
     720                 :             :             {
     721                 :        3606 :                 case CONSTR_IDENTITY:
     722                 :             :                 case CONSTR_PRIMARY:
     723                 :        3606 :                     disallow_noinherit_notnull = true;
     724                 :        3606 :                     break;
     725                 :        8165 :                 default:
     726                 :        8165 :                     break;
     727                 :             :             }
     728                 :             :         }
     729                 :             :     }
     730                 :             : 
     731                 :             :     /* Now scan them again to do full processing */
     732                 :       45359 :     saw_nullable = false;
     733                 :       45359 :     saw_default = false;
     734                 :       45359 :     saw_identity = false;
     735                 :       45359 :     saw_generated = false;
     736                 :             : 
     737   [ +  +  +  +  :      103178 :     foreach_node(Constraint, constraint, column->constraints)
                   +  + ]
     738                 :             :     {
     739   [ +  +  +  +  :       12676 :         switch (constraint->contype)
          +  +  +  +  -  
                +  +  - ]
     740                 :             :         {
     741                 :          15 :             case CONSTR_NULL:
     742   [ -  +  -  -  :          15 :                 if ((saw_nullable && column->is_not_null) || need_notnull)
                   +  + ]
     743         [ +  - ]:           4 :                     ereport(ERROR,
     744                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     745                 :             :                              errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
     746                 :             :                                     column->colname, cxt->relation->relname),
     747                 :             :                              parser_errposition(cxt->pstate,
     748                 :             :                                                 constraint->location)));
     749                 :          11 :                 column->is_not_null = false;
     750                 :          11 :                 saw_nullable = true;
     751                 :          11 :                 break;
     752                 :             : 
     753                 :        4382 :             case CONSTR_NOTNULL:
     754   [ +  +  +  + ]:        4382 :                 if (cxt->ispartitioned && constraint->is_no_inherit)
     755         [ +  - ]:           4 :                     ereport(ERROR,
     756                 :             :                             errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     757                 :             :                             errmsg("not-null constraints on partitioned tables cannot be NO INHERIT"));
     758                 :             : 
     759                 :             :                 /* Disallow conflicting [NOT] NULL markings */
     760   [ +  +  -  + ]:        4378 :                 if (saw_nullable && !column->is_not_null)
     761         [ #  # ]:           0 :                     ereport(ERROR,
     762                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     763                 :             :                              errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
     764                 :             :                                     column->colname, cxt->relation->relname),
     765                 :             :                              parser_errposition(cxt->pstate,
     766                 :             :                                                 constraint->location)));
     767                 :             : 
     768   [ +  +  +  + ]:        4378 :                 if (disallow_noinherit_notnull && constraint->is_no_inherit)
     769         [ +  - ]:          20 :                     ereport(ERROR,
     770                 :             :                             errcode(ERRCODE_SYNTAX_ERROR),
     771                 :             :                             errmsg("conflicting NO INHERIT declarations for not-null constraints on column \"%s\"",
     772                 :             :                                    column->colname));
     773                 :             : 
     774                 :             :                 /*
     775                 :             :                  * If this is the first time we see this column being marked
     776                 :             :                  * not-null, add the constraint entry and keep track of it.
     777                 :             :                  * Also, remove previous markings that we need one.
     778                 :             :                  *
     779                 :             :                  * If this is a redundant not-null specification, just check
     780                 :             :                  * that it doesn't conflict with what was specified earlier.
     781                 :             :                  *
     782                 :             :                  * Any conflicts with table constraints will be further
     783                 :             :                  * checked in AddRelationNotNullConstraints().
     784                 :             :                  */
     785         [ +  + ]:        4358 :                 if (!column->is_not_null)
     786                 :             :                 {
     787                 :        4342 :                     column->is_not_null = true;
     788                 :        4342 :                     saw_nullable = true;
     789                 :        4342 :                     need_notnull = false;
     790                 :             : 
     791                 :        4342 :                     constraint->keys = list_make1(makeString(column->colname));
     792                 :        4342 :                     notnull_constraint = constraint;
     793                 :        4342 :                     cxt->nnconstraints = lappend(cxt->nnconstraints, constraint);
     794                 :             :                 }
     795         [ +  - ]:          16 :                 else if (notnull_constraint)
     796                 :             :                 {
     797         [ +  + ]:          16 :                     if (constraint->conname &&
     798         [ +  + ]:          12 :                         notnull_constraint->conname &&
     799         [ +  + ]:           8 :                         strcmp(notnull_constraint->conname, constraint->conname) != 0)
     800         [ +  - ]:           4 :                         elog(ERROR, "conflicting not-null constraint names \"%s\" and \"%s\"",
     801                 :             :                              notnull_constraint->conname, constraint->conname);
     802                 :             : 
     803         [ -  + ]:          12 :                     if (notnull_constraint->is_no_inherit != constraint->is_no_inherit)
     804         [ #  # ]:           0 :                         ereport(ERROR,
     805                 :             :                                 errcode(ERRCODE_SYNTAX_ERROR),
     806                 :             :                                 errmsg("conflicting NO INHERIT declarations for not-null constraints on column \"%s\"",
     807                 :             :                                        column->colname));
     808                 :             : 
     809   [ +  +  +  + ]:          12 :                     if (!notnull_constraint->conname && constraint->conname)
     810                 :           4 :                         notnull_constraint->conname = constraint->conname;
     811                 :             :                 }
     812                 :             : 
     813                 :        4354 :                 break;
     814                 :             : 
     815                 :        1645 :             case CONSTR_DEFAULT:
     816         [ -  + ]:        1645 :                 if (saw_default)
     817         [ #  # ]:           0 :                     ereport(ERROR,
     818                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     819                 :             :                              errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
     820                 :             :                                     column->colname, cxt->relation->relname),
     821                 :             :                              parser_errposition(cxt->pstate,
     822                 :             :                                                 constraint->location)));
     823                 :        1645 :                 column->raw_default = constraint->raw_expr;
     824                 :             :                 Assert(constraint->cooked_expr == NULL);
     825                 :        1645 :                 saw_default = true;
     826                 :        1645 :                 break;
     827                 :             : 
     828                 :         244 :             case CONSTR_IDENTITY:
     829                 :             :                 {
     830                 :             :                     Type        ctype;
     831                 :             :                     Oid         typeOid;
     832                 :             : 
     833         [ +  + ]:         244 :                     if (cxt->ofType)
     834         [ +  - ]:           4 :                         ereport(ERROR,
     835                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     836                 :             :                                  errmsg("identity columns are not supported on typed tables")));
     837         [ +  + ]:         240 :                     if (cxt->partbound)
     838         [ +  - ]:          16 :                         ereport(ERROR,
     839                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     840                 :             :                                  errmsg("identity columns are not supported on partitions")));
     841                 :             : 
     842                 :         224 :                     ctype = typenameType(cxt->pstate, column->typeName, NULL);
     843                 :         224 :                     typeOid = ((Form_pg_type) GETSTRUCT(ctype))->oid;
     844                 :         224 :                     ReleaseSysCache(ctype);
     845                 :             : 
     846         [ +  + ]:         224 :                     if (saw_identity)
     847         [ +  - ]:           4 :                         ereport(ERROR,
     848                 :             :                                 (errcode(ERRCODE_SYNTAX_ERROR),
     849                 :             :                                  errmsg("multiple identity specifications for column \"%s\" of table \"%s\"",
     850                 :             :                                         column->colname, cxt->relation->relname),
     851                 :             :                                  parser_errposition(cxt->pstate,
     852                 :             :                                                     constraint->location)));
     853                 :             : 
     854                 :         220 :                     generateSerialExtraStmts(cxt, column,
     855                 :             :                                              typeOid, constraint->options,
     856                 :             :                                              true, false,
     857                 :             :                                              NULL, NULL);
     858                 :             : 
     859                 :         220 :                     column->identity = constraint->generated_when;
     860                 :         220 :                     saw_identity = true;
     861                 :             : 
     862                 :             :                     /*
     863                 :             :                      * Identity columns are always NOT NULL, but we may have a
     864                 :             :                      * constraint already.
     865                 :             :                      */
     866         [ +  + ]:         220 :                     if (!saw_nullable)
     867                 :         204 :                         need_notnull = true;
     868         [ +  + ]:          16 :                     else if (!column->is_not_null)
     869         [ +  - ]:           4 :                         ereport(ERROR,
     870                 :             :                                 (errcode(ERRCODE_SYNTAX_ERROR),
     871                 :             :                                  errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
     872                 :             :                                         column->colname, cxt->relation->relname),
     873                 :             :                                  parser_errposition(cxt->pstate,
     874                 :             :                                                     constraint->location)));
     875                 :         216 :                     break;
     876                 :             :                 }
     877                 :             : 
     878                 :        1342 :             case CONSTR_GENERATED:
     879         [ +  + ]:        1342 :                 if (cxt->ofType)
     880         [ +  - ]:           8 :                     ereport(ERROR,
     881                 :             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     882                 :             :                              errmsg("generated columns are not supported on typed tables")));
     883         [ +  + ]:        1334 :                 if (saw_generated)
     884         [ +  - ]:           8 :                     ereport(ERROR,
     885                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     886                 :             :                              errmsg("multiple generation clauses specified for column \"%s\" of table \"%s\"",
     887                 :             :                                     column->colname, cxt->relation->relname),
     888                 :             :                              parser_errposition(cxt->pstate,
     889                 :             :                                                 constraint->location)));
     890                 :        1326 :                 column->generated = constraint->generated_kind;
     891                 :        1326 :                 column->raw_default = constraint->raw_expr;
     892                 :             :                 Assert(constraint->cooked_expr == NULL);
     893                 :        1326 :                 saw_generated = true;
     894                 :        1326 :                 break;
     895                 :             : 
     896                 :         364 :             case CONSTR_CHECK:
     897                 :         364 :                 cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
     898                 :         364 :                 break;
     899                 :             : 
     900                 :        3642 :             case CONSTR_PRIMARY:
     901   [ +  +  -  + ]:        3642 :                 if (saw_nullable && !column->is_not_null)
     902         [ #  # ]:           0 :                     ereport(ERROR,
     903                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     904                 :             :                              errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
     905                 :             :                                     column->colname, cxt->relation->relname),
     906                 :             :                              parser_errposition(cxt->pstate,
     907                 :             :                                                 constraint->location)));
     908                 :        3642 :                 need_notnull = true;
     909                 :             : 
     910         [ +  + ]:        3642 :                 if (cxt->isforeign)
     911         [ +  - ]:           4 :                     ereport(ERROR,
     912                 :             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     913                 :             :                              errmsg("primary key constraints are not supported on foreign tables"),
     914                 :             :                              parser_errposition(cxt->pstate,
     915                 :             :                                                 constraint->location)));
     916                 :             :                 pg_fallthrough;
     917                 :             : 
     918                 :             :             case CONSTR_UNIQUE:
     919         [ -  + ]:        3880 :                 if (cxt->isforeign)
     920         [ #  # ]:           0 :                     ereport(ERROR,
     921                 :             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     922                 :             :                              errmsg("unique constraints are not supported on foreign tables"),
     923                 :             :                              parser_errposition(cxt->pstate,
     924                 :             :                                                 constraint->location)));
     925         [ +  - ]:        3880 :                 if (constraint->keys == NIL)
     926                 :        3880 :                     constraint->keys = list_make1(makeString(column->colname));
     927                 :        3880 :                 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
     928                 :        3880 :                 break;
     929                 :             : 
     930                 :           0 :             case CONSTR_EXCLUSION:
     931                 :             :                 /* grammar does not allow EXCLUDE as a column constraint */
     932         [ #  # ]:           0 :                 elog(ERROR, "column exclusion constraints are not supported");
     933                 :             :                 break;
     934                 :             : 
     935                 :         620 :             case CONSTR_FOREIGN:
     936         [ +  + ]:         620 :                 if (cxt->isforeign)
     937         [ +  - ]:           4 :                     ereport(ERROR,
     938                 :             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     939                 :             :                              errmsg("foreign key constraints are not supported on foreign tables"),
     940                 :             :                              parser_errposition(cxt->pstate,
     941                 :             :                                                 constraint->location)));
     942                 :             : 
     943                 :             :                 /*
     944                 :             :                  * Fill in the current attribute's name and throw it into the
     945                 :             :                  * list of FK constraints to be processed later.
     946                 :             :                  */
     947                 :         616 :                 constraint->fk_attrs = list_make1(makeString(column->colname));
     948                 :         616 :                 cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
     949                 :         616 :                 break;
     950                 :             : 
     951                 :         180 :             case CONSTR_ATTR_DEFERRABLE:
     952                 :             :             case CONSTR_ATTR_NOT_DEFERRABLE:
     953                 :             :             case CONSTR_ATTR_DEFERRED:
     954                 :             :             case CONSTR_ATTR_IMMEDIATE:
     955                 :             :             case CONSTR_ATTR_ENFORCED:
     956                 :             :             case CONSTR_ATTR_NOT_ENFORCED:
     957                 :             :                 /* transformConstraintAttrs took care of these */
     958                 :         180 :                 break;
     959                 :             : 
     960                 :           0 :             default:
     961         [ #  # ]:           0 :                 elog(ERROR, "unrecognized constraint type: %d",
     962                 :             :                      constraint->contype);
     963                 :             :                 break;
     964                 :             :         }
     965                 :             : 
     966   [ +  +  +  + ]:       12592 :         if (saw_default && saw_identity)
     967         [ +  - ]:           8 :             ereport(ERROR,
     968                 :             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     969                 :             :                      errmsg("both default and identity specified for column \"%s\" of table \"%s\"",
     970                 :             :                             column->colname, cxt->relation->relname),
     971                 :             :                      parser_errposition(cxt->pstate,
     972                 :             :                                         constraint->location)));
     973                 :             : 
     974   [ +  +  +  + ]:       12584 :         if (saw_default && saw_generated)
     975         [ +  - ]:           8 :             ereport(ERROR,
     976                 :             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     977                 :             :                      errmsg("both default and generation expression specified for column \"%s\" of table \"%s\"",
     978                 :             :                             column->colname, cxt->relation->relname),
     979                 :             :                      parser_errposition(cxt->pstate,
     980                 :             :                                         constraint->location)));
     981                 :             : 
     982   [ +  +  +  + ]:       12576 :         if (saw_identity && saw_generated)
     983         [ +  - ]:           8 :             ereport(ERROR,
     984                 :             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     985                 :             :                      errmsg("both identity and generation expression specified for column \"%s\" of table \"%s\"",
     986                 :             :                             column->colname, cxt->relation->relname),
     987                 :             :                      parser_errposition(cxt->pstate,
     988                 :             :                                         constraint->location)));
     989                 :             :     }
     990                 :             : 
     991                 :             :     /*
     992                 :             :      * If we need a not-null constraint for PRIMARY KEY, SERIAL or IDENTITY,
     993                 :             :      * and one was not explicitly specified, add one now.
     994                 :             :      */
     995   [ +  +  +  +  :       45251 :     if (need_notnull && !(saw_nullable && column->is_not_null))
                   -  + ]
     996                 :             :     {
     997                 :        3437 :         column->is_not_null = true;
     998                 :        3437 :         notnull_constraint = makeNotNullConstraint(makeString(column->colname));
     999                 :        3437 :         cxt->nnconstraints = lappend(cxt->nnconstraints, notnull_constraint);
    1000                 :             :     }
    1001                 :             : 
    1002                 :             :     /*
    1003                 :             :      * If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
    1004                 :             :      * per-column foreign data wrapper options to this column after creation.
    1005                 :             :      */
    1006         [ +  + ]:       45251 :     if (column->fdwoptions != NIL)
    1007                 :             :     {
    1008                 :             :         AlterTableStmt *stmt;
    1009                 :             :         AlterTableCmd *cmd;
    1010                 :             : 
    1011                 :          85 :         cmd = makeNode(AlterTableCmd);
    1012                 :          85 :         cmd->subtype = AT_AlterColumnGenericOptions;
    1013                 :          85 :         cmd->name = column->colname;
    1014                 :          85 :         cmd->def = (Node *) column->fdwoptions;
    1015                 :          85 :         cmd->behavior = DROP_RESTRICT;
    1016                 :          85 :         cmd->missing_ok = false;
    1017                 :             : 
    1018                 :          85 :         stmt = makeNode(AlterTableStmt);
    1019                 :          85 :         stmt->relation = cxt->relation;
    1020                 :          85 :         stmt->cmds = NIL;
    1021                 :          85 :         stmt->objtype = OBJECT_FOREIGN_TABLE;
    1022                 :          85 :         stmt->cmds = lappend(stmt->cmds, cmd);
    1023                 :             : 
    1024                 :          85 :         cxt->alist = lappend(cxt->alist, stmt);
    1025                 :             :     }
    1026                 :       45251 : }
    1027                 :             : 
    1028                 :             : /*
    1029                 :             :  * transformTableConstraint
    1030                 :             :  *      transform a Constraint node within CREATE TABLE or ALTER TABLE
    1031                 :             :  */
    1032                 :             : static void
    1033                 :       12798 : transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
    1034                 :             : {
    1035   [ +  +  +  +  :       12798 :     switch (constraint->contype)
             +  +  -  - ]
    1036                 :             :     {
    1037                 :        5250 :         case CONSTR_PRIMARY:
    1038         [ +  + ]:        5250 :             if (cxt->isforeign)
    1039         [ +  - ]:           4 :                 ereport(ERROR,
    1040                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1041                 :             :                          errmsg("primary key constraints are not supported on foreign tables"),
    1042                 :             :                          parser_errposition(cxt->pstate,
    1043                 :             :                                             constraint->location)));
    1044                 :        5246 :             cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
    1045                 :        5246 :             break;
    1046                 :             : 
    1047                 :        3333 :         case CONSTR_UNIQUE:
    1048         [ +  + ]:        3333 :             if (cxt->isforeign)
    1049         [ +  - ]:           4 :                 ereport(ERROR,
    1050                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1051                 :             :                          errmsg("unique constraints are not supported on foreign tables"),
    1052                 :             :                          parser_errposition(cxt->pstate,
    1053                 :             :                                             constraint->location)));
    1054                 :        3329 :             cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
    1055                 :        3329 :             break;
    1056                 :             : 
    1057                 :         155 :         case CONSTR_EXCLUSION:
    1058         [ -  + ]:         155 :             if (cxt->isforeign)
    1059         [ #  # ]:           0 :                 ereport(ERROR,
    1060                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1061                 :             :                          errmsg("exclusion constraints are not supported on foreign tables"),
    1062                 :             :                          parser_errposition(cxt->pstate,
    1063                 :             :                                             constraint->location)));
    1064                 :         155 :             cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
    1065                 :         155 :             break;
    1066                 :             : 
    1067                 :        1037 :         case CONSTR_CHECK:
    1068                 :        1037 :             cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
    1069                 :        1037 :             break;
    1070                 :             : 
    1071                 :         756 :         case CONSTR_NOTNULL:
    1072   [ +  +  +  + ]:         756 :             if (cxt->ispartitioned && constraint->is_no_inherit)
    1073         [ +  - ]:           4 :                 ereport(ERROR,
    1074                 :             :                         errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1075                 :             :                         errmsg("not-null constraints on partitioned tables cannot be NO INHERIT"));
    1076                 :             : 
    1077                 :         752 :             cxt->nnconstraints = lappend(cxt->nnconstraints, constraint);
    1078                 :         752 :             break;
    1079                 :             : 
    1080                 :        2267 :         case CONSTR_FOREIGN:
    1081         [ -  + ]:        2267 :             if (cxt->isforeign)
    1082         [ #  # ]:           0 :                 ereport(ERROR,
    1083                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1084                 :             :                          errmsg("foreign key constraints are not supported on foreign tables"),
    1085                 :             :                          parser_errposition(cxt->pstate,
    1086                 :             :                                             constraint->location)));
    1087                 :        2267 :             cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
    1088                 :        2267 :             break;
    1089                 :             : 
    1090                 :           0 :         case CONSTR_NULL:
    1091                 :             :         case CONSTR_DEFAULT:
    1092                 :             :         case CONSTR_ATTR_DEFERRABLE:
    1093                 :             :         case CONSTR_ATTR_NOT_DEFERRABLE:
    1094                 :             :         case CONSTR_ATTR_DEFERRED:
    1095                 :             :         case CONSTR_ATTR_IMMEDIATE:
    1096                 :             :         case CONSTR_ATTR_ENFORCED:
    1097                 :             :         case CONSTR_ATTR_NOT_ENFORCED:
    1098         [ #  # ]:           0 :             elog(ERROR, "invalid context for constraint type %d",
    1099                 :             :                  constraint->contype);
    1100                 :             :             break;
    1101                 :             : 
    1102                 :           0 :         default:
    1103         [ #  # ]:           0 :             elog(ERROR, "unrecognized constraint type: %d",
    1104                 :             :                  constraint->contype);
    1105                 :             :             break;
    1106                 :             :     }
    1107                 :       12786 : }
    1108                 :             : 
    1109                 :             : /*
    1110                 :             :  * transformTableLikeClause
    1111                 :             :  *
    1112                 :             :  * Change the LIKE <srctable> portion of a CREATE TABLE statement into
    1113                 :             :  * column definitions that recreate the user defined column portions of
    1114                 :             :  * <srctable>.  Also, if there are any LIKE options that we can't fully
    1115                 :             :  * process at this point, add the TableLikeClause to cxt->likeclauses, which
    1116                 :             :  * will cause utility.c to call expandTableLikeClause() after the new
    1117                 :             :  * table has been created.
    1118                 :             :  *
    1119                 :             :  * Some options are ignored.  For example, as foreign tables have no storage,
    1120                 :             :  * these INCLUDING options have no effect: STORAGE, COMPRESSION, IDENTITY
    1121                 :             :  * and INDEXES.  Similarly, INCLUDING INDEXES is ignored from a view.
    1122                 :             :  */
    1123                 :             : static void
    1124                 :         525 : transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_clause)
    1125                 :             : {
    1126                 :             :     AttrNumber  parent_attno;
    1127                 :             :     Relation    relation;
    1128                 :             :     TupleDesc   tupleDesc;
    1129                 :             :     AclResult   aclresult;
    1130                 :             :     char       *comment;
    1131                 :             :     ParseCallbackState pcbstate;
    1132                 :             : 
    1133                 :         525 :     setup_parser_errposition_callback(&pcbstate, cxt->pstate,
    1134                 :         525 :                                       table_like_clause->relation->location);
    1135                 :             : 
    1136                 :             :     /* Open the relation referenced by the LIKE clause */
    1137                 :         525 :     relation = relation_openrv(table_like_clause->relation, AccessShareLock);
    1138                 :             : 
    1139         [ +  + ]:         521 :     if (relation->rd_rel->relkind != RELKIND_RELATION &&
    1140         [ +  + ]:         254 :         relation->rd_rel->relkind != RELKIND_VIEW &&
    1141         [ +  - ]:         246 :         relation->rd_rel->relkind != RELKIND_MATVIEW &&
    1142         [ +  + ]:         246 :         relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
    1143         [ +  - ]:         242 :         relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
    1144         [ +  + ]:         242 :         relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
    1145         [ +  - ]:           4 :         ereport(ERROR,
    1146                 :             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1147                 :             :                  errmsg("relation \"%s\" is invalid in LIKE clause",
    1148                 :             :                         RelationGetRelationName(relation)),
    1149                 :             :                  errdetail_relkind_not_supported(relation->rd_rel->relkind)));
    1150                 :             : 
    1151                 :         517 :     cancel_parser_errposition_callback(&pcbstate);
    1152                 :             : 
    1153                 :             :     /*
    1154                 :             :      * Check for privileges
    1155                 :             :      */
    1156         [ +  + ]:         517 :     if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
    1157                 :             :     {
    1158                 :           4 :         aclresult = object_aclcheck(TypeRelationId, relation->rd_rel->reltype, GetUserId(),
    1159                 :             :                                     ACL_USAGE);
    1160         [ -  + ]:           4 :         if (aclresult != ACLCHECK_OK)
    1161                 :           0 :             aclcheck_error(aclresult, OBJECT_TYPE,
    1162                 :           0 :                            RelationGetRelationName(relation));
    1163                 :             :     }
    1164                 :             :     else
    1165                 :             :     {
    1166                 :         513 :         aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
    1167                 :             :                                       ACL_SELECT);
    1168         [ -  + ]:         513 :         if (aclresult != ACLCHECK_OK)
    1169                 :           0 :             aclcheck_error(aclresult, get_relkind_objtype(relation->rd_rel->relkind),
    1170                 :           0 :                            RelationGetRelationName(relation));
    1171                 :             :     }
    1172                 :             : 
    1173                 :         517 :     tupleDesc = RelationGetDescr(relation);
    1174                 :             : 
    1175                 :             :     /*
    1176                 :             :      * Insert the copied attributes into the cxt for the new table definition.
    1177                 :             :      * We must do this now so that they appear in the table in the relative
    1178                 :             :      * position where the LIKE clause is, as required by SQL99.
    1179                 :             :      */
    1180         [ +  + ]:        1683 :     for (parent_attno = 1; parent_attno <= tupleDesc->natts;
    1181                 :        1166 :          parent_attno++)
    1182                 :             :     {
    1183                 :        1166 :         Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
    1184                 :             :                                                     parent_attno - 1);
    1185                 :             :         ColumnDef  *def;
    1186                 :             : 
    1187                 :             :         /*
    1188                 :             :          * Ignore dropped columns in the parent.
    1189                 :             :          */
    1190         [ +  + ]:        1166 :         if (attribute->attisdropped)
    1191                 :          24 :             continue;
    1192                 :             : 
    1193                 :             :         /*
    1194                 :             :          * Create a new column definition
    1195                 :             :          */
    1196                 :        1142 :         def = makeColumnDef(NameStr(attribute->attname), attribute->atttypid,
    1197                 :             :                             attribute->atttypmod, attribute->attcollation);
    1198                 :             : 
    1199                 :             :         /*
    1200                 :             :          * Add to column list
    1201                 :             :          */
    1202                 :        1142 :         cxt->columns = lappend(cxt->columns, def);
    1203                 :             : 
    1204                 :             :         /*
    1205                 :             :          * Although we don't transfer the column's default/generation
    1206                 :             :          * expression now, we need to mark it GENERATED if appropriate.
    1207                 :             :          */
    1208   [ +  +  +  + ]:        1142 :         if (attribute->atthasdef && attribute->attgenerated &&
    1209         [ +  + ]:          52 :             (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED))
    1210                 :          32 :             def->generated = attribute->attgenerated;
    1211                 :             : 
    1212                 :             :         /*
    1213                 :             :          * Copy identity if requested
    1214                 :             :          */
    1215         [ +  + ]:        1142 :         if (attribute->attidentity &&
    1216         [ +  + ]:          28 :             (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) &&
    1217         [ +  + ]:          12 :             !cxt->isforeign)
    1218                 :             :         {
    1219                 :             :             Oid         seq_relid;
    1220                 :             :             List       *seq_options;
    1221                 :             : 
    1222                 :             :             /*
    1223                 :             :              * find sequence owned by old column; extract sequence parameters;
    1224                 :             :              * build new create sequence command
    1225                 :             :              */
    1226                 :           8 :             seq_relid = getIdentitySequence(relation, attribute->attnum, false);
    1227                 :           8 :             seq_options = sequence_options(seq_relid);
    1228                 :           8 :             generateSerialExtraStmts(cxt, def,
    1229                 :             :                                      InvalidOid, seq_options,
    1230                 :             :                                      true, false,
    1231                 :             :                                      NULL, NULL);
    1232                 :           8 :             def->identity = attribute->attidentity;
    1233                 :             :         }
    1234                 :             : 
    1235                 :             :         /* Likewise, copy storage if requested */
    1236         [ +  + ]:        1142 :         if ((table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) &&
    1237         [ +  + ]:         130 :             !cxt->isforeign)
    1238                 :         110 :             def->storage = attribute->attstorage;
    1239                 :             :         else
    1240                 :        1032 :             def->storage = 0;
    1241                 :             : 
    1242                 :             :         /* Likewise, copy compression if requested */
    1243         [ +  + ]:        1142 :         if ((table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) != 0 &&
    1244         [ +  + ]:         100 :             CompressionMethodIsValid(attribute->attcompression) &&
    1245         [ +  + ]:           8 :             !cxt->isforeign)
    1246                 :           4 :             def->compression =
    1247                 :           4 :                 pstrdup(GetCompressionMethodName(attribute->attcompression));
    1248                 :             :         else
    1249                 :        1138 :             def->compression = NULL;
    1250                 :             : 
    1251                 :             :         /* Likewise, copy comment if requested */
    1252   [ +  +  +  + ]:        1278 :         if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
    1253                 :         136 :             (comment = GetComment(attribute->attrelid,
    1254                 :             :                                   RelationRelationId,
    1255                 :         136 :                                   attribute->attnum)) != NULL)
    1256                 :             :         {
    1257                 :          56 :             CommentStmt *stmt = makeNode(CommentStmt);
    1258                 :             : 
    1259                 :          56 :             stmt->objtype = OBJECT_COLUMN;
    1260                 :          56 :             stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
    1261                 :             :                                                makeString(cxt->relation->relname),
    1262                 :             :                                                makeString(def->colname));
    1263                 :          56 :             stmt->comment = comment;
    1264                 :             : 
    1265                 :          56 :             cxt->alist = lappend(cxt->alist, stmt);
    1266                 :             :         }
    1267                 :             :     }
    1268                 :             : 
    1269                 :             :     /*
    1270                 :             :      * Reproduce not-null constraints, if any, by copying them.  We do this
    1271                 :             :      * regardless of options given.
    1272                 :             :      */
    1273   [ +  +  +  + ]:         517 :     if (tupleDesc->constr && tupleDesc->constr->has_not_null)
    1274                 :             :     {
    1275                 :             :         List       *lst;
    1276                 :             : 
    1277                 :         226 :         lst = RelationGetNotNullConstraints(RelationGetRelid(relation), false,
    1278                 :             :                                             true);
    1279                 :         226 :         cxt->nnconstraints = list_concat(cxt->nnconstraints, lst);
    1280                 :             : 
    1281                 :             :         /* Copy comments on not-null constraints */
    1282         [ +  + ]:         226 :         if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
    1283                 :             :         {
    1284   [ +  -  +  +  :         148 :             foreach_node(Constraint, nnconstr, lst)
                   +  + ]
    1285                 :             :             {
    1286         [ +  + ]:          60 :                 if ((comment = GetComment(get_relation_constraint_oid(RelationGetRelid(relation),
    1287                 :          60 :                                                                       nnconstr->conname, false),
    1288                 :             :                                           ConstraintRelationId,
    1289                 :             :                                           0)) != NULL)
    1290                 :             :                 {
    1291                 :          20 :                     CommentStmt *stmt = makeNode(CommentStmt);
    1292                 :             : 
    1293                 :          20 :                     stmt->objtype = OBJECT_TABCONSTRAINT;
    1294                 :          20 :                     stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
    1295                 :             :                                                        makeString(cxt->relation->relname),
    1296                 :             :                                                        makeString(nnconstr->conname));
    1297                 :          20 :                     stmt->comment = comment;
    1298                 :          20 :                     cxt->alist = lappend(cxt->alist, stmt);
    1299                 :             :                 }
    1300                 :             :             }
    1301                 :             :         }
    1302                 :             :     }
    1303                 :             : 
    1304                 :             :     /*
    1305                 :             :      * We cannot yet deal with defaults, CHECK constraints, indexes, or
    1306                 :             :      * statistics, since we don't yet know what column numbers the copied
    1307                 :             :      * columns will have in the finished table.  If any of those options are
    1308                 :             :      * specified, add the LIKE clause to cxt->likeclauses so that
    1309                 :             :      * expandTableLikeClause will be called after we do know that.
    1310                 :             :      *
    1311                 :             :      * In order for this to work, we remember the relation OID so that
    1312                 :             :      * expandTableLikeClause is certain to open the same table.
    1313                 :             :      */
    1314         [ +  + ]:         517 :     if (table_like_clause->options &
    1315                 :             :         (CREATE_TABLE_LIKE_DEFAULTS |
    1316                 :             :          CREATE_TABLE_LIKE_GENERATED |
    1317                 :             :          CREATE_TABLE_LIKE_CONSTRAINTS |
    1318                 :             :          CREATE_TABLE_LIKE_INDEXES |
    1319                 :             :          CREATE_TABLE_LIKE_STATISTICS))
    1320                 :             :     {
    1321                 :         137 :         table_like_clause->relationOid = RelationGetRelid(relation);
    1322                 :         137 :         cxt->likeclauses = lappend(cxt->likeclauses, table_like_clause);
    1323                 :             :     }
    1324                 :             : 
    1325                 :             :     /*
    1326                 :             :      * Close the parent rel, but keep our AccessShareLock on it until xact
    1327                 :             :      * commit.  That will prevent someone else from deleting or ALTERing the
    1328                 :             :      * parent before we can run expandTableLikeClause.
    1329                 :             :      */
    1330                 :         517 :     table_close(relation, NoLock);
    1331                 :         517 : }
    1332                 :             : 
    1333                 :             : /*
    1334                 :             :  * expandTableLikeClause
    1335                 :             :  *
    1336                 :             :  * Process LIKE options that require knowing the final column numbers
    1337                 :             :  * assigned to the new table's columns.  This executes after we have
    1338                 :             :  * run DefineRelation for the new table.  It returns a list of utility
    1339                 :             :  * commands that should be run to generate indexes etc.
    1340                 :             :  */
    1341                 :             : List *
    1342                 :         137 : expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause)
    1343                 :             : {
    1344                 :         137 :     List       *result = NIL;
    1345                 :         137 :     List       *atsubcmds = NIL;
    1346                 :             :     AttrNumber  parent_attno;
    1347                 :             :     Relation    relation;
    1348                 :             :     Relation    childrel;
    1349                 :             :     TupleDesc   tupleDesc;
    1350                 :             :     TupleConstr *constr;
    1351                 :             :     AttrMap    *attmap;
    1352                 :             :     char       *comment;
    1353                 :             : 
    1354                 :             :     /*
    1355                 :             :      * Open the relation referenced by the LIKE clause.  We should still have
    1356                 :             :      * the table lock obtained by transformTableLikeClause (and this'll throw
    1357                 :             :      * an assertion failure if not).  Hence, no need to recheck privileges
    1358                 :             :      * etc.  We must open the rel by OID not name, to be sure we get the same
    1359                 :             :      * table.
    1360                 :             :      */
    1361         [ -  + ]:         137 :     if (!OidIsValid(table_like_clause->relationOid))
    1362         [ #  # ]:           0 :         elog(ERROR, "expandTableLikeClause called on untransformed LIKE clause");
    1363                 :             : 
    1364                 :         137 :     relation = relation_open(table_like_clause->relationOid, NoLock);
    1365                 :             : 
    1366                 :         137 :     tupleDesc = RelationGetDescr(relation);
    1367                 :         137 :     constr = tupleDesc->constr;
    1368                 :             : 
    1369                 :             :     /*
    1370                 :             :      * Open the newly-created child relation; we have lock on that too.
    1371                 :             :      */
    1372                 :         137 :     childrel = relation_openrv(heapRel, NoLock);
    1373                 :             : 
    1374                 :             :     /*
    1375                 :             :      * Construct a map from the LIKE relation's attnos to the child rel's.
    1376                 :             :      * This re-checks type match etc, although it shouldn't be possible to
    1377                 :             :      * have a failure since both tables are locked.
    1378                 :             :      */
    1379                 :         137 :     attmap = build_attrmap_by_name(RelationGetDescr(childrel),
    1380                 :             :                                    tupleDesc,
    1381                 :             :                                    false);
    1382                 :             : 
    1383                 :             :     /*
    1384                 :             :      * Process defaults, if required.
    1385                 :             :      */
    1386         [ +  + ]:         137 :     if ((table_like_clause->options &
    1387         [ +  + ]:          69 :          (CREATE_TABLE_LIKE_DEFAULTS | CREATE_TABLE_LIKE_GENERATED)) &&
    1388                 :             :         constr != NULL)
    1389                 :             :     {
    1390         [ +  + ]:         231 :         for (parent_attno = 1; parent_attno <= tupleDesc->natts;
    1391                 :         170 :              parent_attno++)
    1392                 :             :         {
    1393                 :         170 :             Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
    1394                 :             :                                                         parent_attno - 1);
    1395                 :             : 
    1396                 :             :             /*
    1397                 :             :              * Ignore dropped columns in the parent.
    1398                 :             :              */
    1399         [ +  + ]:         170 :             if (attribute->attisdropped)
    1400                 :           8 :                 continue;
    1401                 :             : 
    1402                 :             :             /*
    1403                 :             :              * Copy default, if present and it should be copied.  We have
    1404                 :             :              * separate options for plain default expressions and GENERATED
    1405                 :             :              * defaults.
    1406                 :             :              */
    1407   [ +  +  +  + ]:         223 :             if (attribute->atthasdef &&
    1408         [ +  + ]:          61 :                 (attribute->attgenerated ?
    1409                 :          36 :                  (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) :
    1410                 :          25 :                  (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS)))
    1411                 :             :             {
    1412                 :             :                 Node       *this_default;
    1413                 :             :                 AlterTableCmd *atsubcmd;
    1414                 :             :                 bool        found_whole_row;
    1415                 :             : 
    1416                 :          53 :                 this_default = TupleDescGetDefault(tupleDesc, parent_attno);
    1417         [ -  + ]:          53 :                 if (this_default == NULL)
    1418         [ #  # ]:           0 :                     elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
    1419                 :             :                          parent_attno, RelationGetRelationName(relation));
    1420                 :             : 
    1421                 :          53 :                 atsubcmd = makeNode(AlterTableCmd);
    1422                 :          53 :                 atsubcmd->subtype = AT_CookedColumnDefault;
    1423                 :          53 :                 atsubcmd->num = attmap->attnums[parent_attno - 1];
    1424                 :          53 :                 atsubcmd->def = map_variable_attnos(this_default,
    1425                 :             :                                                     1, 0,
    1426                 :             :                                                     attmap,
    1427                 :             :                                                     InvalidOid,
    1428                 :             :                                                     &found_whole_row);
    1429                 :             : 
    1430                 :             :                 /*
    1431                 :             :                  * Prevent this for the same reason as for constraints below.
    1432                 :             :                  * Note that defaults cannot contain any vars, so it's OK that
    1433                 :             :                  * the error message refers to generated columns.
    1434                 :             :                  */
    1435         [ -  + ]:          53 :                 if (found_whole_row)
    1436         [ #  # ]:           0 :                     ereport(ERROR,
    1437                 :             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1438                 :             :                              errmsg("cannot convert whole-row table reference"),
    1439                 :             :                              errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
    1440                 :             :                                        NameStr(attribute->attname),
    1441                 :             :                                        RelationGetRelationName(relation))));
    1442                 :             : 
    1443                 :          53 :                 atsubcmds = lappend(atsubcmds, atsubcmd);
    1444                 :             :             }
    1445                 :             :         }
    1446                 :             :     }
    1447                 :             : 
    1448                 :             :     /*
    1449                 :             :      * Copy CHECK constraints if requested, being careful to adjust attribute
    1450                 :             :      * numbers so they match the child.
    1451                 :             :      */
    1452   [ +  +  +  + ]:         137 :     if ((table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) &&
    1453                 :             :         constr != NULL)
    1454                 :             :     {
    1455                 :             :         int         ccnum;
    1456                 :             : 
    1457         [ +  + ]:         168 :         for (ccnum = 0; ccnum < constr->num_check; ccnum++)
    1458                 :             :         {
    1459                 :         100 :             char       *ccname = constr->check[ccnum].ccname;
    1460                 :         100 :             char       *ccbin = constr->check[ccnum].ccbin;
    1461                 :         100 :             bool        ccenforced = constr->check[ccnum].ccenforced;
    1462                 :         100 :             bool        ccnoinherit = constr->check[ccnum].ccnoinherit;
    1463                 :             :             Node       *ccbin_node;
    1464                 :             :             bool        found_whole_row;
    1465                 :             :             Constraint *n;
    1466                 :             :             AlterTableCmd *atsubcmd;
    1467                 :             : 
    1468                 :         100 :             ccbin_node = map_variable_attnos(stringToNode(ccbin),
    1469                 :             :                                              1, 0,
    1470                 :             :                                              attmap,
    1471                 :             :                                              InvalidOid, &found_whole_row);
    1472                 :             : 
    1473                 :             :             /*
    1474                 :             :              * We reject whole-row variables because the whole point of LIKE
    1475                 :             :              * is that the new table's rowtype might later diverge from the
    1476                 :             :              * parent's.  So, while translation might be possible right now,
    1477                 :             :              * it wouldn't be possible to guarantee it would work in future.
    1478                 :             :              */
    1479         [ -  + ]:         100 :             if (found_whole_row)
    1480         [ #  # ]:           0 :                 ereport(ERROR,
    1481                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1482                 :             :                          errmsg("cannot convert whole-row table reference"),
    1483                 :             :                          errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
    1484                 :             :                                    ccname,
    1485                 :             :                                    RelationGetRelationName(relation))));
    1486                 :             : 
    1487                 :         100 :             n = makeNode(Constraint);
    1488                 :         100 :             n->contype = CONSTR_CHECK;
    1489                 :         100 :             n->conname = pstrdup(ccname);
    1490                 :         100 :             n->location = -1;
    1491                 :         100 :             n->is_enforced = ccenforced;
    1492                 :         100 :             n->initially_valid = ccenforced; /* sic */
    1493                 :         100 :             n->is_no_inherit = ccnoinherit;
    1494                 :         100 :             n->raw_expr = NULL;
    1495                 :         100 :             n->cooked_expr = nodeToString(ccbin_node);
    1496                 :             : 
    1497                 :             :             /* We can skip validation, since the new table should be empty. */
    1498                 :         100 :             n->skip_validation = true;
    1499                 :             : 
    1500                 :         100 :             atsubcmd = makeNode(AlterTableCmd);
    1501                 :         100 :             atsubcmd->subtype = AT_AddConstraint;
    1502                 :         100 :             atsubcmd->def = (Node *) n;
    1503                 :         100 :             atsubcmds = lappend(atsubcmds, atsubcmd);
    1504                 :             : 
    1505                 :             :             /* Copy comment on constraint */
    1506   [ +  +  +  + ]:         176 :             if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
    1507                 :          76 :                 (comment = GetComment(get_relation_constraint_oid(RelationGetRelid(relation),
    1508                 :          76 :                                                                   n->conname, false),
    1509                 :             :                                       ConstraintRelationId,
    1510                 :             :                                       0)) != NULL)
    1511                 :             :             {
    1512                 :          20 :                 CommentStmt *stmt = makeNode(CommentStmt);
    1513                 :             : 
    1514                 :          20 :                 stmt->objtype = OBJECT_TABCONSTRAINT;
    1515                 :          20 :                 stmt->object = (Node *) list_make3(makeString(heapRel->schemaname),
    1516                 :             :                                                    makeString(heapRel->relname),
    1517                 :             :                                                    makeString(n->conname));
    1518                 :          20 :                 stmt->comment = comment;
    1519                 :             : 
    1520                 :          20 :                 result = lappend(result, stmt);
    1521                 :             :             }
    1522                 :             :         }
    1523                 :             :     }
    1524                 :             : 
    1525                 :             :     /*
    1526                 :             :      * If we generated any ALTER TABLE actions above, wrap them into a single
    1527                 :             :      * ALTER TABLE command.  Stick it at the front of the result, so it runs
    1528                 :             :      * before any CommentStmts we made above.
    1529                 :             :      */
    1530         [ +  + ]:         137 :     if (atsubcmds)
    1531                 :             :     {
    1532                 :          89 :         AlterTableStmt *atcmd = makeNode(AlterTableStmt);
    1533                 :             : 
    1534                 :          89 :         atcmd->relation = copyObject(heapRel);
    1535                 :          89 :         atcmd->cmds = atsubcmds;
    1536                 :          89 :         atcmd->objtype = OBJECT_TABLE;
    1537                 :          89 :         atcmd->missing_ok = false;
    1538                 :          89 :         result = lcons(atcmd, result);
    1539                 :             :     }
    1540                 :             : 
    1541                 :             :     /*
    1542                 :             :      * Process indexes if required.
    1543                 :             :      */
    1544         [ +  + ]:         137 :     if ((table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) &&
    1545         [ +  + ]:          73 :         relation->rd_rel->relhasindex &&
    1546         [ +  + ]:          57 :         childrel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
    1547                 :             :     {
    1548                 :             :         List       *parent_indexes;
    1549                 :             :         ListCell   *l;
    1550                 :             : 
    1551                 :          53 :         parent_indexes = RelationGetIndexList(relation);
    1552                 :             : 
    1553   [ +  -  +  +  :         139 :         foreach(l, parent_indexes)
                   +  + ]
    1554                 :             :         {
    1555                 :          86 :             Oid         parent_index_oid = lfirst_oid(l);
    1556                 :             :             Relation    parent_index;
    1557                 :             :             IndexStmt  *index_stmt;
    1558                 :             : 
    1559                 :          86 :             parent_index = index_open(parent_index_oid, AccessShareLock);
    1560                 :             : 
    1561                 :             :             /* Build CREATE INDEX statement to recreate the parent_index */
    1562                 :          86 :             index_stmt = generateClonedIndexStmt(heapRel,
    1563                 :             :                                                  parent_index,
    1564                 :             :                                                  attmap,
    1565                 :             :                                                  NULL);
    1566                 :             : 
    1567                 :             :             /* Copy comment on index, if requested */
    1568         [ +  + ]:          86 :             if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
    1569                 :             :             {
    1570                 :          48 :                 comment = GetComment(parent_index_oid, RelationRelationId, 0);
    1571                 :             : 
    1572                 :             :                 /*
    1573                 :             :                  * We make use of IndexStmt's idxcomment option, so as not to
    1574                 :             :                  * need to know now what name the index will have.
    1575                 :             :                  */
    1576                 :          48 :                 index_stmt->idxcomment = comment;
    1577                 :             :             }
    1578                 :             : 
    1579                 :          86 :             result = lappend(result, index_stmt);
    1580                 :             : 
    1581                 :          86 :             index_close(parent_index, AccessShareLock);
    1582                 :             :         }
    1583                 :             :     }
    1584                 :             : 
    1585                 :             :     /*
    1586                 :             :      * Process extended statistics if required.
    1587                 :             :      */
    1588         [ +  + ]:         137 :     if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS)
    1589                 :             :     {
    1590                 :             :         List       *parent_extstats;
    1591                 :             :         ListCell   *l;
    1592                 :             : 
    1593                 :          48 :         parent_extstats = RelationGetStatExtList(relation);
    1594                 :             : 
    1595   [ +  +  +  +  :          88 :         foreach(l, parent_extstats)
                   +  + ]
    1596                 :             :         {
    1597                 :          40 :             Oid         parent_stat_oid = lfirst_oid(l);
    1598                 :             :             CreateStatsStmt *stats_stmt;
    1599                 :             : 
    1600                 :          40 :             stats_stmt = generateClonedExtStatsStmt(heapRel,
    1601                 :             :                                                     RelationGetRelid(childrel),
    1602                 :             :                                                     parent_stat_oid,
    1603                 :             :                                                     attmap);
    1604                 :             : 
    1605                 :             :             /* Copy comment on statistics object, if requested */
    1606         [ +  + ]:          40 :             if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
    1607                 :             :             {
    1608                 :          32 :                 comment = GetComment(parent_stat_oid, StatisticExtRelationId, 0);
    1609                 :             : 
    1610                 :             :                 /*
    1611                 :             :                  * We make use of CreateStatsStmt's stxcomment option, so as
    1612                 :             :                  * not to need to know now what name the statistics will have.
    1613                 :             :                  */
    1614                 :          32 :                 stats_stmt->stxcomment = comment;
    1615                 :             :             }
    1616                 :             : 
    1617                 :          40 :             result = lappend(result, stats_stmt);
    1618                 :             :         }
    1619                 :             : 
    1620                 :          48 :         list_free(parent_extstats);
    1621                 :             :     }
    1622                 :             : 
    1623                 :             :     /* Done with child rel */
    1624                 :         137 :     table_close(childrel, NoLock);
    1625                 :             : 
    1626                 :             :     /*
    1627                 :             :      * Close the parent rel, but keep our AccessShareLock on it until xact
    1628                 :             :      * commit.  That will prevent someone else from deleting or ALTERing the
    1629                 :             :      * parent before the child is committed.
    1630                 :             :      */
    1631                 :         137 :     table_close(relation, NoLock);
    1632                 :             : 
    1633                 :         137 :     return result;
    1634                 :             : }
    1635                 :             : 
    1636                 :             : static void
    1637                 :          81 : transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
    1638                 :             : {
    1639                 :             :     HeapTuple   tuple;
    1640                 :             :     TupleDesc   tupdesc;
    1641                 :             :     int         i;
    1642                 :             :     Oid         ofTypeId;
    1643                 :             : 
    1644                 :             :     Assert(ofTypename);
    1645                 :             : 
    1646                 :          81 :     tuple = typenameType(cxt->pstate, ofTypename, NULL);
    1647                 :          77 :     check_of_type(tuple);
    1648                 :          69 :     ofTypeId = ((Form_pg_type) GETSTRUCT(tuple))->oid;
    1649                 :          69 :     ofTypename->typeOid = ofTypeId; /* cached for later */
    1650                 :             : 
    1651                 :          69 :     tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
    1652         [ +  + ]:         207 :     for (i = 0; i < tupdesc->natts; i++)
    1653                 :             :     {
    1654                 :         138 :         Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
    1655                 :             :         ColumnDef  *n;
    1656                 :             : 
    1657         [ -  + ]:         138 :         if (attr->attisdropped)
    1658                 :           0 :             continue;
    1659                 :             : 
    1660                 :         138 :         n = makeColumnDef(NameStr(attr->attname), attr->atttypid,
    1661                 :             :                           attr->atttypmod, attr->attcollation);
    1662                 :         138 :         n->is_from_type = true;
    1663                 :             : 
    1664                 :         138 :         cxt->columns = lappend(cxt->columns, n);
    1665                 :             :     }
    1666         [ +  - ]:          69 :     ReleaseTupleDesc(tupdesc);
    1667                 :             : 
    1668                 :          69 :     ReleaseSysCache(tuple);
    1669                 :          69 : }
    1670                 :             : 
    1671                 :             : /*
    1672                 :             :  * Generate an IndexStmt node using information from an already existing index
    1673                 :             :  * "source_idx".
    1674                 :             :  *
    1675                 :             :  * heapRel is stored into the IndexStmt's relation field, but we don't use it
    1676                 :             :  * otherwise; some callers pass NULL, if they don't need it to be valid.
    1677                 :             :  * (The target relation might not exist yet, so we mustn't try to access it.)
    1678                 :             :  *
    1679                 :             :  * Attribute numbers in expression Vars are adjusted according to attmap.
    1680                 :             :  *
    1681                 :             :  * If constraintOid isn't NULL, we store the OID of any constraint associated
    1682                 :             :  * with the index there.
    1683                 :             :  *
    1684                 :             :  * Unlike transformIndexConstraint, we don't make any effort to force primary
    1685                 :             :  * key columns to be not-null.  The larger cloning process this is part of
    1686                 :             :  * should have cloned their not-null status separately (and DefineIndex will
    1687                 :             :  * complain if that fails to happen).
    1688                 :             :  */
    1689                 :             : IndexStmt *
    1690                 :        2177 : generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
    1691                 :             :                         const AttrMap *attmap,
    1692                 :             :                         Oid *constraintOid)
    1693                 :             : {
    1694                 :        2177 :     Oid         source_relid = RelationGetRelid(source_idx);
    1695                 :             :     HeapTuple   ht_idxrel;
    1696                 :             :     HeapTuple   ht_idx;
    1697                 :             :     HeapTuple   ht_am;
    1698                 :             :     Form_pg_class idxrelrec;
    1699                 :             :     Form_pg_index idxrec;
    1700                 :             :     Form_pg_am  amrec;
    1701                 :             :     oidvector  *indcollation;
    1702                 :             :     oidvector  *indclass;
    1703                 :             :     IndexStmt  *index;
    1704                 :             :     List       *indexprs;
    1705                 :             :     ListCell   *indexpr_item;
    1706                 :             :     Oid         indrelid;
    1707                 :             :     int         keyno;
    1708                 :             :     Oid         keycoltype;
    1709                 :             :     Datum       datum;
    1710                 :             :     bool        isnull;
    1711                 :             : 
    1712         [ +  + ]:        2177 :     if (constraintOid)
    1713                 :        1417 :         *constraintOid = InvalidOid;
    1714                 :             : 
    1715                 :             :     /*
    1716                 :             :      * Fetch pg_class tuple of source index.  We can't use the copy in the
    1717                 :             :      * relcache entry because it doesn't include optional fields.
    1718                 :             :      */
    1719                 :        2177 :     ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(source_relid));
    1720         [ -  + ]:        2177 :     if (!HeapTupleIsValid(ht_idxrel))
    1721         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for relation %u", source_relid);
    1722                 :        2177 :     idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
    1723                 :             : 
    1724                 :             :     /* Fetch pg_index tuple for source index from relcache entry */
    1725                 :        2177 :     ht_idx = source_idx->rd_indextuple;
    1726                 :        2177 :     idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
    1727                 :        2177 :     indrelid = idxrec->indrelid;
    1728                 :             : 
    1729                 :             :     /* Fetch the pg_am tuple of the index' access method */
    1730                 :        2177 :     ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
    1731         [ -  + ]:        2177 :     if (!HeapTupleIsValid(ht_am))
    1732         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for access method %u",
    1733                 :             :              idxrelrec->relam);
    1734                 :        2177 :     amrec = (Form_pg_am) GETSTRUCT(ht_am);
    1735                 :             : 
    1736                 :             :     /* Extract indcollation from the pg_index tuple */
    1737                 :        2177 :     datum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
    1738                 :             :                                    Anum_pg_index_indcollation);
    1739                 :        2177 :     indcollation = (oidvector *) DatumGetPointer(datum);
    1740                 :             : 
    1741                 :             :     /* Extract indclass from the pg_index tuple */
    1742                 :        2177 :     datum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx, Anum_pg_index_indclass);
    1743                 :        2177 :     indclass = (oidvector *) DatumGetPointer(datum);
    1744                 :             : 
    1745                 :             :     /* Begin building the IndexStmt */
    1746                 :        2177 :     index = makeNode(IndexStmt);
    1747                 :        2177 :     index->relation = heapRel;
    1748                 :        2177 :     index->accessMethod = pstrdup(NameStr(amrec->amname));
    1749         [ +  + ]:        2177 :     if (OidIsValid(idxrelrec->reltablespace))
    1750                 :          58 :         index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
    1751                 :             :     else
    1752                 :        2119 :         index->tableSpace = NULL;
    1753                 :        2177 :     index->excludeOpNames = NIL;
    1754                 :        2177 :     index->idxcomment = NULL;
    1755                 :        2177 :     index->indexOid = InvalidOid;
    1756                 :        2177 :     index->oldNumber = InvalidRelFileNumber;
    1757                 :        2177 :     index->oldCreateSubid = InvalidSubTransactionId;
    1758                 :        2177 :     index->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
    1759                 :        2177 :     index->unique = idxrec->indisunique;
    1760                 :        2177 :     index->nulls_not_distinct = idxrec->indnullsnotdistinct;
    1761                 :        2177 :     index->primary = idxrec->indisprimary;
    1762   [ +  +  +  +  :        2177 :     index->iswithoutoverlaps = (idxrec->indisprimary || idxrec->indisunique) && idxrec->indisexclusion;
                   +  + ]
    1763                 :        2177 :     index->transformed = true;   /* don't need transformIndexStmt */
    1764                 :        2177 :     index->concurrent = false;
    1765                 :        2177 :     index->if_not_exists = false;
    1766                 :        2177 :     index->reset_default_tblspc = false;
    1767                 :             : 
    1768                 :             :     /*
    1769                 :             :      * We don't try to preserve the name of the source index; instead, just
    1770                 :             :      * let DefineIndex() choose a reasonable name.  (If we tried to preserve
    1771                 :             :      * the name, we'd get duplicate-relation-name failures unless the source
    1772                 :             :      * table was in a different schema.)
    1773                 :             :      */
    1774                 :        2177 :     index->idxname = NULL;
    1775                 :             : 
    1776                 :             :     /*
    1777                 :             :      * If the index is marked PRIMARY or has an exclusion condition, it's
    1778                 :             :      * certainly from a constraint; else, if it's not marked UNIQUE, it
    1779                 :             :      * certainly isn't.  If it is or might be from a constraint, we have to
    1780                 :             :      * fetch the pg_constraint record.
    1781                 :             :      */
    1782   [ +  +  +  +  :        2177 :     if (index->primary || index->unique || idxrec->indisexclusion)
                   +  + ]
    1783                 :        1160 :     {
    1784                 :        1160 :         Oid         constraintId = get_index_constraint(source_relid);
    1785                 :             : 
    1786         [ +  + ]:        1160 :         if (OidIsValid(constraintId))
    1787                 :             :         {
    1788                 :             :             HeapTuple   ht_constr;
    1789                 :             :             Form_pg_constraint conrec;
    1790                 :             : 
    1791         [ +  + ]:        1127 :             if (constraintOid)
    1792                 :        1009 :                 *constraintOid = constraintId;
    1793                 :             : 
    1794                 :        1127 :             ht_constr = SearchSysCache1(CONSTROID,
    1795                 :             :                                         ObjectIdGetDatum(constraintId));
    1796         [ -  + ]:        1127 :             if (!HeapTupleIsValid(ht_constr))
    1797         [ #  # ]:           0 :                 elog(ERROR, "cache lookup failed for constraint %u",
    1798                 :             :                      constraintId);
    1799                 :        1127 :             conrec = (Form_pg_constraint) GETSTRUCT(ht_constr);
    1800                 :             : 
    1801                 :        1127 :             index->isconstraint = true;
    1802                 :        1127 :             index->deferrable = conrec->condeferrable;
    1803                 :        1127 :             index->initdeferred = conrec->condeferred;
    1804                 :             : 
    1805                 :             :             /* If it's an exclusion constraint, we need the operator names */
    1806         [ +  + ]:        1127 :             if (idxrec->indisexclusion)
    1807                 :             :             {
    1808                 :             :                 Datum      *elems;
    1809                 :             :                 int         nElems;
    1810                 :             :                 int         i;
    1811                 :             : 
    1812                 :             :                 Assert(conrec->contype == CONSTRAINT_EXCLUSION ||
    1813                 :             :                        (index->iswithoutoverlaps &&
    1814                 :             :                         (conrec->contype == CONSTRAINT_PRIMARY || conrec->contype == CONSTRAINT_UNIQUE)));
    1815                 :             :                 /* Extract operator OIDs from the pg_constraint tuple */
    1816                 :          75 :                 datum = SysCacheGetAttrNotNull(CONSTROID, ht_constr,
    1817                 :             :                                                Anum_pg_constraint_conexclop);
    1818                 :          75 :                 deconstruct_array_builtin(DatumGetArrayTypeP(datum), OIDOID, &elems, NULL, &nElems);
    1819                 :             : 
    1820         [ +  + ]:         224 :                 for (i = 0; i < nElems; i++)
    1821                 :             :                 {
    1822                 :         149 :                     Oid         operid = DatumGetObjectId(elems[i]);
    1823                 :             :                     HeapTuple   opertup;
    1824                 :             :                     Form_pg_operator operform;
    1825                 :             :                     char       *oprname;
    1826                 :             :                     char       *nspname;
    1827                 :             :                     List       *namelist;
    1828                 :             : 
    1829                 :         149 :                     opertup = SearchSysCache1(OPEROID,
    1830                 :             :                                               ObjectIdGetDatum(operid));
    1831         [ -  + ]:         149 :                     if (!HeapTupleIsValid(opertup))
    1832         [ #  # ]:           0 :                         elog(ERROR, "cache lookup failed for operator %u",
    1833                 :             :                              operid);
    1834                 :         149 :                     operform = (Form_pg_operator) GETSTRUCT(opertup);
    1835                 :         149 :                     oprname = pstrdup(NameStr(operform->oprname));
    1836                 :             :                     /* For simplicity we always schema-qualify the op name */
    1837                 :         149 :                     nspname = get_namespace_name(operform->oprnamespace);
    1838                 :         149 :                     namelist = list_make2(makeString(nspname),
    1839                 :             :                                           makeString(oprname));
    1840                 :         149 :                     index->excludeOpNames = lappend(index->excludeOpNames,
    1841                 :             :                                                     namelist);
    1842                 :         149 :                     ReleaseSysCache(opertup);
    1843                 :             :                 }
    1844                 :             :             }
    1845                 :             : 
    1846                 :        1127 :             ReleaseSysCache(ht_constr);
    1847                 :             :         }
    1848                 :             :         else
    1849                 :          33 :             index->isconstraint = false;
    1850                 :             :     }
    1851                 :             :     else
    1852                 :        1017 :         index->isconstraint = false;
    1853                 :             : 
    1854                 :             :     /* Get the index expressions, if any */
    1855                 :        2177 :     datum = SysCacheGetAttr(INDEXRELID, ht_idx,
    1856                 :             :                             Anum_pg_index_indexprs, &isnull);
    1857         [ +  + ]:        2177 :     if (!isnull)
    1858                 :             :     {
    1859                 :             :         char       *exprsString;
    1860                 :             : 
    1861                 :         123 :         exprsString = TextDatumGetCString(datum);
    1862                 :         123 :         indexprs = (List *) stringToNode(exprsString);
    1863                 :             :     }
    1864                 :             :     else
    1865                 :        2054 :         indexprs = NIL;
    1866                 :             : 
    1867                 :             :     /* Build the list of IndexElem */
    1868                 :        2177 :     index->indexParams = NIL;
    1869                 :        2177 :     index->indexIncludingParams = NIL;
    1870                 :             : 
    1871                 :        2177 :     indexpr_item = list_head(indexprs);
    1872         [ +  + ]:        4729 :     for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++)
    1873                 :             :     {
    1874                 :             :         IndexElem  *iparam;
    1875                 :        2552 :         AttrNumber  attnum = idxrec->indkey.values[keyno];
    1876                 :        2552 :         Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
    1877                 :             :                                                keyno);
    1878                 :        2552 :         int16       opt = source_idx->rd_indoption[keyno];
    1879                 :             : 
    1880                 :        2552 :         iparam = makeNode(IndexElem);
    1881                 :             : 
    1882         [ +  + ]:        2552 :         if (AttributeNumberIsValid(attnum))
    1883                 :             :         {
    1884                 :             :             /* Simple index column */
    1885                 :             :             char       *attname;
    1886                 :             : 
    1887                 :        2429 :             attname = get_attname(indrelid, attnum, false);
    1888                 :        2429 :             keycoltype = get_atttype(indrelid, attnum);
    1889                 :             : 
    1890                 :        2429 :             iparam->name = attname;
    1891                 :        2429 :             iparam->expr = NULL;
    1892                 :             :         }
    1893                 :             :         else
    1894                 :             :         {
    1895                 :             :             /* Expressional index */
    1896                 :             :             Node       *indexkey;
    1897                 :             :             bool        found_whole_row;
    1898                 :             : 
    1899         [ -  + ]:         123 :             if (indexpr_item == NULL)
    1900         [ #  # ]:           0 :                 elog(ERROR, "too few entries in indexprs list");
    1901                 :         123 :             indexkey = (Node *) lfirst(indexpr_item);
    1902                 :         123 :             indexpr_item = lnext(indexprs, indexpr_item);
    1903                 :             : 
    1904                 :             :             /* Adjust Vars to match new table's column numbering */
    1905                 :         123 :             indexkey = map_variable_attnos(indexkey,
    1906                 :             :                                            1, 0,
    1907                 :             :                                            attmap,
    1908                 :             :                                            InvalidOid, &found_whole_row);
    1909                 :             : 
    1910                 :             :             /* As in expandTableLikeClause, reject whole-row variables */
    1911         [ -  + ]:         123 :             if (found_whole_row)
    1912         [ #  # ]:           0 :                 ereport(ERROR,
    1913                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1914                 :             :                          errmsg("cannot convert whole-row table reference"),
    1915                 :             :                          errdetail("Index \"%s\" contains a whole-row table reference.",
    1916                 :             :                                    RelationGetRelationName(source_idx))));
    1917                 :             : 
    1918                 :         123 :             iparam->name = NULL;
    1919                 :         123 :             iparam->expr = indexkey;
    1920                 :             : 
    1921                 :         123 :             keycoltype = exprType(indexkey);
    1922                 :             :         }
    1923                 :             : 
    1924                 :             :         /* Copy the original index column name */
    1925                 :        2552 :         iparam->indexcolname = pstrdup(NameStr(attr->attname));
    1926                 :             : 
    1927                 :             :         /* Add the collation name, if non-default */
    1928                 :        2552 :         iparam->collation = get_collation(indcollation->values[keyno], keycoltype);
    1929                 :             : 
    1930                 :             :         /* Add the operator class name, if non-default */
    1931                 :        2552 :         iparam->opclass = get_opclass(indclass->values[keyno], keycoltype);
    1932                 :        2552 :         iparam->opclassopts =
    1933                 :        2552 :             untransformRelOptions(get_attoptions(source_relid, keyno + 1));
    1934                 :             : 
    1935                 :        2552 :         iparam->ordering = SORTBY_DEFAULT;
    1936                 :        2552 :         iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
    1937                 :             : 
    1938                 :             :         /* Adjust options if necessary */
    1939         [ +  + ]:        2552 :         if (source_idx->rd_indam->amcanorder)
    1940                 :             :         {
    1941                 :             :             /*
    1942                 :             :              * If it supports sort ordering, copy DESC and NULLS opts. Don't
    1943                 :             :              * set non-default settings unnecessarily, though, so as to
    1944                 :             :              * improve the chance of recognizing equivalence to constraint
    1945                 :             :              * indexes.
    1946                 :             :              */
    1947         [ -  + ]:        2386 :             if (opt & INDOPTION_DESC)
    1948                 :             :             {
    1949                 :           0 :                 iparam->ordering = SORTBY_DESC;
    1950         [ #  # ]:           0 :                 if ((opt & INDOPTION_NULLS_FIRST) == 0)
    1951                 :           0 :                     iparam->nulls_ordering = SORTBY_NULLS_LAST;
    1952                 :             :             }
    1953                 :             :             else
    1954                 :             :             {
    1955         [ -  + ]:        2386 :                 if (opt & INDOPTION_NULLS_FIRST)
    1956                 :           0 :                     iparam->nulls_ordering = SORTBY_NULLS_FIRST;
    1957                 :             :             }
    1958                 :             :         }
    1959                 :             : 
    1960                 :        2552 :         iparam->location = -1;
    1961                 :             : 
    1962                 :        2552 :         index->indexParams = lappend(index->indexParams, iparam);
    1963                 :             :     }
    1964                 :             : 
    1965                 :             :     /* Handle included columns separately */
    1966         [ +  + ]:        2189 :     for (keyno = idxrec->indnkeyatts; keyno < idxrec->indnatts; keyno++)
    1967                 :             :     {
    1968                 :             :         IndexElem  *iparam;
    1969                 :          12 :         AttrNumber  attnum = idxrec->indkey.values[keyno];
    1970                 :          12 :         Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
    1971                 :             :                                                keyno);
    1972                 :             : 
    1973                 :          12 :         iparam = makeNode(IndexElem);
    1974                 :             : 
    1975         [ +  - ]:          12 :         if (AttributeNumberIsValid(attnum))
    1976                 :             :         {
    1977                 :             :             /* Simple index column */
    1978                 :             :             char       *attname;
    1979                 :             : 
    1980                 :          12 :             attname = get_attname(indrelid, attnum, false);
    1981                 :             : 
    1982                 :          12 :             iparam->name = attname;
    1983                 :          12 :             iparam->expr = NULL;
    1984                 :             :         }
    1985                 :             :         else
    1986         [ #  # ]:           0 :             ereport(ERROR,
    1987                 :             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1988                 :             :                      errmsg("expressions are not supported in included columns")));
    1989                 :             : 
    1990                 :             :         /* Copy the original index column name */
    1991                 :          12 :         iparam->indexcolname = pstrdup(NameStr(attr->attname));
    1992                 :             : 
    1993                 :          12 :         iparam->location = -1;
    1994                 :             : 
    1995                 :          12 :         index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
    1996                 :             :     }
    1997                 :             :     /* Copy reloptions if any */
    1998                 :        2177 :     datum = SysCacheGetAttr(RELOID, ht_idxrel,
    1999                 :             :                             Anum_pg_class_reloptions, &isnull);
    2000         [ -  + ]:        2177 :     if (!isnull)
    2001                 :           0 :         index->options = untransformRelOptions(datum);
    2002                 :             : 
    2003                 :             :     /* If it's a partial index, decompile and append the predicate */
    2004                 :        2177 :     datum = SysCacheGetAttr(INDEXRELID, ht_idx,
    2005                 :             :                             Anum_pg_index_indpred, &isnull);
    2006         [ +  + ]:        2177 :     if (!isnull)
    2007                 :             :     {
    2008                 :             :         char       *pred_str;
    2009                 :             :         Node       *pred_tree;
    2010                 :             :         bool        found_whole_row;
    2011                 :             : 
    2012                 :             :         /* Convert text string to node tree */
    2013                 :          20 :         pred_str = TextDatumGetCString(datum);
    2014                 :          20 :         pred_tree = (Node *) stringToNode(pred_str);
    2015                 :             : 
    2016                 :             :         /* Adjust Vars to match new table's column numbering */
    2017                 :          20 :         pred_tree = map_variable_attnos(pred_tree,
    2018                 :             :                                         1, 0,
    2019                 :             :                                         attmap,
    2020                 :             :                                         InvalidOid, &found_whole_row);
    2021                 :             : 
    2022                 :             :         /* As in expandTableLikeClause, reject whole-row variables */
    2023         [ -  + ]:          20 :         if (found_whole_row)
    2024         [ #  # ]:           0 :             ereport(ERROR,
    2025                 :             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2026                 :             :                      errmsg("cannot convert whole-row table reference"),
    2027                 :             :                      errdetail("Index \"%s\" contains a whole-row table reference.",
    2028                 :             :                                RelationGetRelationName(source_idx))));
    2029                 :             : 
    2030                 :          20 :         index->whereClause = pred_tree;
    2031                 :             :     }
    2032                 :             : 
    2033                 :             :     /* Clean up */
    2034                 :        2177 :     ReleaseSysCache(ht_idxrel);
    2035                 :        2177 :     ReleaseSysCache(ht_am);
    2036                 :             : 
    2037                 :        2177 :     return index;
    2038                 :             : }
    2039                 :             : 
    2040                 :             : /*
    2041                 :             :  * Generate a CreateStatsStmt node using information from an already existing
    2042                 :             :  * extended statistic "source_statsid", for the rel identified by heapRel and
    2043                 :             :  * heapRelid.
    2044                 :             :  *
    2045                 :             :  * stxkeys in the source statistic holds attribute numbers from the parent
    2046                 :             :  * relation.  Those attnums, along with the attribute numbers referenced by
    2047                 :             :  * Vars inside the expression tree, are remapped to the new relation's
    2048                 :             :  * numbering according to attmap.
    2049                 :             :  */
    2050                 :             : static CreateStatsStmt *
    2051                 :          40 : generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid,
    2052                 :             :                            Oid source_statsid, const AttrMap *attmap)
    2053                 :             : {
    2054                 :             :     HeapTuple   ht_stats;
    2055                 :             :     Form_pg_statistic_ext statsrec;
    2056                 :             :     CreateStatsStmt *stats;
    2057                 :          40 :     List       *stat_types = NIL;
    2058                 :          40 :     List       *def_names = NIL;
    2059                 :             :     bool        isnull;
    2060                 :             :     Datum       datum;
    2061                 :             :     ArrayType  *arr;
    2062                 :             :     char       *enabled;
    2063                 :             :     int         i;
    2064                 :             : 
    2065                 :             :     Assert(OidIsValid(heapRelid));
    2066                 :             :     Assert(heapRel != NULL);
    2067                 :             : 
    2068                 :             :     /*
    2069                 :             :      * Fetch pg_statistic_ext tuple of source statistics object.
    2070                 :             :      */
    2071                 :          40 :     ht_stats = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(source_statsid));
    2072         [ -  + ]:          40 :     if (!HeapTupleIsValid(ht_stats))
    2073         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for statistics object %u", source_statsid);
    2074                 :          40 :     statsrec = (Form_pg_statistic_ext) GETSTRUCT(ht_stats);
    2075                 :             : 
    2076                 :             :     /* Determine which statistics types exist */
    2077                 :          40 :     datum = SysCacheGetAttrNotNull(STATEXTOID, ht_stats,
    2078                 :             :                                    Anum_pg_statistic_ext_stxkind);
    2079                 :          40 :     arr = DatumGetArrayTypeP(datum);
    2080         [ +  - ]:          40 :     if (ARR_NDIM(arr) != 1 ||
    2081         [ +  - ]:          40 :         ARR_HASNULL(arr) ||
    2082         [ -  + ]:          40 :         ARR_ELEMTYPE(arr) != CHAROID)
    2083         [ #  # ]:           0 :         elog(ERROR, "stxkind is not a 1-D char array");
    2084         [ -  + ]:          40 :     enabled = (char *) ARR_DATA_PTR(arr);
    2085         [ +  + ]:         128 :     for (i = 0; i < ARR_DIMS(arr)[0]; i++)
    2086                 :             :     {
    2087         [ +  + ]:          88 :         if (enabled[i] == STATS_EXT_NDISTINCT)
    2088                 :          24 :             stat_types = lappend(stat_types, makeString("ndistinct"));
    2089         [ +  + ]:          64 :         else if (enabled[i] == STATS_EXT_DEPENDENCIES)
    2090                 :          24 :             stat_types = lappend(stat_types, makeString("dependencies"));
    2091         [ +  + ]:          40 :         else if (enabled[i] == STATS_EXT_MCV)
    2092                 :          24 :             stat_types = lappend(stat_types, makeString("mcv"));
    2093         [ +  - ]:          16 :         else if (enabled[i] == STATS_EXT_EXPRESSIONS)
    2094                 :             :             /* expression stats are not exposed to users */
    2095                 :          16 :             continue;
    2096                 :             :         else
    2097         [ #  # ]:           0 :             elog(ERROR, "unrecognized statistics kind %c", enabled[i]);
    2098                 :             :     }
    2099                 :             : 
    2100                 :             :     /* Determine which columns the statistics are on */
    2101         [ +  + ]:          88 :     for (i = 0; i < statsrec->stxkeys.dim1; i++)
    2102                 :             :     {
    2103                 :          48 :         StatsElem  *selem = makeNode(StatsElem);
    2104                 :          48 :         AttrNumber  attnum = statsrec->stxkeys.values[i];
    2105                 :             : 
    2106                 :          48 :         selem->name =
    2107                 :          48 :             get_attname(heapRelid, attmap->attnums[attnum - 1], false);
    2108                 :          48 :         selem->expr = NULL;
    2109                 :             : 
    2110                 :          48 :         def_names = lappend(def_names, selem);
    2111                 :             :     }
    2112                 :             : 
    2113                 :             :     /*
    2114                 :             :      * Now handle expressions, if there are any. The order (with respect to
    2115                 :             :      * regular attributes) does not really matter for extended stats, so we
    2116                 :             :      * simply append them after simple column references.
    2117                 :             :      *
    2118                 :             :      * XXX Some places during build/estimation treat expressions as if they
    2119                 :             :      * are before attributes, but for the CREATE command that's entirely
    2120                 :             :      * irrelevant.
    2121                 :             :      */
    2122                 :          40 :     datum = SysCacheGetAttr(STATEXTOID, ht_stats,
    2123                 :             :                             Anum_pg_statistic_ext_stxexprs, &isnull);
    2124                 :             : 
    2125         [ +  + ]:          40 :     if (!isnull)
    2126                 :             :     {
    2127                 :             :         ListCell   *lc;
    2128                 :          16 :         List       *exprs = NIL;
    2129                 :             :         char       *exprsString;
    2130                 :             : 
    2131                 :          16 :         exprsString = TextDatumGetCString(datum);
    2132                 :          16 :         exprs = (List *) stringToNode(exprsString);
    2133                 :             : 
    2134   [ +  -  +  +  :          32 :         foreach(lc, exprs)
                   +  + ]
    2135                 :             :         {
    2136                 :          16 :             Node       *expr = (Node *) lfirst(lc);
    2137                 :          16 :             StatsElem  *selem = makeNode(StatsElem);
    2138                 :             :             bool        found_whole_row;
    2139                 :             : 
    2140                 :             :             /* Adjust Vars to match new table's column numbering */
    2141                 :          16 :             expr = map_variable_attnos(expr,
    2142                 :             :                                        1, 0,
    2143                 :             :                                        attmap,
    2144                 :             :                                        InvalidOid,
    2145                 :             :                                        &found_whole_row);
    2146                 :             : 
    2147                 :          16 :             selem->name = NULL;
    2148                 :          16 :             selem->expr = expr;
    2149                 :             : 
    2150                 :          16 :             def_names = lappend(def_names, selem);
    2151                 :             :         }
    2152                 :             : 
    2153                 :          16 :         pfree(exprsString);
    2154                 :             :     }
    2155                 :             : 
    2156                 :             :     /* finally, build the output node */
    2157                 :          40 :     stats = makeNode(CreateStatsStmt);
    2158                 :          40 :     stats->defnames = NULL;
    2159                 :          40 :     stats->stat_types = stat_types;
    2160                 :          40 :     stats->exprs = def_names;
    2161                 :          40 :     stats->relations = list_make1(heapRel);
    2162                 :          40 :     stats->stxcomment = NULL;
    2163                 :          40 :     stats->transformed = true;   /* don't need transformStatsStmt again */
    2164                 :          40 :     stats->if_not_exists = false;
    2165                 :             : 
    2166                 :             :     /* Clean up */
    2167                 :          40 :     ReleaseSysCache(ht_stats);
    2168                 :             : 
    2169                 :          40 :     return stats;
    2170                 :             : }
    2171                 :             : 
    2172                 :             : /*
    2173                 :             :  * get_collation        - fetch qualified name of a collation
    2174                 :             :  *
    2175                 :             :  * If collation is InvalidOid or is the default for the given actual_datatype,
    2176                 :             :  * then the return value is NIL.
    2177                 :             :  */
    2178                 :             : static List *
    2179                 :        2552 : get_collation(Oid collation, Oid actual_datatype)
    2180                 :             : {
    2181                 :             :     List       *result;
    2182                 :             :     HeapTuple   ht_coll;
    2183                 :             :     Form_pg_collation coll_rec;
    2184                 :             :     char       *nsp_name;
    2185                 :             :     char       *coll_name;
    2186                 :             : 
    2187         [ +  + ]:        2552 :     if (!OidIsValid(collation))
    2188                 :        2281 :         return NIL;             /* easy case */
    2189         [ +  + ]:         271 :     if (collation == get_typcollation(actual_datatype))
    2190                 :         257 :         return NIL;             /* just let it default */
    2191                 :             : 
    2192                 :          14 :     ht_coll = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation));
    2193         [ -  + ]:          14 :     if (!HeapTupleIsValid(ht_coll))
    2194         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for collation %u", collation);
    2195                 :          14 :     coll_rec = (Form_pg_collation) GETSTRUCT(ht_coll);
    2196                 :             : 
    2197                 :             :     /* For simplicity, we always schema-qualify the name */
    2198                 :          14 :     nsp_name = get_namespace_name(coll_rec->collnamespace);
    2199                 :          14 :     coll_name = pstrdup(NameStr(coll_rec->collname));
    2200                 :          14 :     result = list_make2(makeString(nsp_name), makeString(coll_name));
    2201                 :             : 
    2202                 :          14 :     ReleaseSysCache(ht_coll);
    2203                 :          14 :     return result;
    2204                 :             : }
    2205                 :             : 
    2206                 :             : /*
    2207                 :             :  * get_opclass          - fetch qualified name of an index operator class
    2208                 :             :  *
    2209                 :             :  * If the opclass is the default for the given actual_datatype, then
    2210                 :             :  * the return value is NIL.
    2211                 :             :  */
    2212                 :             : static List *
    2213                 :        2552 : get_opclass(Oid opclass, Oid actual_datatype)
    2214                 :             : {
    2215                 :        2552 :     List       *result = NIL;
    2216                 :             :     HeapTuple   ht_opc;
    2217                 :             :     Form_pg_opclass opc_rec;
    2218                 :             : 
    2219                 :        2552 :     ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    2220         [ -  + ]:        2552 :     if (!HeapTupleIsValid(ht_opc))
    2221         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for opclass %u", opclass);
    2222                 :        2552 :     opc_rec = (Form_pg_opclass) GETSTRUCT(ht_opc);
    2223                 :             : 
    2224         [ +  + ]:        2552 :     if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
    2225                 :             :     {
    2226                 :             :         /* For simplicity, we always schema-qualify the name */
    2227                 :          16 :         char       *nsp_name = get_namespace_name(opc_rec->opcnamespace);
    2228                 :          16 :         char       *opc_name = pstrdup(NameStr(opc_rec->opcname));
    2229                 :             : 
    2230                 :          16 :         result = list_make2(makeString(nsp_name), makeString(opc_name));
    2231                 :             :     }
    2232                 :             : 
    2233                 :        2552 :     ReleaseSysCache(ht_opc);
    2234                 :        2552 :     return result;
    2235                 :             : }
    2236                 :             : 
    2237                 :             : 
    2238                 :             : /*
    2239                 :             :  * transformIndexConstraints
    2240                 :             :  *      Handle UNIQUE, PRIMARY KEY, EXCLUDE constraints, which create indexes.
    2241                 :             :  *      We also merge in any index definitions arising from
    2242                 :             :  *      LIKE ... INCLUDING INDEXES.
    2243                 :             :  */
    2244                 :             : static void
    2245                 :       42509 : transformIndexConstraints(CreateStmtContext *cxt)
    2246                 :             : {
    2247                 :             :     IndexStmt  *index;
    2248                 :       42509 :     List       *indexlist = NIL;
    2249                 :       42509 :     List       *finalindexlist = NIL;
    2250                 :             :     ListCell   *lc;
    2251                 :             : 
    2252                 :             :     /*
    2253                 :             :      * Run through the constraints that need to generate an index, and do so.
    2254                 :             :      *
    2255                 :             :      * For PRIMARY KEY, this queues not-null constraints for each column, if
    2256                 :             :      * needed.
    2257                 :             :      */
    2258   [ +  +  +  +  :       55047 :     foreach(lc, cxt->ixconstraints)
                   +  + ]
    2259                 :             :     {
    2260                 :       12582 :         Constraint *constraint = lfirst_node(Constraint, lc);
    2261                 :             : 
    2262                 :             :         Assert(constraint->contype == CONSTR_PRIMARY ||
    2263                 :             :                constraint->contype == CONSTR_UNIQUE ||
    2264                 :             :                constraint->contype == CONSTR_EXCLUSION);
    2265                 :             : 
    2266                 :       12582 :         index = transformIndexConstraint(constraint, cxt);
    2267                 :             : 
    2268                 :       12538 :         indexlist = lappend(indexlist, index);
    2269                 :             :     }
    2270                 :             : 
    2271                 :             :     /*
    2272                 :             :      * Scan the index list and remove any redundant index specifications. This
    2273                 :             :      * can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
    2274                 :             :      * strict reading of SQL would suggest raising an error instead, but that
    2275                 :             :      * strikes me as too anal-retentive. - tgl 2001-02-14
    2276                 :             :      *
    2277                 :             :      * XXX in ALTER TABLE case, it'd be nice to look for duplicate
    2278                 :             :      * pre-existing indexes, too.
    2279                 :             :      */
    2280         [ +  + ]:       42465 :     if (cxt->pkey != NULL)
    2281                 :             :     {
    2282                 :             :         /* Make sure we keep the PKEY index in preference to others... */
    2283                 :        8836 :         finalindexlist = list_make1(cxt->pkey);
    2284                 :             :     }
    2285                 :             : 
    2286   [ +  +  +  +  :       55003 :     foreach(lc, indexlist)
                   +  + ]
    2287                 :             :     {
    2288                 :       12538 :         bool        keep = true;
    2289                 :             :         ListCell   *k;
    2290                 :             : 
    2291                 :       12538 :         index = lfirst(lc);
    2292                 :             : 
    2293                 :             :         /* if it's pkey, it's already in finalindexlist */
    2294         [ +  + ]:       12538 :         if (index == cxt->pkey)
    2295                 :        8836 :             continue;
    2296                 :             : 
    2297   [ +  +  +  +  :        3826 :         foreach(k, finalindexlist)
                   +  + ]
    2298                 :             :         {
    2299                 :         124 :             IndexStmt  *priorindex = lfirst(k);
    2300                 :             : 
    2301   [ +  +  +  - ]:         128 :             if (equal(index->indexParams, priorindex->indexParams) &&
    2302         [ +  - ]:           8 :                 equal(index->indexIncludingParams, priorindex->indexIncludingParams) &&
    2303         [ +  - ]:           8 :                 equal(index->whereClause, priorindex->whereClause) &&
    2304                 :           4 :                 equal(index->excludeOpNames, priorindex->excludeOpNames) &&
    2305         [ +  - ]:           4 :                 strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
    2306         [ +  - ]:           4 :                 index->nulls_not_distinct == priorindex->nulls_not_distinct &&
    2307         [ -  + ]:           4 :                 index->deferrable == priorindex->deferrable &&
    2308         [ #  # ]:           0 :                 index->initdeferred == priorindex->initdeferred)
    2309                 :             :             {
    2310                 :           0 :                 priorindex->unique |= index->unique;
    2311                 :             : 
    2312                 :             :                 /*
    2313                 :             :                  * If the prior index is as yet unnamed, and this one is
    2314                 :             :                  * named, then transfer the name to the prior index. This
    2315                 :             :                  * ensures that if we have named and unnamed constraints,
    2316                 :             :                  * we'll use (at least one of) the names for the index.
    2317                 :             :                  */
    2318         [ #  # ]:           0 :                 if (priorindex->idxname == NULL)
    2319                 :           0 :                     priorindex->idxname = index->idxname;
    2320                 :           0 :                 keep = false;
    2321                 :           0 :                 break;
    2322                 :             :             }
    2323                 :             :         }
    2324                 :             : 
    2325         [ +  - ]:        3702 :         if (keep)
    2326                 :        3702 :             finalindexlist = lappend(finalindexlist, index);
    2327                 :             :     }
    2328                 :             : 
    2329                 :             :     /*
    2330                 :             :      * Now append all the IndexStmts to cxt->alist.
    2331                 :             :      */
    2332                 :       42465 :     cxt->alist = list_concat(cxt->alist, finalindexlist);
    2333                 :       42465 : }
    2334                 :             : 
    2335                 :             : /*
    2336                 :             :  * transformIndexConstraint
    2337                 :             :  *      Transform one UNIQUE, PRIMARY KEY, or EXCLUDE constraint for
    2338                 :             :  *      transformIndexConstraints. An IndexStmt is returned.
    2339                 :             :  *
    2340                 :             :  * For a PRIMARY KEY constraint, we additionally create not-null constraints
    2341                 :             :  * for columns that don't already have them.
    2342                 :             :  */
    2343                 :             : static IndexStmt *
    2344                 :       12582 : transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
    2345                 :             : {
    2346                 :             :     IndexStmt  *index;
    2347                 :             :     ListCell   *lc;
    2348                 :             : 
    2349                 :       12582 :     index = makeNode(IndexStmt);
    2350                 :             : 
    2351                 :       12582 :     index->unique = (constraint->contype != CONSTR_EXCLUSION);
    2352                 :       12582 :     index->primary = (constraint->contype == CONSTR_PRIMARY);
    2353         [ +  + ]:       12582 :     if (index->primary)
    2354                 :             :     {
    2355         [ -  + ]:        8856 :         if (cxt->pkey != NULL)
    2356         [ #  # ]:           0 :             ereport(ERROR,
    2357                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    2358                 :             :                      errmsg("multiple primary keys for table \"%s\" are not allowed",
    2359                 :             :                             cxt->relation->relname),
    2360                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2361                 :        8856 :         cxt->pkey = index;
    2362                 :             : 
    2363                 :             :         /*
    2364                 :             :          * In ALTER TABLE case, a primary index might already exist, but
    2365                 :             :          * DefineIndex will check for it.
    2366                 :             :          */
    2367                 :             :     }
    2368                 :       12582 :     index->nulls_not_distinct = constraint->nulls_not_distinct;
    2369                 :       12582 :     index->isconstraint = true;
    2370                 :       12582 :     index->iswithoutoverlaps = constraint->without_overlaps;
    2371                 :       12582 :     index->deferrable = constraint->deferrable;
    2372                 :       12582 :     index->initdeferred = constraint->initdeferred;
    2373                 :             : 
    2374         [ +  + ]:       12582 :     if (constraint->conname != NULL)
    2375                 :         978 :         index->idxname = pstrdup(constraint->conname);
    2376                 :             :     else
    2377                 :       11604 :         index->idxname = NULL;   /* DefineIndex will choose name */
    2378                 :             : 
    2379                 :       12582 :     index->relation = cxt->relation;
    2380         [ +  + ]:       12582 :     index->accessMethod = constraint->access_method ? constraint->access_method : DEFAULT_INDEX_TYPE;
    2381                 :       12582 :     index->options = constraint->options;
    2382                 :       12582 :     index->tableSpace = constraint->indexspace;
    2383                 :       12582 :     index->whereClause = constraint->where_clause;
    2384                 :       12582 :     index->indexParams = NIL;
    2385                 :       12582 :     index->indexIncludingParams = NIL;
    2386                 :       12582 :     index->excludeOpNames = NIL;
    2387                 :       12582 :     index->idxcomment = NULL;
    2388                 :       12582 :     index->indexOid = InvalidOid;
    2389                 :       12582 :     index->oldNumber = InvalidRelFileNumber;
    2390                 :       12582 :     index->oldCreateSubid = InvalidSubTransactionId;
    2391                 :       12582 :     index->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
    2392                 :       12582 :     index->transformed = false;
    2393                 :       12582 :     index->concurrent = false;
    2394                 :       12582 :     index->if_not_exists = false;
    2395                 :       12582 :     index->reset_default_tblspc = constraint->reset_default_tblspc;
    2396                 :             : 
    2397                 :             :     /*
    2398                 :             :      * If it's ALTER TABLE ADD CONSTRAINT USING INDEX, look up the index and
    2399                 :             :      * verify it's usable, then extract the implied column name list.  (We
    2400                 :             :      * will not actually need the column name list at runtime, but we need it
    2401                 :             :      * now to check for duplicate column entries below.)
    2402                 :             :      */
    2403         [ +  + ]:       12582 :     if (constraint->indexname != NULL)
    2404                 :             :     {
    2405                 :        6669 :         char       *index_name = constraint->indexname;
    2406                 :        6669 :         Relation    heap_rel = cxt->rel;
    2407                 :             :         Oid         index_oid;
    2408                 :             :         Relation    index_rel;
    2409                 :             :         Form_pg_index index_form;
    2410                 :             :         oidvector  *indclass;
    2411                 :             :         Datum       indclassDatum;
    2412                 :             :         int         i;
    2413                 :             : 
    2414                 :             :         /* Grammar should not allow this with explicit column list */
    2415                 :             :         Assert(constraint->keys == NIL);
    2416                 :             : 
    2417                 :             :         /* Grammar should only allow PRIMARY and UNIQUE constraints */
    2418                 :             :         Assert(constraint->contype == CONSTR_PRIMARY ||
    2419                 :             :                constraint->contype == CONSTR_UNIQUE);
    2420                 :             : 
    2421                 :             :         /* Must be ALTER, not CREATE, but grammar doesn't enforce that */
    2422         [ -  + ]:        6669 :         if (!cxt->isalter)
    2423         [ #  # ]:           0 :             ereport(ERROR,
    2424                 :             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2425                 :             :                      errmsg("cannot use an existing index in CREATE TABLE"),
    2426                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2427                 :             : 
    2428                 :             :         /* Look for the index in the same schema as the table */
    2429                 :        6669 :         index_oid = get_relname_relid(index_name, RelationGetNamespace(heap_rel));
    2430                 :             : 
    2431         [ -  + ]:        6669 :         if (!OidIsValid(index_oid))
    2432         [ #  # ]:           0 :             ereport(ERROR,
    2433                 :             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    2434                 :             :                      errmsg("index \"%s\" does not exist", index_name),
    2435                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2436                 :             : 
    2437                 :             :         /* Open the index (this will throw an error if it is not an index) */
    2438                 :        6669 :         index_rel = index_open(index_oid, AccessShareLock);
    2439                 :        6669 :         index_form = index_rel->rd_index;
    2440                 :             : 
    2441                 :             :         /* Check that it does not have an associated constraint already */
    2442         [ -  + ]:        6669 :         if (OidIsValid(get_index_constraint(index_oid)))
    2443         [ #  # ]:           0 :             ereport(ERROR,
    2444                 :             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    2445                 :             :                      errmsg("index \"%s\" is already associated with a constraint",
    2446                 :             :                             index_name),
    2447                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2448                 :             : 
    2449                 :             :         /* Perform validity checks on the index */
    2450         [ -  + ]:        6669 :         if (index_form->indrelid != RelationGetRelid(heap_rel))
    2451         [ #  # ]:           0 :             ereport(ERROR,
    2452                 :             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    2453                 :             :                      errmsg("index \"%s\" does not belong to table \"%s\"",
    2454                 :             :                             index_name, RelationGetRelationName(heap_rel)),
    2455                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2456                 :             : 
    2457         [ -  + ]:        6669 :         if (!index_form->indisvalid)
    2458         [ #  # ]:           0 :             ereport(ERROR,
    2459                 :             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    2460                 :             :                      errmsg("index \"%s\" is not valid", index_name),
    2461                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2462                 :             : 
    2463                 :             :         /*
    2464                 :             :          * Today we forbid non-unique indexes, but we could permit GiST
    2465                 :             :          * indexes whose last entry is a range type and use that to create a
    2466                 :             :          * WITHOUT OVERLAPS constraint (i.e. a temporal constraint).
    2467                 :             :          */
    2468         [ +  + ]:        6669 :         if (!index_form->indisunique)
    2469         [ +  - ]:           8 :             ereport(ERROR,
    2470                 :             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2471                 :             :                      errmsg("\"%s\" is not a unique index", index_name),
    2472                 :             :                      errdetail("Cannot create a primary key or unique constraint using such an index."),
    2473                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2474                 :             : 
    2475         [ -  + ]:        6661 :         if (RelationGetIndexExpressions(index_rel) != NIL)
    2476         [ #  # ]:           0 :             ereport(ERROR,
    2477                 :             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2478                 :             :                      errmsg("index \"%s\" contains expressions", index_name),
    2479                 :             :                      errdetail("Cannot create a primary key or unique constraint using such an index."),
    2480                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2481                 :             : 
    2482         [ -  + ]:        6661 :         if (RelationGetIndexPredicate(index_rel) != NIL)
    2483         [ #  # ]:           0 :             ereport(ERROR,
    2484                 :             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2485                 :             :                      errmsg("\"%s\" is a partial index", index_name),
    2486                 :             :                      errdetail("Cannot create a primary key or unique constraint using such an index."),
    2487                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2488                 :             : 
    2489                 :             :         /*
    2490                 :             :          * It's probably unsafe to change a deferred index to non-deferred. (A
    2491                 :             :          * non-constraint index couldn't be deferred anyway, so this case
    2492                 :             :          * should never occur; no need to sweat, but let's check it.)
    2493                 :             :          */
    2494   [ -  +  -  - ]:        6661 :         if (!index_form->indimmediate && !constraint->deferrable)
    2495         [ #  # ]:           0 :             ereport(ERROR,
    2496                 :             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2497                 :             :                      errmsg("\"%s\" is a deferrable index", index_name),
    2498                 :             :                      errdetail("Cannot create a non-deferrable constraint using a deferrable index."),
    2499                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2500                 :             : 
    2501                 :             :         /*
    2502                 :             :          * Insist on it being a btree.  We must have an index that exactly
    2503                 :             :          * matches what you'd get from plain ADD CONSTRAINT syntax, else dump
    2504                 :             :          * and reload will produce a different index (breaking pg_upgrade in
    2505                 :             :          * particular).
    2506                 :             :          */
    2507         [ -  + ]:        6661 :         if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false))
    2508         [ #  # ]:           0 :             ereport(ERROR,
    2509                 :             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2510                 :             :                      errmsg("index \"%s\" is not a btree", index_name),
    2511                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2512                 :             : 
    2513                 :             :         /* Must get indclass the hard way */
    2514                 :        6661 :         indclassDatum = SysCacheGetAttrNotNull(INDEXRELID,
    2515                 :        6661 :                                                index_rel->rd_indextuple,
    2516                 :             :                                                Anum_pg_index_indclass);
    2517                 :        6661 :         indclass = (oidvector *) DatumGetPointer(indclassDatum);
    2518                 :             : 
    2519         [ +  + ]:       17538 :         for (i = 0; i < index_form->indnatts; i++)
    2520                 :             :         {
    2521                 :       10885 :             int16       attnum = index_form->indkey.values[i];
    2522                 :             :             const FormData_pg_attribute *attform;
    2523                 :             :             char       *attname;
    2524                 :             :             Oid         defopclass;
    2525                 :             : 
    2526                 :             :             /*
    2527                 :             :              * We shouldn't see attnum == 0 here, since we already rejected
    2528                 :             :              * expression indexes.  If we do, SystemAttributeDefinition will
    2529                 :             :              * throw an error.
    2530                 :             :              */
    2531         [ +  - ]:       10885 :             if (attnum > 0)
    2532                 :             :             {
    2533                 :             :                 Assert(attnum <= heap_rel->rd_att->natts);
    2534                 :       10885 :                 attform = TupleDescAttr(heap_rel->rd_att, attnum - 1);
    2535                 :             :             }
    2536                 :             :             else
    2537                 :           0 :                 attform = SystemAttributeDefinition(attnum);
    2538                 :       10885 :             attname = pstrdup(NameStr(attform->attname));
    2539                 :             : 
    2540         [ +  + ]:       10885 :             if (i < index_form->indnkeyatts)
    2541                 :             :             {
    2542                 :             :                 /*
    2543                 :             :                  * Insist on default opclass, collation, and sort options.
    2544                 :             :                  * While the index would still work as a constraint with
    2545                 :             :                  * non-default settings, it might not provide exactly the same
    2546                 :             :                  * uniqueness semantics as you'd get from a normally-created
    2547                 :             :                  * constraint; and there's also the dump/reload problem
    2548                 :             :                  * mentioned above.
    2549                 :             :                  */
    2550                 :             :                 Datum       attoptions =
    2551                 :       10865 :                     get_attoptions(RelationGetRelid(index_rel), i + 1);
    2552                 :             : 
    2553                 :       10865 :                 defopclass = GetDefaultOpClass(attform->atttypid,
    2554                 :       10865 :                                                index_rel->rd_rel->relam);
    2555         [ +  - ]:       10865 :                 if (indclass->values[i] != defopclass ||
    2556   [ +  +  +  - ]:       10865 :                     attform->attcollation != index_rel->rd_indcollation[i] ||
    2557                 :       10861 :                     attoptions != (Datum) 0 ||
    2558         [ +  + ]:       10861 :                     index_rel->rd_indoption[i] != 0)
    2559         [ +  - ]:           8 :                     ereport(ERROR,
    2560                 :             :                             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2561                 :             :                              errmsg("index \"%s\" column number %d does not have default sorting behavior", index_name, i + 1),
    2562                 :             :                              errdetail("Cannot create a primary key or unique constraint using such an index."),
    2563                 :             :                              parser_errposition(cxt->pstate, constraint->location)));
    2564                 :             : 
    2565                 :             :                 /* If a PK, ensure the columns get not null constraints */
    2566         [ +  + ]:       10857 :                 if (constraint->contype == CONSTR_PRIMARY)
    2567                 :        4841 :                     cxt->nnconstraints =
    2568                 :        4841 :                         lappend(cxt->nnconstraints,
    2569                 :        4841 :                                 makeNotNullConstraint(makeString(attname)));
    2570                 :             : 
    2571                 :       10857 :                 constraint->keys = lappend(constraint->keys, makeString(attname));
    2572                 :             :             }
    2573                 :             :             else
    2574                 :          20 :                 constraint->including = lappend(constraint->including, makeString(attname));
    2575                 :             :         }
    2576                 :             : 
    2577                 :             :         /* Close the index relation but keep the lock */
    2578                 :        6653 :         index_close(index_rel, NoLock);
    2579                 :             : 
    2580                 :        6653 :         index->indexOid = index_oid;
    2581                 :             :     }
    2582                 :             : 
    2583                 :             :     /*
    2584                 :             :      * If it's an EXCLUDE constraint, the grammar returns a list of pairs of
    2585                 :             :      * IndexElems and operator names.  We have to break that apart into
    2586                 :             :      * separate lists.
    2587                 :             :      */
    2588         [ +  + ]:       12566 :     if (constraint->contype == CONSTR_EXCLUSION)
    2589                 :             :     {
    2590   [ +  -  +  +  :         379 :         foreach(lc, constraint->exclusions)
                   +  + ]
    2591                 :             :         {
    2592                 :         224 :             List       *pair = (List *) lfirst(lc);
    2593                 :             :             IndexElem  *elem;
    2594                 :             :             List       *opname;
    2595                 :             : 
    2596                 :             :             Assert(list_length(pair) == 2);
    2597                 :         224 :             elem = linitial_node(IndexElem, pair);
    2598                 :         224 :             opname = lsecond_node(List, pair);
    2599                 :             : 
    2600                 :         224 :             index->indexParams = lappend(index->indexParams, elem);
    2601                 :         224 :             index->excludeOpNames = lappend(index->excludeOpNames, opname);
    2602                 :             :         }
    2603                 :             :     }
    2604                 :             : 
    2605                 :             :     /*
    2606                 :             :      * For UNIQUE and PRIMARY KEY, we just have a list of column names.
    2607                 :             :      *
    2608                 :             :      * Make sure referenced keys exist.  If we are making a PRIMARY KEY index,
    2609                 :             :      * also make sure they are not-null.  For WITHOUT OVERLAPS constraints, we
    2610                 :             :      * make sure the last part is a range or multirange.
    2611                 :             :      */
    2612                 :             :     else
    2613                 :             :     {
    2614   [ +  -  +  +  :       30151 :         foreach(lc, constraint->keys)
                   +  + ]
    2615                 :             :         {
    2616                 :       17760 :             char       *key = strVal(lfirst(lc));
    2617                 :       17760 :             bool        found = false;
    2618                 :       17760 :             ColumnDef  *column = NULL;
    2619                 :             :             ListCell   *columns;
    2620                 :             :             IndexElem  *iparam;
    2621                 :       17760 :             Oid         typid = InvalidOid;
    2622                 :             : 
    2623                 :             :             /* Make sure referenced column exists. */
    2624   [ +  +  +  +  :       19054 :             foreach(columns, cxt->columns)
                   +  + ]
    2625                 :             :             {
    2626                 :        7074 :                 column = lfirst_node(ColumnDef, columns);
    2627         [ +  + ]:        7074 :                 if (strcmp(column->colname, key) == 0)
    2628                 :             :                 {
    2629                 :        5780 :                     found = true;
    2630                 :        5780 :                     break;
    2631                 :             :                 }
    2632                 :             :             }
    2633         [ +  + ]:       17760 :             if (!found)
    2634                 :       11980 :                 column = NULL;
    2635                 :             : 
    2636         [ +  + ]:       17760 :             if (found)
    2637                 :             :             {
    2638                 :             :                 /*
    2639                 :             :                  * column is defined in the new table.  For CREATE TABLE with
    2640                 :             :                  * a PRIMARY KEY, we can apply the not-null constraint cheaply
    2641                 :             :                  * here.  If the not-null constraint already exists, we can
    2642                 :             :                  * (albeit not so cheaply) verify that it's not a NO INHERIT
    2643                 :             :                  * constraint.
    2644                 :             :                  *
    2645                 :             :                  * Note that ALTER TABLE never needs either check, because
    2646                 :             :                  * those constraints have already been added by
    2647                 :             :                  * ATPrepAddPrimaryKey.
    2648                 :             :                  */
    2649         [ +  + ]:        5780 :                 if (constraint->contype == CONSTR_PRIMARY &&
    2650         [ +  + ]:        5245 :                     !cxt->isalter)
    2651                 :             :                 {
    2652         [ +  + ]:        5226 :                     if (column->is_not_null)
    2653                 :             :                     {
    2654   [ +  -  +  -  :        8439 :                         foreach_node(Constraint, nn, cxt->nnconstraints)
                   +  + ]
    2655                 :             :                         {
    2656         [ +  + ]:        4339 :                             if (strcmp(strVal(linitial(nn->keys)), key) == 0)
    2657                 :             :                             {
    2658         [ +  + ]:        4104 :                                 if (nn->is_no_inherit)
    2659         [ +  - ]:           4 :                                     ereport(ERROR,
    2660                 :             :                                             errcode(ERRCODE_SYNTAX_ERROR),
    2661                 :             :                                             errmsg("conflicting NO INHERIT declaration for not-null constraint on column \"%s\"",
    2662                 :             :                                                    key));
    2663                 :        4100 :                                 break;
    2664                 :             :                             }
    2665                 :             :                         }
    2666                 :             :                     }
    2667                 :             :                     else
    2668                 :             :                     {
    2669                 :        1122 :                         column->is_not_null = true;
    2670                 :        1122 :                         cxt->nnconstraints =
    2671                 :        1122 :                             lappend(cxt->nnconstraints,
    2672                 :        1122 :                                     makeNotNullConstraint(makeString(key)));
    2673                 :             :                     }
    2674                 :             :                 }
    2675                 :          19 :                 else if (constraint->contype == CONSTR_PRIMARY)
    2676                 :             :                     Assert(column->is_not_null);
    2677                 :             :             }
    2678         [ -  + ]:       11980 :             else if (SystemAttributeByName(key) != NULL)
    2679                 :             :             {
    2680                 :             :                 /*
    2681                 :             :                  * column will be a system column in the new table, so accept
    2682                 :             :                  * it. System columns can't ever be null, so no need to worry
    2683                 :             :                  * about PRIMARY/NOT NULL constraint.
    2684                 :             :                  */
    2685                 :           0 :                 found = true;
    2686                 :             :             }
    2687         [ +  + ]:       11980 :             else if (cxt->inhRelations)
    2688                 :             :             {
    2689                 :             :                 /* try inherited tables */
    2690                 :             :                 ListCell   *inher;
    2691                 :             : 
    2692   [ +  -  +  -  :          64 :                 foreach(inher, cxt->inhRelations)
                   +  - ]
    2693                 :             :                 {
    2694                 :          64 :                     RangeVar   *inh = lfirst_node(RangeVar, inher);
    2695                 :             :                     Relation    rel;
    2696                 :             :                     int         count;
    2697                 :             : 
    2698                 :          64 :                     rel = table_openrv(inh, AccessShareLock);
    2699                 :             :                     /* check user requested inheritance from valid relkind */
    2700         [ -  + ]:          64 :                     if (rel->rd_rel->relkind != RELKIND_RELATION &&
    2701         [ #  # ]:           0 :                         rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
    2702         [ #  # ]:           0 :                         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
    2703         [ #  # ]:           0 :                         ereport(ERROR,
    2704                 :             :                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2705                 :             :                                  errmsg("inherited relation \"%s\" is not a table or foreign table",
    2706                 :             :                                         inh->relname)));
    2707         [ +  - ]:          68 :                     for (count = 0; count < rel->rd_att->natts; count++)
    2708                 :             :                     {
    2709                 :          68 :                         Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
    2710                 :             :                                                                   count);
    2711                 :          68 :                         char       *inhname = NameStr(inhattr->attname);
    2712                 :             : 
    2713         [ -  + ]:          68 :                         if (inhattr->attisdropped)
    2714                 :           0 :                             continue;
    2715         [ +  + ]:          68 :                         if (strcmp(key, inhname) == 0)
    2716                 :             :                         {
    2717                 :          64 :                             found = true;
    2718                 :          64 :                             typid = inhattr->atttypid;
    2719                 :             : 
    2720         [ +  + ]:          64 :                             if (constraint->contype == CONSTR_PRIMARY)
    2721                 :          56 :                                 cxt->nnconstraints =
    2722                 :          56 :                                     lappend(cxt->nnconstraints,
    2723                 :          56 :                                             makeNotNullConstraint(makeString(pstrdup(inhname))));
    2724                 :          64 :                             break;
    2725                 :             :                         }
    2726                 :             :                     }
    2727                 :          64 :                     table_close(rel, NoLock);
    2728         [ +  - ]:          64 :                     if (found)
    2729                 :          64 :                         break;
    2730                 :             :                 }
    2731                 :             :             }
    2732                 :             : 
    2733                 :             :             /*
    2734                 :             :              * In the ALTER TABLE case, don't complain about index keys not
    2735                 :             :              * created in the command; they may well exist already.
    2736                 :             :              * DefineIndex will complain about them if not.
    2737                 :             :              */
    2738   [ +  +  +  + ]:       17756 :             if (!found && !cxt->isalter)
    2739         [ +  - ]:           8 :                 ereport(ERROR,
    2740                 :             :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    2741                 :             :                          errmsg("column \"%s\" named in key does not exist", key),
    2742                 :             :                          parser_errposition(cxt->pstate, constraint->location)));
    2743                 :             : 
    2744                 :             :             /* Check for PRIMARY KEY(foo, foo) */
    2745   [ +  +  +  +  :       24761 :             foreach(columns, index->indexParams)
                   +  + ]
    2746                 :             :             {
    2747                 :        7013 :                 iparam = (IndexElem *) lfirst(columns);
    2748   [ +  -  -  + ]:        7013 :                 if (iparam->name && strcmp(key, iparam->name) == 0)
    2749                 :             :                 {
    2750         [ #  # ]:           0 :                     if (index->primary)
    2751         [ #  # ]:           0 :                         ereport(ERROR,
    2752                 :             :                                 (errcode(ERRCODE_DUPLICATE_COLUMN),
    2753                 :             :                                  errmsg("column \"%s\" appears twice in primary key constraint",
    2754                 :             :                                         key),
    2755                 :             :                                  parser_errposition(cxt->pstate, constraint->location)));
    2756                 :             :                     else
    2757         [ #  # ]:           0 :                         ereport(ERROR,
    2758                 :             :                                 (errcode(ERRCODE_DUPLICATE_COLUMN),
    2759                 :             :                                  errmsg("column \"%s\" appears twice in unique constraint",
    2760                 :             :                                         key),
    2761                 :             :                                  parser_errposition(cxt->pstate, constraint->location)));
    2762                 :             :                 }
    2763                 :             :             }
    2764                 :             : 
    2765                 :             :             /*
    2766                 :             :              * The WITHOUT OVERLAPS part (if any) must be a range or
    2767                 :             :              * multirange type, or a domain over such a type.
    2768                 :             :              */
    2769   [ +  +  +  + ]:       17748 :             if (constraint->without_overlaps && lc == list_last_cell(constraint->keys))
    2770                 :             :             {
    2771   [ +  +  +  - ]:         533 :                 if (!found && cxt->isalter)
    2772                 :             :                 {
    2773                 :             :                     /*
    2774                 :             :                      * Look up the column type on existing table. If we can't
    2775                 :             :                      * find it, let things fail in DefineIndex.
    2776                 :             :                      */
    2777                 :         109 :                     Relation    rel = cxt->rel;
    2778                 :             : 
    2779         [ +  - ]:         220 :                     for (int i = 0; i < rel->rd_att->natts; i++)
    2780                 :             :                     {
    2781                 :         220 :                         Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
    2782                 :             :                         const char *attname;
    2783                 :             : 
    2784         [ -  + ]:         220 :                         if (attr->attisdropped)
    2785                 :           0 :                             continue;
    2786                 :         220 :                         attname = NameStr(attr->attname);
    2787         [ +  + ]:         220 :                         if (strcmp(attname, key) == 0)
    2788                 :             :                         {
    2789                 :         109 :                             found = true;
    2790                 :         109 :                             typid = attr->atttypid;
    2791                 :         109 :                             break;
    2792                 :             :                         }
    2793                 :             :                     }
    2794                 :             :                 }
    2795         [ +  - ]:         533 :                 if (found)
    2796                 :             :                 {
    2797                 :             :                     /* Look up column type if we didn't already */
    2798   [ +  +  +  - ]:         533 :                     if (!OidIsValid(typid) && column)
    2799                 :         420 :                         typid = typenameTypeId(cxt->pstate,
    2800                 :         420 :                                                column->typeName);
    2801                 :             :                     /* Look through any domain */
    2802         [ +  - ]:         533 :                     if (OidIsValid(typid))
    2803                 :         533 :                         typid = getBaseType(typid);
    2804                 :             :                     /* Complain if not range/multirange */
    2805         [ +  - ]:         533 :                     if (!OidIsValid(typid) ||
    2806   [ +  +  +  + ]:         533 :                         !(type_is_range(typid) || type_is_multirange(typid)))
    2807         [ +  - ]:           8 :                         ereport(ERROR,
    2808                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    2809                 :             :                                  errmsg("column \"%s\" in WITHOUT OVERLAPS is not a range or multirange type", key),
    2810                 :             :                                  parser_errposition(cxt->pstate, constraint->location)));
    2811                 :             :                 }
    2812                 :             :             }
    2813                 :             : 
    2814                 :             :             /* OK, add it to the index definition */
    2815                 :       17740 :             iparam = makeNode(IndexElem);
    2816                 :       17740 :             iparam->name = pstrdup(key);
    2817                 :       17740 :             iparam->expr = NULL;
    2818                 :       17740 :             iparam->indexcolname = NULL;
    2819                 :       17740 :             iparam->collation = NIL;
    2820                 :       17740 :             iparam->opclass = NIL;
    2821                 :       17740 :             iparam->opclassopts = NIL;
    2822                 :       17740 :             iparam->ordering = SORTBY_DEFAULT;
    2823                 :       17740 :             iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
    2824                 :       17740 :             iparam->location = -1;
    2825                 :       17740 :             index->indexParams = lappend(index->indexParams, iparam);
    2826                 :             :         }
    2827                 :             : 
    2828         [ +  + ]:       12391 :         if (constraint->without_overlaps)
    2829                 :             :         {
    2830                 :             :             /*
    2831                 :             :              * This enforces that there is at least one equality column
    2832                 :             :              * besides the WITHOUT OVERLAPS columns.  This is per SQL
    2833                 :             :              * standard.  XXX Do we need this?
    2834                 :             :              */
    2835         [ +  + ]:         525 :             if (list_length(constraint->keys) < 2)
    2836         [ +  - ]:           8 :                 ereport(ERROR,
    2837                 :             :                         errcode(ERRCODE_SYNTAX_ERROR),
    2838                 :             :                         errmsg("constraint using WITHOUT OVERLAPS needs at least two columns"));
    2839                 :             : 
    2840                 :             :             /* WITHOUT OVERLAPS requires a GiST index */
    2841                 :         517 :             index->accessMethod = "gist";
    2842                 :             :         }
    2843                 :             : 
    2844                 :             :     }
    2845                 :             : 
    2846                 :             :     /*
    2847                 :             :      * Add included columns to index definition.  This is much like the
    2848                 :             :      * simple-column-name-list code above, except that we don't worry about
    2849                 :             :      * NOT NULL marking; included columns in a primary key should not be
    2850                 :             :      * forced NOT NULL.  We don't complain about duplicate columns, either,
    2851                 :             :      * though maybe we should?
    2852                 :             :      */
    2853   [ +  +  +  +  :       12730 :     foreach(lc, constraint->including)
                   +  + ]
    2854                 :             :     {
    2855                 :         192 :         char       *key = strVal(lfirst(lc));
    2856                 :         192 :         bool        found = false;
    2857                 :         192 :         ColumnDef  *column = NULL;
    2858                 :             :         ListCell   *columns;
    2859                 :             :         IndexElem  *iparam;
    2860                 :             : 
    2861   [ +  +  +  -  :         417 :         foreach(columns, cxt->columns)
                   +  + ]
    2862                 :             :         {
    2863                 :         341 :             column = lfirst_node(ColumnDef, columns);
    2864         [ +  + ]:         341 :             if (strcmp(column->colname, key) == 0)
    2865                 :             :             {
    2866                 :         116 :                 found = true;
    2867                 :         116 :                 break;
    2868                 :             :             }
    2869                 :             :         }
    2870                 :             : 
    2871         [ +  + ]:         192 :         if (!found)
    2872                 :             :         {
    2873         [ -  + ]:          76 :             if (SystemAttributeByName(key) != NULL)
    2874                 :             :             {
    2875                 :             :                 /*
    2876                 :             :                  * column will be a system column in the new table, so accept
    2877                 :             :                  * it.
    2878                 :             :                  */
    2879                 :           0 :                 found = true;
    2880                 :             :             }
    2881         [ -  + ]:          76 :             else if (cxt->inhRelations)
    2882                 :             :             {
    2883                 :             :                 /* try inherited tables */
    2884                 :             :                 ListCell   *inher;
    2885                 :             : 
    2886   [ #  #  #  #  :           0 :                 foreach(inher, cxt->inhRelations)
                   #  # ]
    2887                 :             :                 {
    2888                 :           0 :                     RangeVar   *inh = lfirst_node(RangeVar, inher);
    2889                 :             :                     Relation    rel;
    2890                 :             :                     int         count;
    2891                 :             : 
    2892                 :           0 :                     rel = table_openrv(inh, AccessShareLock);
    2893                 :             :                     /* check user requested inheritance from valid relkind */
    2894         [ #  # ]:           0 :                     if (rel->rd_rel->relkind != RELKIND_RELATION &&
    2895         [ #  # ]:           0 :                         rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
    2896         [ #  # ]:           0 :                         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
    2897         [ #  # ]:           0 :                         ereport(ERROR,
    2898                 :             :                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2899                 :             :                                  errmsg("inherited relation \"%s\" is not a table or foreign table",
    2900                 :             :                                         inh->relname)));
    2901         [ #  # ]:           0 :                     for (count = 0; count < rel->rd_att->natts; count++)
    2902                 :             :                     {
    2903                 :           0 :                         Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
    2904                 :             :                                                                   count);
    2905                 :           0 :                         char       *inhname = NameStr(inhattr->attname);
    2906                 :             : 
    2907         [ #  # ]:           0 :                         if (inhattr->attisdropped)
    2908                 :           0 :                             continue;
    2909         [ #  # ]:           0 :                         if (strcmp(key, inhname) == 0)
    2910                 :             :                         {
    2911                 :           0 :                             found = true;
    2912                 :           0 :                             break;
    2913                 :             :                         }
    2914                 :             :                     }
    2915                 :           0 :                     table_close(rel, NoLock);
    2916         [ #  # ]:           0 :                     if (found)
    2917                 :           0 :                         break;
    2918                 :             :                 }
    2919                 :             :             }
    2920                 :             :         }
    2921                 :             : 
    2922                 :             :         /*
    2923                 :             :          * In the ALTER TABLE case, don't complain about index keys not
    2924                 :             :          * created in the command; they may well exist already. DefineIndex
    2925                 :             :          * will complain about them if not.
    2926                 :             :          */
    2927   [ +  +  -  + ]:         192 :         if (!found && !cxt->isalter)
    2928         [ #  # ]:           0 :             ereport(ERROR,
    2929                 :             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    2930                 :             :                      errmsg("column \"%s\" named in key does not exist", key),
    2931                 :             :                      parser_errposition(cxt->pstate, constraint->location)));
    2932                 :             : 
    2933                 :             :         /* OK, add it to the index definition */
    2934                 :         192 :         iparam = makeNode(IndexElem);
    2935                 :         192 :         iparam->name = pstrdup(key);
    2936                 :         192 :         iparam->expr = NULL;
    2937                 :         192 :         iparam->indexcolname = NULL;
    2938                 :         192 :         iparam->collation = NIL;
    2939                 :         192 :         iparam->opclass = NIL;
    2940                 :         192 :         iparam->opclassopts = NIL;
    2941                 :         192 :         iparam->location = -1;
    2942                 :         192 :         index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
    2943                 :             :     }
    2944                 :             : 
    2945                 :       12538 :     return index;
    2946                 :             : }
    2947                 :             : 
    2948                 :             : /*
    2949                 :             :  * transformCheckConstraints
    2950                 :             :  *      handle CHECK constraints
    2951                 :             :  *
    2952                 :             :  * Right now, there's nothing to do here when called from ALTER TABLE,
    2953                 :             :  * but the other constraint-transformation functions are called in both
    2954                 :             :  * the CREATE TABLE and ALTER TABLE paths, so do the same here, and just
    2955                 :             :  * don't do anything if we're not authorized to skip validation.
    2956                 :             :  */
    2957                 :             : static void
    2958                 :       42465 : transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation)
    2959                 :             : {
    2960                 :             :     ListCell   *ckclist;
    2961                 :             : 
    2962         [ +  + ]:       42465 :     if (cxt->ckconstraints == NIL)
    2963                 :       41171 :         return;
    2964                 :             : 
    2965                 :             :     /*
    2966                 :             :      * When creating a new table (but not a foreign table), we can safely skip
    2967                 :             :      * the validation of check constraints and mark them as valid based on the
    2968                 :             :      * constraint enforcement flag, since NOT ENFORCED constraints must always
    2969                 :             :      * be marked as NOT VALID. (This will override any user-supplied NOT VALID
    2970                 :             :      * flag.)
    2971                 :             :      */
    2972         [ +  + ]:        1294 :     if (skipValidation)
    2973                 :             :     {
    2974   [ +  -  +  +  :        1122 :         foreach(ckclist, cxt->ckconstraints)
                   +  + ]
    2975                 :             :         {
    2976                 :         612 :             Constraint *constraint = (Constraint *) lfirst(ckclist);
    2977                 :             : 
    2978                 :         612 :             constraint->skip_validation = true;
    2979                 :         612 :             constraint->initially_valid = constraint->is_enforced;
    2980                 :             :         }
    2981                 :             :     }
    2982                 :             : }
    2983                 :             : 
    2984                 :             : /*
    2985                 :             :  * transformFKConstraints
    2986                 :             :  *      handle FOREIGN KEY constraints
    2987                 :             :  */
    2988                 :             : static void
    2989                 :       42465 : transformFKConstraints(CreateStmtContext *cxt,
    2990                 :             :                        bool skipValidation, bool isAddConstraint)
    2991                 :             : {
    2992                 :             :     ListCell   *fkclist;
    2993                 :             : 
    2994         [ +  + ]:       42465 :     if (cxt->fkconstraints == NIL)
    2995                 :       39663 :         return;
    2996                 :             : 
    2997                 :             :     /*
    2998                 :             :      * If CREATE TABLE or adding a column with NULL default, we can safely
    2999                 :             :      * skip validation of FK constraints, and mark them as valid based on the
    3000                 :             :      * constraint enforcement flag, since NOT ENFORCED constraints must always
    3001                 :             :      * be marked as NOT VALID. (This will override any user-supplied NOT VALID
    3002                 :             :      * flag.)
    3003                 :             :      */
    3004         [ +  + ]:        2802 :     if (skipValidation)
    3005                 :             :     {
    3006   [ +  -  +  +  :        1969 :         foreach(fkclist, cxt->fkconstraints)
                   +  + ]
    3007                 :             :         {
    3008                 :        1025 :             Constraint *constraint = (Constraint *) lfirst(fkclist);
    3009                 :             : 
    3010                 :        1025 :             constraint->skip_validation = true;
    3011                 :        1025 :             constraint->initially_valid = constraint->is_enforced;
    3012                 :             :         }
    3013                 :             :     }
    3014                 :             : 
    3015                 :             :     /*
    3016                 :             :      * For CREATE TABLE or ALTER TABLE ADD COLUMN, gin up an ALTER TABLE ADD
    3017                 :             :      * CONSTRAINT command to execute after the basic command is complete. (If
    3018                 :             :      * called from ADD CONSTRAINT, that routine will add the FK constraints to
    3019                 :             :      * its own subcommand list.)
    3020                 :             :      *
    3021                 :             :      * Note: the ADD CONSTRAINT command must also execute after any index
    3022                 :             :      * creation commands.  Thus, this should run after
    3023                 :             :      * transformIndexConstraints, so that the CREATE INDEX commands are
    3024                 :             :      * already in cxt->alist.  See also the handling of cxt->likeclauses.
    3025                 :             :      */
    3026         [ +  + ]:        2802 :     if (!isAddConstraint)
    3027                 :             :     {
    3028                 :         940 :         AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
    3029                 :             : 
    3030                 :         940 :         alterstmt->relation = cxt->relation;
    3031                 :         940 :         alterstmt->cmds = NIL;
    3032                 :         940 :         alterstmt->objtype = OBJECT_TABLE;
    3033                 :             : 
    3034   [ +  -  +  +  :        1961 :         foreach(fkclist, cxt->fkconstraints)
                   +  + ]
    3035                 :             :         {
    3036                 :        1021 :             Constraint *constraint = (Constraint *) lfirst(fkclist);
    3037                 :        1021 :             AlterTableCmd *altercmd = makeNode(AlterTableCmd);
    3038                 :             : 
    3039                 :        1021 :             altercmd->subtype = AT_AddConstraint;
    3040                 :        1021 :             altercmd->name = NULL;
    3041                 :        1021 :             altercmd->def = (Node *) constraint;
    3042                 :        1021 :             alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
    3043                 :             :         }
    3044                 :             : 
    3045                 :         940 :         cxt->alist = lappend(cxt->alist, alterstmt);
    3046                 :             :     }
    3047                 :             : }
    3048                 :             : 
    3049                 :             : /*
    3050                 :             :  * transformIndexStmt - parse analysis for CREATE INDEX and ALTER TABLE
    3051                 :             :  *
    3052                 :             :  * Note: this is a no-op for an index not using either index expressions or
    3053                 :             :  * a predicate expression.  There are several code paths that create indexes
    3054                 :             :  * without bothering to call this, because they know they don't have any
    3055                 :             :  * such expressions to deal with.
    3056                 :             :  *
    3057                 :             :  * To avoid race conditions, it's important that this function rely only on
    3058                 :             :  * the passed-in relid (and not on stmt->relation) to determine the target
    3059                 :             :  * relation.
    3060                 :             :  */
    3061                 :             : IndexStmt *
    3062                 :       16966 : transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
    3063                 :             : {
    3064                 :             :     ParseState *pstate;
    3065                 :             :     ParseNamespaceItem *nsitem;
    3066                 :             :     ListCell   *l;
    3067                 :             :     Relation    rel;
    3068                 :             : 
    3069                 :             :     /* Nothing to do if statement already transformed. */
    3070         [ +  + ]:       16966 :     if (stmt->transformed)
    3071                 :          86 :         return stmt;
    3072                 :             : 
    3073                 :             :     /* Set up pstate */
    3074                 :       16880 :     pstate = make_parsestate(NULL);
    3075                 :       16880 :     pstate->p_sourcetext = queryString;
    3076                 :             : 
    3077                 :             :     /*
    3078                 :             :      * Put the parent table into the rtable so that the expressions can refer
    3079                 :             :      * to its fields without qualification.  Caller is responsible for locking
    3080                 :             :      * relation, but we still need to open it.
    3081                 :             :      */
    3082                 :       16880 :     rel = relation_open(relid, NoLock);
    3083                 :       16880 :     nsitem = addRangeTableEntryForRelation(pstate, rel,
    3084                 :             :                                            AccessShareLock,
    3085                 :             :                                            NULL, false, true);
    3086                 :             : 
    3087                 :             :     /* no to join list, yes to namespaces */
    3088                 :       16880 :     addNSItemToQuery(pstate, nsitem, false, true, true);
    3089                 :             : 
    3090                 :             :     /* take care of the where clause */
    3091         [ +  + ]:       16880 :     if (stmt->whereClause)
    3092                 :             :     {
    3093                 :         265 :         stmt->whereClause = transformWhereClause(pstate,
    3094                 :             :                                                  stmt->whereClause,
    3095                 :             :                                                  EXPR_KIND_INDEX_PREDICATE,
    3096                 :             :                                                  "WHERE");
    3097                 :             :         /* we have to fix its collations too */
    3098                 :         265 :         assign_expr_collations(pstate, stmt->whereClause);
    3099                 :             :     }
    3100                 :             : 
    3101                 :             :     /* take care of any index expressions */
    3102   [ +  -  +  +  :       40233 :     foreach(l, stmt->indexParams)
                   +  + ]
    3103                 :             :     {
    3104                 :       23377 :         IndexElem  *ielem = (IndexElem *) lfirst(l);
    3105                 :             : 
    3106         [ +  + ]:       23377 :         if (ielem->expr)
    3107                 :             :         {
    3108                 :             :             /* Do parse transformation of the expression */
    3109                 :         813 :             ielem->expr = transformExpr(pstate, ielem->expr,
    3110                 :             :                                         EXPR_KIND_INDEX_EXPRESSION);
    3111                 :             : 
    3112                 :             :             /* We have to fix its collations too */
    3113                 :         789 :             assign_expr_collations(pstate, ielem->expr);
    3114                 :             : 
    3115                 :             :             /*
    3116                 :             :              * transformExpr() should have already rejected subqueries,
    3117                 :             :              * aggregates, window functions, and SRFs, based on the EXPR_KIND_
    3118                 :             :              * for an index expression.
    3119                 :             :              *
    3120                 :             :              * DefineIndex() will make more checks.
    3121                 :             :              */
    3122                 :             :         }
    3123                 :             :     }
    3124                 :             : 
    3125                 :             :     /*
    3126                 :             :      * Check that only the base rel is mentioned.  (This should be dead code
    3127                 :             :      * now that add_missing_from is history.)
    3128                 :             :      */
    3129         [ -  + ]:       16856 :     if (list_length(pstate->p_rtable) != 1)
    3130         [ #  # ]:           0 :         ereport(ERROR,
    3131                 :             :                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
    3132                 :             :                  errmsg("index expressions and predicates can refer only to the table being indexed")));
    3133                 :             : 
    3134                 :       16856 :     free_parsestate(pstate);
    3135                 :             : 
    3136                 :             :     /* Close relation */
    3137                 :       16856 :     table_close(rel, NoLock);
    3138                 :             : 
    3139                 :             :     /* Mark statement as successfully transformed */
    3140                 :       16856 :     stmt->transformed = true;
    3141                 :             : 
    3142                 :       16856 :     return stmt;
    3143                 :             : }
    3144                 :             : 
    3145                 :             : /*
    3146                 :             :  * transformStatsStmt - parse analysis for CREATE STATISTICS
    3147                 :             :  *
    3148                 :             :  * To avoid race conditions, it's important that this function relies only on
    3149                 :             :  * the passed-in relid (and not on stmt->relation) to determine the target
    3150                 :             :  * relation.
    3151                 :             :  */
    3152                 :             : CreateStatsStmt *
    3153                 :         669 : transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
    3154                 :             : {
    3155                 :             :     ParseState *pstate;
    3156                 :             :     ParseNamespaceItem *nsitem;
    3157                 :             :     ListCell   *l;
    3158                 :             :     Relation    rel;
    3159                 :             : 
    3160                 :             :     /* Nothing to do if statement already transformed. */
    3161         [ +  + ]:         669 :     if (stmt->transformed)
    3162                 :          40 :         return stmt;
    3163                 :             : 
    3164                 :             :     /* Set up pstate */
    3165                 :         629 :     pstate = make_parsestate(NULL);
    3166                 :         629 :     pstate->p_sourcetext = queryString;
    3167                 :             : 
    3168                 :             :     /*
    3169                 :             :      * Put the parent table into the rtable so that the expressions can refer
    3170                 :             :      * to its fields without qualification.  Caller is responsible for locking
    3171                 :             :      * relation, but we still need to open it.
    3172                 :             :      */
    3173                 :         629 :     rel = relation_open(relid, NoLock);
    3174                 :         629 :     nsitem = addRangeTableEntryForRelation(pstate, rel,
    3175                 :             :                                            AccessShareLock,
    3176                 :             :                                            NULL, false, true);
    3177                 :             : 
    3178                 :             :     /* no to join list, yes to namespaces */
    3179                 :         629 :     addNSItemToQuery(pstate, nsitem, false, true, true);
    3180                 :             : 
    3181                 :             :     /* take care of any expressions */
    3182   [ +  -  +  +  :        2163 :     foreach(l, stmt->exprs)
                   +  + ]
    3183                 :             :     {
    3184                 :        1534 :         StatsElem  *selem = (StatsElem *) lfirst(l);
    3185                 :             : 
    3186         [ +  + ]:        1534 :         if (selem->expr)
    3187                 :             :         {
    3188                 :             :             /* Now do parse transformation of the expression */
    3189                 :         423 :             selem->expr = transformExpr(pstate, selem->expr,
    3190                 :             :                                         EXPR_KIND_STATS_EXPRESSION);
    3191                 :             : 
    3192                 :             :             /* We have to fix its collations too */
    3193                 :         423 :             assign_expr_collations(pstate, selem->expr);
    3194                 :             :         }
    3195                 :             :     }
    3196                 :             : 
    3197                 :             :     /*
    3198                 :             :      * Check that only the base rel is mentioned.  (This should be dead code
    3199                 :             :      * now that add_missing_from is history.)
    3200                 :             :      */
    3201         [ -  + ]:         629 :     if (list_length(pstate->p_rtable) != 1)
    3202         [ #  # ]:           0 :         ereport(ERROR,
    3203                 :             :                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
    3204                 :             :                  errmsg("statistics expressions can refer only to the table being referenced")));
    3205                 :             : 
    3206                 :         629 :     free_parsestate(pstate);
    3207                 :             : 
    3208                 :             :     /* Close relation */
    3209                 :         629 :     table_close(rel, NoLock);
    3210                 :             : 
    3211                 :             :     /* Mark statement as successfully transformed */
    3212                 :         629 :     stmt->transformed = true;
    3213                 :             : 
    3214                 :         629 :     return stmt;
    3215                 :             : }
    3216                 :             : 
    3217                 :             : 
    3218                 :             : /*
    3219                 :             :  * transformRuleStmt -
    3220                 :             :  *    transform a CREATE RULE Statement. The action is a list of parse
    3221                 :             :  *    trees which is transformed into a list of query trees, and we also
    3222                 :             :  *    transform the WHERE clause if any.
    3223                 :             :  *
    3224                 :             :  * actions and whereClause are output parameters that receive the
    3225                 :             :  * transformed results.
    3226                 :             :  */
    3227                 :             : void
    3228                 :         750 : transformRuleStmt(RuleStmt *stmt, const char *queryString,
    3229                 :             :                   List **actions, Node **whereClause)
    3230                 :             : {
    3231                 :             :     Relation    rel;
    3232                 :             :     ParseState *pstate;
    3233                 :             :     ParseNamespaceItem *oldnsitem;
    3234                 :             :     ParseNamespaceItem *newnsitem;
    3235                 :             : 
    3236                 :             :     /*
    3237                 :             :      * To avoid deadlock, make sure the first thing we do is grab
    3238                 :             :      * AccessExclusiveLock on the target relation.  This will be needed by
    3239                 :             :      * DefineQueryRewrite(), and we don't want to grab a lesser lock
    3240                 :             :      * beforehand.
    3241                 :             :      */
    3242                 :         750 :     rel = table_openrv(stmt->relation, AccessExclusiveLock);
    3243                 :             : 
    3244         [ -  + ]:         750 :     if (rel->rd_rel->relkind == RELKIND_MATVIEW)
    3245         [ #  # ]:           0 :         ereport(ERROR,
    3246                 :             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3247                 :             :                  errmsg("rules on materialized views are not supported")));
    3248                 :             : 
    3249                 :             :     /* Set up pstate */
    3250                 :         750 :     pstate = make_parsestate(NULL);
    3251                 :         750 :     pstate->p_sourcetext = queryString;
    3252                 :             : 
    3253                 :             :     /*
    3254                 :             :      * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to 2.
    3255                 :             :      * Set up their ParseNamespaceItems in the main pstate for use in parsing
    3256                 :             :      * the rule qualification.
    3257                 :             :      */
    3258                 :         750 :     oldnsitem = addRangeTableEntryForRelation(pstate, rel,
    3259                 :             :                                               AccessShareLock,
    3260                 :             :                                               makeAlias("old", NIL),
    3261                 :             :                                               false, false);
    3262                 :         750 :     newnsitem = addRangeTableEntryForRelation(pstate, rel,
    3263                 :             :                                               AccessShareLock,
    3264                 :             :                                               makeAlias("new", NIL),
    3265                 :             :                                               false, false);
    3266                 :             : 
    3267                 :             :     /*
    3268                 :             :      * They must be in the namespace too for lookup purposes, but only add the
    3269                 :             :      * one(s) that are relevant for the current kind of rule.  In an UPDATE
    3270                 :             :      * rule, quals must refer to OLD.field or NEW.field to be unambiguous, but
    3271                 :             :      * there's no need to be so picky for INSERT & DELETE.  We do not add them
    3272                 :             :      * to the joinlist.
    3273                 :             :      */
    3274   [ +  +  +  +  :         750 :     switch (stmt->event)
                      - ]
    3275                 :             :     {
    3276                 :          12 :         case CMD_SELECT:
    3277                 :          12 :             addNSItemToQuery(pstate, oldnsitem, false, true, true);
    3278                 :          12 :             break;
    3279                 :         290 :         case CMD_UPDATE:
    3280                 :         290 :             addNSItemToQuery(pstate, oldnsitem, false, true, true);
    3281                 :         290 :             addNSItemToQuery(pstate, newnsitem, false, true, true);
    3282                 :         290 :             break;
    3283                 :         338 :         case CMD_INSERT:
    3284                 :         338 :             addNSItemToQuery(pstate, newnsitem, false, true, true);
    3285                 :         338 :             break;
    3286                 :         110 :         case CMD_DELETE:
    3287                 :         110 :             addNSItemToQuery(pstate, oldnsitem, false, true, true);
    3288                 :         110 :             break;
    3289                 :           0 :         default:
    3290         [ #  # ]:           0 :             elog(ERROR, "unrecognized event type: %d",
    3291                 :             :                  (int) stmt->event);
    3292                 :             :             break;
    3293                 :             :     }
    3294                 :             : 
    3295                 :             :     /* take care of the where clause */
    3296                 :         750 :     *whereClause = transformWhereClause(pstate,
    3297                 :             :                                         stmt->whereClause,
    3298                 :             :                                         EXPR_KIND_WHERE,
    3299                 :             :                                         "WHERE");
    3300                 :             :     /* we have to fix its collations too */
    3301                 :         750 :     assign_expr_collations(pstate, *whereClause);
    3302                 :             : 
    3303                 :             :     /* this is probably dead code without add_missing_from: */
    3304         [ -  + ]:         750 :     if (list_length(pstate->p_rtable) != 2) /* naughty, naughty... */
    3305         [ #  # ]:           0 :         ereport(ERROR,
    3306                 :             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3307                 :             :                  errmsg("rule WHERE condition cannot contain references to other relations")));
    3308                 :             : 
    3309                 :             :     /*
    3310                 :             :      * 'instead nothing' rules with a qualification need a query rangetable so
    3311                 :             :      * the rewrite handler can add the negated rule qualification to the
    3312                 :             :      * original query. We create a query with the new command type CMD_NOTHING
    3313                 :             :      * here that is treated specially by the rewrite system.
    3314                 :             :      */
    3315         [ +  + ]:         750 :     if (stmt->actions == NIL)
    3316                 :             :     {
    3317                 :         108 :         Query      *nothing_qry = makeNode(Query);
    3318                 :             : 
    3319                 :         108 :         nothing_qry->commandType = CMD_NOTHING;
    3320                 :         108 :         nothing_qry->rtable = pstate->p_rtable;
    3321                 :         108 :         nothing_qry->rteperminfos = pstate->p_rteperminfos;
    3322                 :         108 :         nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
    3323                 :             : 
    3324                 :         108 :         *actions = list_make1(nothing_qry);
    3325                 :             :     }
    3326                 :             :     else
    3327                 :             :     {
    3328                 :             :         ListCell   *l;
    3329                 :         642 :         List       *newactions = NIL;
    3330                 :             : 
    3331                 :             :         /*
    3332                 :             :          * transform each statement, like parse_sub_analyze()
    3333                 :             :          */
    3334   [ +  -  +  +  :        1302 :         foreach(l, stmt->actions)
                   +  + ]
    3335                 :             :         {
    3336                 :         672 :             Node       *action = (Node *) lfirst(l);
    3337                 :         672 :             ParseState *sub_pstate = make_parsestate(NULL);
    3338                 :             :             Query      *sub_qry,
    3339                 :             :                        *top_subqry;
    3340                 :             :             bool        has_old,
    3341                 :             :                         has_new;
    3342                 :             : 
    3343                 :             :             /*
    3344                 :             :              * Since outer ParseState isn't parent of inner, have to pass down
    3345                 :             :              * the query text by hand.
    3346                 :             :              */
    3347                 :         672 :             sub_pstate->p_sourcetext = queryString;
    3348                 :             : 
    3349                 :             :             /*
    3350                 :             :              * Set up OLD/NEW in the rtable for this statement.  The entries
    3351                 :             :              * are added only to relnamespace, not varnamespace, because we
    3352                 :             :              * don't want them to be referred to by unqualified field names
    3353                 :             :              * nor "*" in the rule actions.  We decide later whether to put
    3354                 :             :              * them in the joinlist.
    3355                 :             :              */
    3356                 :         672 :             oldnsitem = addRangeTableEntryForRelation(sub_pstate, rel,
    3357                 :             :                                                       AccessShareLock,
    3358                 :             :                                                       makeAlias("old", NIL),
    3359                 :             :                                                       false, false);
    3360                 :         672 :             newnsitem = addRangeTableEntryForRelation(sub_pstate, rel,
    3361                 :             :                                                       AccessShareLock,
    3362                 :             :                                                       makeAlias("new", NIL),
    3363                 :             :                                                       false, false);
    3364                 :         672 :             addNSItemToQuery(sub_pstate, oldnsitem, false, true, false);
    3365                 :         672 :             addNSItemToQuery(sub_pstate, newnsitem, false, true, false);
    3366                 :             : 
    3367                 :             :             /* Transform the rule action statement */
    3368                 :         672 :             top_subqry = transformStmt(sub_pstate, action);
    3369                 :             : 
    3370                 :             :             /*
    3371                 :             :              * We cannot support utility-statement actions (eg NOTIFY) with
    3372                 :             :              * nonempty rule WHERE conditions, because there's no way to make
    3373                 :             :              * the utility action execute conditionally.
    3374                 :             :              */
    3375         [ +  + ]:         664 :             if (top_subqry->commandType == CMD_UTILITY &&
    3376         [ -  + ]:          26 :                 *whereClause != NULL)
    3377         [ #  # ]:           0 :                 ereport(ERROR,
    3378                 :             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3379                 :             :                          errmsg("rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions")));
    3380                 :             : 
    3381                 :             :             /*
    3382                 :             :              * If the action is INSERT...SELECT, OLD/NEW have been pushed down
    3383                 :             :              * into the SELECT, and that's what we need to look at. (Ugly
    3384                 :             :              * kluge ... try to fix this when we redesign querytrees.)
    3385                 :             :              */
    3386                 :         664 :             sub_qry = getInsertSelectQuery(top_subqry, NULL);
    3387                 :             : 
    3388                 :             :             /*
    3389                 :             :              * If the sub_qry is a setop, we cannot attach any qualifications
    3390                 :             :              * to it, because the planner won't notice them.  This could
    3391                 :             :              * perhaps be relaxed someday, but for now, we may as well reject
    3392                 :             :              * such a rule immediately.
    3393                 :             :              */
    3394   [ -  +  -  - ]:         664 :             if (sub_qry->setOperations != NULL && *whereClause != NULL)
    3395         [ #  # ]:           0 :                 ereport(ERROR,
    3396                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3397                 :             :                          errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
    3398                 :             : 
    3399                 :             :             /*
    3400                 :             :              * Validate action's use of OLD/NEW, qual too
    3401                 :             :              */
    3402                 :         664 :             has_old =
    3403   [ +  +  +  + ]:        1076 :                 rangeTableEntry_used((Node *) sub_qry, PRS2_OLD_VARNO, 0) ||
    3404                 :         412 :                 rangeTableEntry_used(*whereClause, PRS2_OLD_VARNO, 0);
    3405                 :         664 :             has_new =
    3406   [ +  +  +  + ]:         899 :                 rangeTableEntry_used((Node *) sub_qry, PRS2_NEW_VARNO, 0) ||
    3407                 :         235 :                 rangeTableEntry_used(*whereClause, PRS2_NEW_VARNO, 0);
    3408                 :             : 
    3409   [ +  +  +  +  :         664 :             switch (stmt->event)
                      - ]
    3410                 :             :             {
    3411                 :          12 :                 case CMD_SELECT:
    3412         [ -  + ]:          12 :                     if (has_old)
    3413         [ #  # ]:           0 :                         ereport(ERROR,
    3414                 :             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3415                 :             :                                  errmsg("ON SELECT rule cannot use OLD")));
    3416         [ -  + ]:          12 :                     if (has_new)
    3417         [ #  # ]:           0 :                         ereport(ERROR,
    3418                 :             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3419                 :             :                                  errmsg("ON SELECT rule cannot use NEW")));
    3420                 :          12 :                     break;
    3421                 :         232 :                 case CMD_UPDATE:
    3422                 :             :                     /* both are OK */
    3423                 :         232 :                     break;
    3424                 :         307 :                 case CMD_INSERT:
    3425         [ -  + ]:         307 :                     if (has_old)
    3426         [ #  # ]:           0 :                         ereport(ERROR,
    3427                 :             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3428                 :             :                                  errmsg("ON INSERT rule cannot use OLD")));
    3429                 :         307 :                     break;
    3430                 :         113 :                 case CMD_DELETE:
    3431         [ -  + ]:         113 :                     if (has_new)
    3432         [ #  # ]:           0 :                         ereport(ERROR,
    3433                 :             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3434                 :             :                                  errmsg("ON DELETE rule cannot use NEW")));
    3435                 :         113 :                     break;
    3436                 :           0 :                 default:
    3437         [ #  # ]:           0 :                     elog(ERROR, "unrecognized event type: %d",
    3438                 :             :                          (int) stmt->event);
    3439                 :             :                     break;
    3440                 :             :             }
    3441                 :             : 
    3442                 :             :             /*
    3443                 :             :              * OLD/NEW are not allowed in WITH queries, because they would
    3444                 :             :              * amount to outer references for the WITH, which we disallow.
    3445                 :             :              * However, they were already in the outer rangetable when we
    3446                 :             :              * analyzed the query, so we have to check.
    3447                 :             :              *
    3448                 :             :              * Note that in the INSERT...SELECT case, we need to examine the
    3449                 :             :              * CTE lists of both top_subqry and sub_qry.
    3450                 :             :              *
    3451                 :             :              * Note that we aren't digging into the body of the query looking
    3452                 :             :              * for WITHs in nested sub-SELECTs.  A WITH down there can
    3453                 :             :              * legitimately refer to OLD/NEW, because it'd be an
    3454                 :             :              * indirect-correlated outer reference.
    3455                 :             :              */
    3456         [ +  + ]:         664 :             if (rangeTableEntry_used((Node *) top_subqry->cteList,
    3457         [ -  + ]:         660 :                                      PRS2_OLD_VARNO, 0) ||
    3458                 :         660 :                 rangeTableEntry_used((Node *) sub_qry->cteList,
    3459                 :             :                                      PRS2_OLD_VARNO, 0))
    3460         [ +  - ]:           4 :                 ereport(ERROR,
    3461                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3462                 :             :                          errmsg("cannot refer to OLD within WITH query")));
    3463         [ +  - ]:         660 :             if (rangeTableEntry_used((Node *) top_subqry->cteList,
    3464         [ -  + ]:         660 :                                      PRS2_NEW_VARNO, 0) ||
    3465                 :         660 :                 rangeTableEntry_used((Node *) sub_qry->cteList,
    3466                 :             :                                      PRS2_NEW_VARNO, 0))
    3467         [ #  # ]:           0 :                 ereport(ERROR,
    3468                 :             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3469                 :             :                          errmsg("cannot refer to NEW within WITH query")));
    3470                 :             : 
    3471                 :             :             /*
    3472                 :             :              * For efficiency's sake, add OLD to the rule action's jointree
    3473                 :             :              * only if it was actually referenced in the statement or qual.
    3474                 :             :              *
    3475                 :             :              * For INSERT, NEW is not really a relation (only a reference to
    3476                 :             :              * the to-be-inserted tuple) and should never be added to the
    3477                 :             :              * jointree.
    3478                 :             :              *
    3479                 :             :              * For UPDATE, we treat NEW as being another kind of reference to
    3480                 :             :              * OLD, because it represents references to *transformed* tuples
    3481                 :             :              * of the existing relation.  It would be wrong to enter NEW
    3482                 :             :              * separately in the jointree, since that would cause a double
    3483                 :             :              * join of the updated relation.  It's also wrong to fail to make
    3484                 :             :              * a jointree entry if only NEW and not OLD is mentioned.
    3485                 :             :              */
    3486   [ +  +  +  +  :         660 :             if (has_old || (has_new && stmt->event == CMD_UPDATE))
                   +  + ]
    3487                 :             :             {
    3488                 :             :                 RangeTblRef *rtr;
    3489                 :             : 
    3490                 :             :                 /*
    3491                 :             :                  * If sub_qry is a setop, manipulating its jointree will do no
    3492                 :             :                  * good at all, because the jointree is dummy. (This should be
    3493                 :             :                  * a can't-happen case because of prior tests.)
    3494                 :             :                  */
    3495         [ -  + ]:         279 :                 if (sub_qry->setOperations != NULL)
    3496         [ #  # ]:           0 :                     ereport(ERROR,
    3497                 :             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3498                 :             :                              errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
    3499                 :             :                 /* hackishly add OLD to the already-built FROM clause */
    3500                 :         279 :                 rtr = makeNode(RangeTblRef);
    3501                 :         279 :                 rtr->rtindex = oldnsitem->p_rtindex;
    3502                 :         279 :                 sub_qry->jointree->fromlist =
    3503                 :         279 :                     lappend(sub_qry->jointree->fromlist, rtr);
    3504                 :             :             }
    3505                 :             : 
    3506                 :         660 :             newactions = lappend(newactions, top_subqry);
    3507                 :             : 
    3508                 :         660 :             free_parsestate(sub_pstate);
    3509                 :             :         }
    3510                 :             : 
    3511                 :         630 :         *actions = newactions;
    3512                 :             :     }
    3513                 :             : 
    3514                 :         738 :     free_parsestate(pstate);
    3515                 :             : 
    3516                 :             :     /* Close relation, but keep the exclusive lock */
    3517                 :         738 :     table_close(rel, NoLock);
    3518                 :         738 : }
    3519                 :             : 
    3520                 :             : 
    3521                 :             : /*
    3522                 :             :  * checkPartition
    3523                 :             :  * Check whether partRelOid is a leaf partition of the parent table (rel).
    3524                 :             :  * isMerge: true indicates the operation is "ALTER TABLE ... MERGE PARTITIONS";
    3525                 :             :  * false indicates the operation is "ALTER TABLE ... SPLIT PARTITION".
    3526                 :             :  */
    3527                 :             : static void
    3528                 :         673 : checkPartition(Relation rel, Oid partRelOid, bool isMerge)
    3529                 :             : {
    3530                 :             :     Relation    partRel;
    3531                 :             : 
    3532                 :         673 :     partRel = table_open(partRelOid, NoLock);
    3533                 :             : 
    3534         [ +  + ]:         673 :     if (partRel->rd_rel->relkind != RELKIND_RELATION)
    3535   [ +  -  +  - ]:           4 :         ereport(ERROR,
    3536                 :             :                 errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3537                 :             :                 errmsg("\"%s\" is not a table", RelationGetRelationName(partRel)),
    3538                 :             :                 isMerge
    3539                 :             :                 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions that don't have sub-partitions.")
    3540                 :             :                 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions that don't have sub-partitions."));
    3541                 :             : 
    3542         [ +  + ]:         669 :     if (!partRel->rd_rel->relispartition)
    3543   [ +  -  +  - ]:          12 :         ereport(ERROR,
    3544                 :             :                 errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3545                 :             :                 errmsg("\"%s\" is not a partition of partitioned table \"%s\"",
    3546                 :             :                        RelationGetRelationName(partRel), RelationGetRelationName(rel)),
    3547                 :             :                 isMerge
    3548                 :             :                 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions that don't have sub-partitions.")
    3549                 :             :                 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions that don't have sub-partitions."));
    3550                 :             : 
    3551         [ +  + ]:         657 :     if (get_partition_parent(partRelOid, false) != RelationGetRelid(rel))
    3552   [ +  -  +  + ]:          12 :         ereport(ERROR,
    3553                 :             :                 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    3554                 :             :                 errmsg("relation \"%s\" is not a partition of relation \"%s\"",
    3555                 :             :                        RelationGetRelationName(partRel), RelationGetRelationName(rel)),
    3556                 :             :                 isMerge
    3557                 :             :                 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions that don't have sub-partitions.")
    3558                 :             :                 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions that don't have sub-partitions."));
    3559                 :             : 
    3560                 :         645 :     table_close(partRel, NoLock);
    3561                 :         645 : }
    3562                 :             : 
    3563                 :             : /*
    3564                 :             :  * transformPartitionCmdForSplit -
    3565                 :             :  *      analyze the ALTER TABLE ... SPLIT PARTITION command
    3566                 :             :  *
    3567                 :             :  * For each new partition, sps->bound is set to the transformed value of bound.
    3568                 :             :  * Does checks for bounds of new partitions.
    3569                 :             :  */
    3570                 :             : static void
    3571                 :         277 : transformPartitionCmdForSplit(CreateStmtContext *cxt, PartitionCmd *partcmd)
    3572                 :             : {
    3573                 :         277 :     Relation    parent = cxt->rel;
    3574                 :             :     PartitionKey key;
    3575                 :             :     char        strategy;
    3576                 :             :     Oid         splitPartOid;
    3577                 :             :     Oid         defaultPartOid;
    3578                 :         277 :     int         default_index = -1;
    3579                 :             :     bool        isSplitPartDefault;
    3580                 :             :     ListCell   *listptr,
    3581                 :             :                *listptr2;
    3582                 :             :     List       *splitlist;
    3583                 :             : 
    3584                 :         277 :     splitlist = partcmd->partlist;
    3585                 :         277 :     key = RelationGetPartitionKey(parent);
    3586                 :         277 :     strategy = get_partition_strategy(key);
    3587                 :         277 :     defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(parent, true));
    3588                 :             : 
    3589                 :             :     /* Transform partition bounds for all partitions in the list: */
    3590   [ +  -  +  +  :        1312 :     foreach_node(SinglePartitionSpec, sps, splitlist)
                   +  + ]
    3591                 :             :     {
    3592                 :         766 :         cxt->partbound = NULL;
    3593                 :         766 :         transformPartitionCmd(cxt, sps->bound);
    3594                 :             :         /* Assign the transformed value of the partition bound. */
    3595                 :         762 :         sps->bound = cxt->partbound;
    3596                 :             :     }
    3597                 :             : 
    3598                 :             :     /*
    3599                 :             :      * Open and lock the partition, check ownership along the way. We need to
    3600                 :             :      * use AccessExclusiveLock here because this split partition will be
    3601                 :             :      * detached, then dropped in ATExecSplitPartition.
    3602                 :             :      */
    3603                 :         273 :     splitPartOid = RangeVarGetRelidExtended(partcmd->name, AccessExclusiveLock,
    3604                 :             :                                             0, RangeVarCallbackOwnsRelation,
    3605                 :             :                                             NULL);
    3606                 :             : 
    3607                 :         265 :     checkPartition(parent, splitPartOid, false);
    3608                 :             : 
    3609      [ +  +  - ]:         261 :     switch (strategy)
    3610                 :             :     {
    3611                 :         257 :         case PARTITION_STRATEGY_LIST:
    3612                 :             :         case PARTITION_STRATEGY_RANGE:
    3613                 :             :             {
    3614   [ +  -  +  +  :        1232 :                 foreach_node(SinglePartitionSpec, sps, splitlist)
                   +  + ]
    3615                 :             :                 {
    3616         [ +  + ]:         726 :                     if (sps->bound->is_default)
    3617                 :             :                     {
    3618         [ +  + ]:          72 :                         if (default_index != -1)
    3619         [ +  - ]:           4 :                             ereport(ERROR,
    3620                 :             :                                     errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3621                 :             :                                     errmsg("cannot specify more than one DEFAULT partition"),
    3622                 :             :                                     parser_errposition(cxt->pstate, sps->name->location));
    3623                 :             : 
    3624                 :          68 :                         default_index = foreach_current_index(sps);
    3625                 :             :                     }
    3626                 :             :                 }
    3627                 :             :             }
    3628                 :         253 :             break;
    3629                 :             : 
    3630                 :           4 :         case PARTITION_STRATEGY_HASH:
    3631         [ +  - ]:           4 :             ereport(ERROR,
    3632                 :             :                     errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3633                 :             :                     errmsg("partition of hash-partitioned table cannot be split"));
    3634                 :             :             break;
    3635                 :             : 
    3636                 :           0 :         default:
    3637         [ #  # ]:           0 :             elog(ERROR, "unexpected partition strategy: %d",
    3638                 :             :                  (int) key->strategy);
    3639                 :             :             break;
    3640                 :             :     }
    3641                 :             : 
    3642                 :             :     /* isSplitPartDefault: is the being split partition a DEFAULT partition? */
    3643                 :         253 :     isSplitPartDefault = (defaultPartOid == splitPartOid);
    3644                 :             : 
    3645   [ +  +  +  + ]:         253 :     if (isSplitPartDefault && default_index == -1)
    3646         [ +  - ]:           4 :         ereport(ERROR,
    3647                 :             :                 errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3648                 :             :                 errmsg("cannot split DEFAULT partition \"%s\"",
    3649                 :             :                        get_rel_name(splitPartOid)),
    3650                 :             :                 errhint("To split a DEFAULT partition, one of the new partitions must be DEFAULT."));
    3651                 :             : 
    3652                 :             :     /*
    3653                 :             :      * If the partition being split is not the DEFAULT partition, but the
    3654                 :             :      * DEFAULT partition exists, then none of the resulting split partitions
    3655                 :             :      * can be the DEFAULT.
    3656                 :             :      */
    3657   [ +  +  +  +  :         249 :     if (!isSplitPartDefault && (default_index != -1) && OidIsValid(defaultPartOid))
                   +  + ]
    3658                 :             :     {
    3659                 :             :         SinglePartitionSpec *spsDef =
    3660                 :           4 :             (SinglePartitionSpec *) list_nth(splitlist, default_index);
    3661                 :             : 
    3662         [ +  - ]:           4 :         ereport(ERROR,
    3663                 :             :                 errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3664                 :             :                 errmsg("cannot split non-DEFAULT partition \"%s\"",
    3665                 :             :                        get_rel_name(splitPartOid)),
    3666                 :             :                 errdetail("New partition cannot be DEFAULT because DEFAULT partition \"%s\" already exists.",
    3667                 :             :                           get_rel_name(defaultPartOid)),
    3668                 :             :                 parser_errposition(cxt->pstate, spsDef->name->location));
    3669                 :             :     }
    3670                 :             : 
    3671   [ +  -  +  +  :         887 :     foreach(listptr, splitlist)
                   +  + ]
    3672                 :             :     {
    3673                 :             :         Oid         nspid;
    3674                 :         654 :         SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
    3675                 :         654 :         RangeVar   *name = sps->name;
    3676                 :             : 
    3677                 :         654 :         nspid = RangeVarGetCreationNamespace(sps->name);
    3678                 :             : 
    3679                 :             :         /* Partitions in the list should have different names. */
    3680   [ +  -  +  +  :        1291 :         for_each_cell(listptr2, splitlist, lnext(splitlist, listptr))
                   +  + ]
    3681                 :             :         {
    3682                 :             :             Oid         nspid2;
    3683                 :         649 :             SinglePartitionSpec *sps2 = (SinglePartitionSpec *) lfirst(listptr2);
    3684                 :         649 :             RangeVar   *name2 = sps2->name;
    3685                 :             : 
    3686         [ +  + ]:         649 :             if (equal(name, name2))
    3687         [ +  - ]:           8 :                 ereport(ERROR,
    3688                 :             :                         errcode(ERRCODE_DUPLICATE_TABLE),
    3689                 :             :                         errmsg("partition with name \"%s\" is already used", name->relname),
    3690                 :             :                         parser_errposition(cxt->pstate, name2->location));
    3691                 :             : 
    3692                 :         641 :             nspid2 = RangeVarGetCreationNamespace(sps2->name);
    3693                 :             : 
    3694   [ +  +  +  + ]:         641 :             if (nspid2 == nspid && strcmp(name->relname, name2->relname) == 0)
    3695         [ +  - ]:           4 :                 ereport(ERROR,
    3696                 :             :                         errcode(ERRCODE_DUPLICATE_TABLE),
    3697                 :             :                         errmsg("partition with name \"%s\" is already used", name->relname),
    3698                 :             :                         parser_errposition(cxt->pstate, name2->location));
    3699                 :             :         }
    3700                 :             :     }
    3701                 :             : 
    3702                 :             :     /* Then we should check partitions with transformed bounds. */
    3703                 :         233 :     check_partitions_for_split(parent, splitPartOid, splitlist, cxt->pstate);
    3704                 :         153 : }
    3705                 :             : 
    3706                 :             : 
    3707                 :             : /*
    3708                 :             :  * transformPartitionCmdForMerge -
    3709                 :             :  *      analyze the ALTER TABLE ... MERGE PARTITIONS command
    3710                 :             :  *
    3711                 :             :  * Does simple checks for merged partitions. Calculates bound of the resulting
    3712                 :             :  * partition.
    3713                 :             :  */
    3714                 :             : static void
    3715                 :         196 : transformPartitionCmdForMerge(CreateStmtContext *cxt, PartitionCmd *partcmd)
    3716                 :             : {
    3717                 :             :     Oid         defaultPartOid;
    3718                 :             :     Oid         partOid;
    3719                 :         196 :     Relation    parent = cxt->rel;
    3720                 :             :     PartitionKey key;
    3721                 :             :     char        strategy;
    3722                 :             :     ListCell   *listptr,
    3723                 :             :                *listptr2;
    3724                 :         196 :     bool        isDefaultPart = false;
    3725                 :         196 :     List       *partOids = NIL;
    3726                 :             : 
    3727                 :         196 :     key = RelationGetPartitionKey(parent);
    3728                 :         196 :     strategy = get_partition_strategy(key);
    3729                 :             : 
    3730         [ +  + ]:         196 :     if (strategy == PARTITION_STRATEGY_HASH)
    3731         [ +  - ]:           4 :         ereport(ERROR,
    3732                 :             :                 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3733                 :             :                 errmsg("partition of hash-partitioned table cannot be merged"));
    3734                 :             : 
    3735                 :             :     /* Does the partitioned table (parent) have a default partition? */
    3736                 :         192 :     defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(parent, true));
    3737                 :             : 
    3738   [ +  -  +  +  :         576 :     foreach(listptr, partcmd->partlist)
                   +  + ]
    3739                 :             :     {
    3740                 :         424 :         RangeVar   *name = (RangeVar *) lfirst(listptr);
    3741                 :             : 
    3742                 :             :         /* Partitions in the list should have different names. */
    3743   [ +  -  +  +  :         728 :         for_each_cell(listptr2, partcmd->partlist, lnext(partcmd->partlist, listptr))
                   +  + ]
    3744                 :             :         {
    3745                 :         308 :             RangeVar   *name2 = (RangeVar *) lfirst(listptr2);
    3746                 :             : 
    3747         [ +  + ]:         308 :             if (equal(name, name2))
    3748         [ +  - ]:           4 :                 ereport(ERROR,
    3749                 :             :                         errcode(ERRCODE_DUPLICATE_TABLE),
    3750                 :             :                         errmsg("partition with name \"%s\" is already used", name->relname),
    3751                 :             :                         parser_errposition(cxt->pstate, name2->location));
    3752                 :             :         }
    3753                 :             : 
    3754                 :             :         /*
    3755                 :             :          * Search the DEFAULT partition in the list. Open and lock partitions
    3756                 :             :          * before calculating the boundary for resulting partition, we also
    3757                 :             :          * check for ownership along the way.  We need to use
    3758                 :             :          * AccessExclusiveLock here, because these merged partitions will be
    3759                 :             :          * detached and then dropped in ATExecMergePartitions.
    3760                 :             :          */
    3761                 :         420 :         partOid = RangeVarGetRelidExtended(name, AccessExclusiveLock, 0,
    3762                 :             :                                            RangeVarCallbackOwnsRelation,
    3763                 :             :                                            NULL);
    3764                 :             :         /* Is the current partition a DEFAULT partition? */
    3765         [ +  + ]:         412 :         if (partOid == defaultPartOid)
    3766                 :           8 :             isDefaultPart = true;
    3767                 :             : 
    3768                 :             :         /*
    3769                 :             :          * Extended check because the same partition can have different names
    3770                 :             :          * (for example, "part_name" and "public.part_name").
    3771                 :             :          */
    3772   [ +  +  +  +  :         684 :         foreach(listptr2, partOids)
                   +  + ]
    3773                 :             :         {
    3774                 :         276 :             Oid         curOid = lfirst_oid(listptr2);
    3775                 :             : 
    3776         [ +  + ]:         276 :             if (curOid == partOid)
    3777         [ +  - ]:           4 :                 ereport(ERROR,
    3778                 :             :                         errcode(ERRCODE_DUPLICATE_TABLE),
    3779                 :             :                         errmsg("partition with name \"%s\" is already used", name->relname),
    3780                 :             :                         parser_errposition(cxt->pstate, name->location));
    3781                 :             :         }
    3782                 :             : 
    3783                 :         408 :         checkPartition(parent, partOid, true);
    3784                 :             : 
    3785                 :         384 :         partOids = lappend_oid(partOids, partOid);
    3786                 :             :     }
    3787                 :             : 
    3788                 :             :     /* Allocate the bound of the resulting partition. */
    3789                 :             :     Assert(partcmd->bound == NULL);
    3790                 :         152 :     partcmd->bound = makeNode(PartitionBoundSpec);
    3791                 :             : 
    3792                 :             :     /* Fill the partition bound. */
    3793                 :         152 :     partcmd->bound->strategy = strategy;
    3794                 :         152 :     partcmd->bound->location = -1;
    3795                 :         152 :     partcmd->bound->is_default = isDefaultPart;
    3796         [ +  + ]:         152 :     if (!isDefaultPart)
    3797                 :         144 :         calculate_partition_bound_for_merge(parent, partcmd->partlist,
    3798                 :             :                                             partOids, partcmd->bound,
    3799                 :             :                                             cxt->pstate);
    3800                 :         144 : }
    3801                 :             : 
    3802                 :             : /*
    3803                 :             :  * transformAlterTableStmt -
    3804                 :             :  *      parse analysis for ALTER TABLE
    3805                 :             :  *
    3806                 :             :  * Returns the transformed AlterTableStmt.  There may be additional actions
    3807                 :             :  * to be done before and after the transformed statement, which are returned
    3808                 :             :  * in *beforeStmts and *afterStmts as lists of utility command parsetrees.
    3809                 :             :  *
    3810                 :             :  * To avoid race conditions, it's important that this function rely only on
    3811                 :             :  * the passed-in relid (and not on stmt->relation) to determine the target
    3812                 :             :  * relation.
    3813                 :             :  */
    3814                 :             : AlterTableStmt *
    3815                 :       16142 : transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
    3816                 :             :                         const char *queryString,
    3817                 :             :                         List **beforeStmts, List **afterStmts)
    3818                 :             : {
    3819                 :             :     Relation    rel;
    3820                 :             :     TupleDesc   tupdesc;
    3821                 :             :     ParseState *pstate;
    3822                 :             :     CreateStmtContext cxt;
    3823                 :             :     List       *save_alist;
    3824                 :             :     ListCell   *lcmd,
    3825                 :             :                *l;
    3826                 :       16142 :     List       *newcmds = NIL;
    3827                 :       16142 :     bool        skipValidation = true;
    3828                 :             :     AlterTableCmd *newcmd;
    3829                 :             :     ParseNamespaceItem *nsitem;
    3830                 :             : 
    3831                 :             :     /* Caller is responsible for locking the relation */
    3832                 :       16142 :     rel = relation_open(relid, NoLock);
    3833                 :       16142 :     tupdesc = RelationGetDescr(rel);
    3834                 :             : 
    3835                 :             :     /* Set up pstate */
    3836                 :       16142 :     pstate = make_parsestate(NULL);
    3837                 :       16142 :     pstate->p_sourcetext = queryString;
    3838                 :       16142 :     nsitem = addRangeTableEntryForRelation(pstate,
    3839                 :             :                                            rel,
    3840                 :             :                                            AccessShareLock,
    3841                 :             :                                            NULL,
    3842                 :             :                                            false,
    3843                 :             :                                            true);
    3844                 :       16142 :     addNSItemToQuery(pstate, nsitem, false, true, true);
    3845                 :             : 
    3846                 :             :     /* Set up CreateStmtContext */
    3847                 :       16142 :     cxt.pstate = pstate;
    3848         [ +  + ]:       16142 :     if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
    3849                 :             :     {
    3850                 :         120 :         cxt.stmtType = "ALTER FOREIGN TABLE";
    3851                 :         120 :         cxt.isforeign = true;
    3852                 :             :     }
    3853                 :             :     else
    3854                 :             :     {
    3855                 :       16022 :         cxt.stmtType = "ALTER TABLE";
    3856                 :       16022 :         cxt.isforeign = false;
    3857                 :             :     }
    3858                 :       16142 :     cxt.relation = stmt->relation;
    3859                 :       16142 :     cxt.rel = rel;
    3860                 :       16142 :     cxt.inhRelations = NIL;
    3861                 :       16142 :     cxt.isalter = true;
    3862                 :       16142 :     cxt.columns = NIL;
    3863                 :       16142 :     cxt.ckconstraints = NIL;
    3864                 :       16142 :     cxt.nnconstraints = NIL;
    3865                 :       16142 :     cxt.fkconstraints = NIL;
    3866                 :       16142 :     cxt.ixconstraints = NIL;
    3867                 :       16142 :     cxt.likeclauses = NIL;
    3868                 :       16142 :     cxt.blist = NIL;
    3869                 :       16142 :     cxt.alist = NIL;
    3870                 :       16142 :     cxt.pkey = NULL;
    3871                 :       16142 :     cxt.ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    3872                 :       16142 :     cxt.partbound = NULL;
    3873                 :       16142 :     cxt.ofType = false;
    3874                 :             : 
    3875                 :             :     /*
    3876                 :             :      * Transform ALTER subcommands that need it (most don't).  These largely
    3877                 :             :      * re-use code from CREATE TABLE.
    3878                 :             :      */
    3879   [ +  -  +  +  :       32068 :     foreach(lcmd, stmt->cmds)
                   +  + ]
    3880                 :             :     {
    3881                 :       16142 :         AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
    3882                 :             : 
    3883   [ +  +  +  +  :       16142 :         switch (cmd->subtype)
             +  +  +  +  
                      - ]
    3884                 :             :         {
    3885                 :        1505 :             case AT_AddColumn:
    3886                 :             :                 {
    3887                 :        1505 :                     ColumnDef  *def = castNode(ColumnDef, cmd->def);
    3888                 :             : 
    3889                 :        1505 :                     transformColumnDefinition(&cxt, def);
    3890                 :             : 
    3891                 :             :                     /*
    3892                 :             :                      * If the column has a non-null default, we can't skip
    3893                 :             :                      * validation of foreign keys.
    3894                 :             :                      */
    3895         [ +  + ]:        1501 :                     if (def->raw_default != NULL)
    3896                 :         674 :                         skipValidation = false;
    3897                 :             : 
    3898                 :             :                     /*
    3899                 :             :                      * All constraints are processed in other ways. Remove the
    3900                 :             :                      * original list
    3901                 :             :                      */
    3902                 :        1501 :                     def->constraints = NIL;
    3903                 :             : 
    3904                 :        1501 :                     newcmds = lappend(newcmds, cmd);
    3905                 :        1501 :                     break;
    3906                 :             :                 }
    3907                 :             : 
    3908                 :       10787 :             case AT_AddConstraint:
    3909                 :             : 
    3910                 :             :                 /*
    3911                 :             :                  * The original AddConstraint cmd node doesn't go to newcmds
    3912                 :             :                  */
    3913         [ +  - ]:       10787 :                 if (IsA(cmd->def, Constraint))
    3914                 :             :                 {
    3915                 :       10787 :                     transformTableConstraint(&cxt, (Constraint *) cmd->def);
    3916         [ +  + ]:       10783 :                     if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN)
    3917                 :        1858 :                         skipValidation = false;
    3918                 :             :                 }
    3919                 :             :                 else
    3920         [ #  # ]:           0 :                     elog(ERROR, "unrecognized node type: %d",
    3921                 :             :                          (int) nodeTag(cmd->def));
    3922                 :       10783 :                 break;
    3923                 :             : 
    3924                 :         951 :             case AT_AlterColumnType:
    3925                 :             :                 {
    3926                 :         951 :                     ColumnDef  *def = castNode(ColumnDef, cmd->def);
    3927                 :             :                     AttrNumber  attnum;
    3928                 :             : 
    3929                 :             :                     /*
    3930                 :             :                      * For ALTER COLUMN TYPE, transform the USING clause if
    3931                 :             :                      * one was specified.
    3932                 :             :                      */
    3933         [ +  + ]:         951 :                     if (def->raw_default)
    3934                 :             :                     {
    3935                 :         167 :                         def->cooked_default =
    3936                 :         167 :                             transformExpr(pstate, def->raw_default,
    3937                 :             :                                           EXPR_KIND_ALTER_COL_TRANSFORM);
    3938                 :             :                     }
    3939                 :             : 
    3940                 :             :                     /*
    3941                 :             :                      * For identity column, create ALTER SEQUENCE command to
    3942                 :             :                      * change the data type of the sequence. Identity sequence
    3943                 :             :                      * is associated with the top level partitioned table.
    3944                 :             :                      * Hence ignore partitions.
    3945                 :             :                      */
    3946         [ +  + ]:         951 :                     if (!RelationGetForm(rel)->relispartition)
    3947                 :             :                     {
    3948                 :         883 :                         attnum = get_attnum(relid, cmd->name);
    3949         [ -  + ]:         883 :                         if (attnum == InvalidAttrNumber)
    3950         [ #  # ]:           0 :                             ereport(ERROR,
    3951                 :             :                                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    3952                 :             :                                      errmsg("column \"%s\" of relation \"%s\" does not exist",
    3953                 :             :                                             cmd->name, RelationGetRelationName(rel))));
    3954                 :             : 
    3955         [ +  + ]:         883 :                         if (attnum > 0 &&
    3956         [ +  + ]:         879 :                             TupleDescAttr(tupdesc, attnum - 1)->attidentity)
    3957                 :             :                         {
    3958                 :          24 :                             Oid         seq_relid = getIdentitySequence(rel, attnum, false);
    3959                 :          24 :                             Oid         typeOid = typenameTypeId(pstate, def->typeName);
    3960                 :          24 :                             AlterSeqStmt *altseqstmt = makeNode(AlterSeqStmt);
    3961                 :             : 
    3962                 :             :                             altseqstmt->sequence
    3963                 :          24 :                                 = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
    3964                 :             :                                                get_rel_name(seq_relid),
    3965                 :             :                                                -1);
    3966                 :          24 :                             altseqstmt->options = list_make1(makeDefElem("as",
    3967                 :             :                                                                          (Node *) makeTypeNameFromOid(typeOid, -1),
    3968                 :             :                                                                          -1));
    3969                 :          24 :                             altseqstmt->for_identity = true;
    3970                 :          24 :                             cxt.blist = lappend(cxt.blist, altseqstmt);
    3971                 :             :                         }
    3972                 :             :                     }
    3973                 :             : 
    3974                 :         951 :                     newcmds = lappend(newcmds, cmd);
    3975                 :         951 :                     break;
    3976                 :             :                 }
    3977                 :             : 
    3978                 :         107 :             case AT_AddIdentity:
    3979                 :             :                 {
    3980                 :         107 :                     Constraint *def = castNode(Constraint, cmd->def);
    3981                 :         107 :                     ColumnDef  *newdef = makeNode(ColumnDef);
    3982                 :             :                     AttrNumber  attnum;
    3983                 :             : 
    3984                 :         107 :                     newdef->colname = cmd->name;
    3985                 :         107 :                     newdef->identity = def->generated_when;
    3986                 :         107 :                     cmd->def = (Node *) newdef;
    3987                 :             : 
    3988                 :         107 :                     attnum = get_attnum(relid, cmd->name);
    3989         [ +  + ]:         107 :                     if (attnum == InvalidAttrNumber)
    3990         [ +  - ]:           4 :                         ereport(ERROR,
    3991                 :             :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    3992                 :             :                                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    3993                 :             :                                         cmd->name, RelationGetRelationName(rel))));
    3994                 :             : 
    3995                 :         103 :                     generateSerialExtraStmts(&cxt, newdef,
    3996                 :             :                                              get_atttype(relid, attnum),
    3997                 :             :                                              def->options, true, true,
    3998                 :             :                                              NULL, NULL);
    3999                 :             : 
    4000                 :         103 :                     newcmds = lappend(newcmds, cmd);
    4001                 :         103 :                     break;
    4002                 :             :                 }
    4003                 :             : 
    4004                 :          41 :             case AT_SetIdentity:
    4005                 :             :                 {
    4006                 :             :                     /*
    4007                 :             :                      * Create an ALTER SEQUENCE statement for the internal
    4008                 :             :                      * sequence of the identity column.
    4009                 :             :                      */
    4010                 :             :                     ListCell   *lc;
    4011                 :          41 :                     List       *newseqopts = NIL;
    4012                 :          41 :                     List       *newdef = NIL;
    4013                 :             :                     AttrNumber  attnum;
    4014                 :             :                     Oid         seq_relid;
    4015                 :             : 
    4016                 :             :                     /*
    4017                 :             :                      * Split options into those handled by ALTER SEQUENCE and
    4018                 :             :                      * those for ALTER TABLE proper.
    4019                 :             :                      */
    4020   [ +  -  +  +  :         122 :                     foreach(lc, castNode(List, cmd->def))
                   +  + ]
    4021                 :             :                     {
    4022                 :          81 :                         DefElem    *def = lfirst_node(DefElem, lc);
    4023                 :             : 
    4024         [ +  + ]:          81 :                         if (strcmp(def->defname, "generated") == 0)
    4025                 :          29 :                             newdef = lappend(newdef, def);
    4026                 :             :                         else
    4027                 :          52 :                             newseqopts = lappend(newseqopts, def);
    4028                 :             :                     }
    4029                 :             : 
    4030                 :          41 :                     attnum = get_attnum(relid, cmd->name);
    4031         [ -  + ]:          41 :                     if (attnum == InvalidAttrNumber)
    4032         [ #  # ]:           0 :                         ereport(ERROR,
    4033                 :             :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    4034                 :             :                                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    4035                 :             :                                         cmd->name, RelationGetRelationName(rel))));
    4036                 :             : 
    4037                 :          41 :                     seq_relid = getIdentitySequence(rel, attnum, true);
    4038                 :             : 
    4039         [ +  + ]:          41 :                     if (seq_relid)
    4040                 :             :                     {
    4041                 :             :                         AlterSeqStmt *seqstmt;
    4042                 :             : 
    4043                 :          33 :                         seqstmt = makeNode(AlterSeqStmt);
    4044                 :          33 :                         seqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
    4045                 :             :                                                          get_rel_name(seq_relid), -1);
    4046                 :          33 :                         seqstmt->options = newseqopts;
    4047                 :          33 :                         seqstmt->for_identity = true;
    4048                 :          33 :                         seqstmt->missing_ok = false;
    4049                 :             : 
    4050                 :          33 :                         cxt.blist = lappend(cxt.blist, seqstmt);
    4051                 :             :                     }
    4052                 :             : 
    4053                 :             :                     /*
    4054                 :             :                      * If column was not an identity column, we just let the
    4055                 :             :                      * ALTER TABLE command error out later.  (There are cases
    4056                 :             :                      * this fails to cover, but we'll need to restructure
    4057                 :             :                      * where creation of the sequence dependency linkage
    4058                 :             :                      * happens before we can fix it.)
    4059                 :             :                      */
    4060                 :             : 
    4061                 :          41 :                     cmd->def = (Node *) newdef;
    4062                 :          41 :                     newcmds = lappend(newcmds, cmd);
    4063                 :          41 :                     break;
    4064                 :             :                 }
    4065                 :             : 
    4066                 :        2266 :             case AT_AttachPartition:
    4067                 :             :             case AT_DetachPartition:
    4068                 :             :                 {
    4069                 :        2266 :                     PartitionCmd *partcmd = (PartitionCmd *) cmd->def;
    4070                 :             : 
    4071                 :        2266 :                     transformPartitionCmd(&cxt, partcmd->bound);
    4072                 :             :                     /* assign the transformed value of the partition bound */
    4073                 :        2250 :                     partcmd->bound = cxt.partbound;
    4074                 :             :                 }
    4075                 :             : 
    4076                 :        2250 :                 newcmds = lappend(newcmds, cmd);
    4077                 :        2250 :                 break;
    4078                 :             : 
    4079                 :         200 :             case AT_MergePartitions:
    4080                 :             :                 {
    4081                 :         200 :                     PartitionCmd *partcmd = (PartitionCmd *) cmd->def;
    4082                 :             : 
    4083         [ +  + ]:         200 :                     if (list_length(partcmd->partlist) < 2)
    4084         [ +  - ]:           4 :                         ereport(ERROR,
    4085                 :             :                                 errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    4086                 :             :                                 errmsg("list of partitions to be merged should include at least two partitions"));
    4087                 :             : 
    4088                 :         196 :                     transformPartitionCmdForMerge(&cxt, partcmd);
    4089                 :         144 :                     newcmds = lappend(newcmds, cmd);
    4090                 :         144 :                     break;
    4091                 :             :                 }
    4092                 :             : 
    4093                 :         285 :             case AT_SplitPartition:
    4094                 :             :                 {
    4095                 :         285 :                     PartitionCmd *partcmd = (PartitionCmd *) cmd->def;
    4096                 :             : 
    4097         [ +  + ]:         285 :                     if (list_length(partcmd->partlist) < 2)
    4098         [ +  - ]:           8 :                         ereport(ERROR,
    4099                 :             :                                 errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    4100                 :             :                                 errmsg("list of new partitions should contain at least two partitions"));
    4101                 :             : 
    4102                 :         277 :                     transformPartitionCmdForSplit(&cxt, partcmd);
    4103                 :         153 :                     newcmds = lappend(newcmds, cmd);
    4104                 :         153 :                     break;
    4105                 :             :                 }
    4106                 :             : 
    4107                 :           0 :             default:
    4108                 :             : 
    4109                 :             :                 /*
    4110                 :             :                  * Currently, we shouldn't actually get here for the
    4111                 :             :                  * subcommand types that don't require transformation; but if
    4112                 :             :                  * we do, just emit them unchanged.
    4113                 :             :                  */
    4114                 :           0 :                 newcmds = lappend(newcmds, cmd);
    4115                 :           0 :                 break;
    4116                 :             :         }
    4117                 :             :     }
    4118                 :             : 
    4119                 :             :     /*
    4120                 :             :      * Transfer anything we already have in cxt.alist into save_alist, to keep
    4121                 :             :      * it separate from the output of transformIndexConstraints.
    4122                 :             :      */
    4123                 :       15926 :     save_alist = cxt.alist;
    4124                 :       15926 :     cxt.alist = NIL;
    4125                 :             : 
    4126                 :             :     /* Postprocess constraints */
    4127                 :       15926 :     transformIndexConstraints(&cxt);
    4128                 :       15910 :     transformFKConstraints(&cxt, skipValidation, true);
    4129                 :       15910 :     transformCheckConstraints(&cxt, false);
    4130                 :             : 
    4131                 :             :     /*
    4132                 :             :      * Push any index-creation commands into the ALTER, so that they can be
    4133                 :             :      * scheduled nicely by tablecmds.c.  Note that tablecmds.c assumes that
    4134                 :             :      * the IndexStmt attached to an AT_AddIndex or AT_AddIndexConstraint
    4135                 :             :      * subcommand has already been through transformIndexStmt.
    4136                 :             :      */
    4137   [ +  +  +  +  :       23483 :     foreach(l, cxt.alist)
                   +  + ]
    4138                 :             :     {
    4139                 :        7573 :         Node       *istmt = (Node *) lfirst(l);
    4140                 :             : 
    4141                 :             :         /*
    4142                 :             :          * We assume here that cxt.alist contains only IndexStmts generated
    4143                 :             :          * from primary key constraints.
    4144                 :             :          */
    4145         [ +  - ]:        7573 :         if (IsA(istmt, IndexStmt))
    4146                 :             :         {
    4147                 :        7573 :             IndexStmt  *idxstmt = (IndexStmt *) istmt;
    4148                 :             : 
    4149                 :        7573 :             idxstmt = transformIndexStmt(relid, idxstmt, queryString);
    4150                 :        7573 :             newcmd = makeNode(AlterTableCmd);
    4151         [ +  + ]:        7573 :             newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex;
    4152                 :        7573 :             newcmd->def = (Node *) idxstmt;
    4153                 :        7573 :             newcmds = lappend(newcmds, newcmd);
    4154                 :             :         }
    4155                 :             :         else
    4156         [ #  # ]:           0 :             elog(ERROR, "unexpected stmt type %d", (int) nodeTag(istmt));
    4157                 :             :     }
    4158                 :       15910 :     cxt.alist = NIL;
    4159                 :             : 
    4160                 :             :     /* Append any CHECK, NOT NULL or FK constraints to the commands list */
    4161   [ +  +  +  +  :       32592 :     foreach_node(Constraint, def, cxt.ckconstraints)
                   +  + ]
    4162                 :             :     {
    4163                 :         772 :         newcmd = makeNode(AlterTableCmd);
    4164                 :         772 :         newcmd->subtype = AT_AddConstraint;
    4165                 :         772 :         newcmd->def = (Node *) def;
    4166                 :         772 :         newcmds = lappend(newcmds, newcmd);
    4167                 :             :     }
    4168   [ +  +  +  +  :       37533 :     foreach_node(Constraint, def, cxt.nnconstraints)
                   +  + ]
    4169                 :             :     {
    4170                 :        5713 :         newcmd = makeNode(AlterTableCmd);
    4171                 :        5713 :         newcmd->subtype = AT_AddConstraint;
    4172                 :        5713 :         newcmd->def = (Node *) def;
    4173                 :        5713 :         newcmds = lappend(newcmds, newcmd);
    4174                 :             :     }
    4175   [ +  +  +  +  :       33682 :     foreach_node(Constraint, def, cxt.fkconstraints)
                   +  + ]
    4176                 :             :     {
    4177                 :        1862 :         newcmd = makeNode(AlterTableCmd);
    4178                 :        1862 :         newcmd->subtype = AT_AddConstraint;
    4179                 :        1862 :         newcmd->def = (Node *) def;
    4180                 :        1862 :         newcmds = lappend(newcmds, newcmd);
    4181                 :             :     }
    4182                 :             : 
    4183                 :             :     /* Close rel */
    4184                 :       15910 :     relation_close(rel, NoLock);
    4185                 :             : 
    4186                 :             :     /*
    4187                 :             :      * Output results.
    4188                 :             :      */
    4189                 :       15910 :     stmt->cmds = newcmds;
    4190                 :             : 
    4191                 :       15910 :     *beforeStmts = cxt.blist;
    4192                 :       15910 :     *afterStmts = list_concat(cxt.alist, save_alist);
    4193                 :             : 
    4194                 :       15910 :     return stmt;
    4195                 :             : }
    4196                 :             : 
    4197                 :             : 
    4198                 :             : /*
    4199                 :             :  * Preprocess a list of column constraint clauses
    4200                 :             :  * to attach constraint attributes to their primary constraint nodes
    4201                 :             :  * and detect inconsistent/misplaced constraint attributes.
    4202                 :             :  *
    4203                 :             :  * NOTE: currently, attributes are only supported for FOREIGN KEY, UNIQUE,
    4204                 :             :  * EXCLUSION, and PRIMARY KEY constraints, but someday they ought to be
    4205                 :             :  * supported for other constraint types.
    4206                 :             :  *
    4207                 :             :  * NOTE: this must be idempotent in non-error cases; see
    4208                 :             :  * transformCreateSchemaCreateTable.
    4209                 :             :  */
    4210                 :             : static void
    4211                 :       45691 : transformConstraintAttrs(ParseState *pstate, List *constraintList)
    4212                 :             : {
    4213                 :       45691 :     Constraint *lastprimarycon = NULL;
    4214                 :       45691 :     bool        saw_deferrability = false;
    4215                 :       45691 :     bool        saw_initially = false;
    4216                 :       45691 :     bool        saw_enforced = false;
    4217                 :             :     ListCell   *clist;
    4218                 :             : 
    4219                 :             : #define SUPPORTS_ATTRS(node)                \
    4220                 :             :     ((node) != NULL &&                      \
    4221                 :             :      ((node)->contype == CONSTR_PRIMARY ||   \
    4222                 :             :       (node)->contype == CONSTR_UNIQUE ||    \
    4223                 :             :       (node)->contype == CONSTR_EXCLUSION || \
    4224                 :             :       (node)->contype == CONSTR_FOREIGN))
    4225                 :             : 
    4226   [ +  +  +  +  :       58644 :     foreach(clist, constraintList)
                   +  + ]
    4227                 :             :     {
    4228                 :       12969 :         Constraint *con = (Constraint *) lfirst(clist);
    4229                 :             : 
    4230         [ -  + ]:       12969 :         if (!IsA(con, Constraint))
    4231         [ #  # ]:           0 :             elog(ERROR, "unrecognized node type: %d",
    4232                 :             :                  (int) nodeTag(con));
    4233   [ +  +  +  +  :       12969 :         switch (con->contype)
                +  +  + ]
    4234                 :             :         {
    4235                 :          87 :             case CONSTR_ATTR_DEFERRABLE:
    4236   [ +  -  +  +  :          87 :                 if (!SUPPORTS_ATTRS(lastprimarycon))
          +  +  +  -  -  
                      + ]
    4237         [ #  # ]:           0 :                     ereport(ERROR,
    4238                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4239                 :             :                              errmsg("misplaced DEFERRABLE clause"),
    4240                 :             :                              parser_errposition(pstate, con->location)));
    4241         [ -  + ]:          87 :                 if (saw_deferrability)
    4242         [ #  # ]:           0 :                     ereport(ERROR,
    4243                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4244                 :             :                              errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
    4245                 :             :                              parser_errposition(pstate, con->location)));
    4246                 :          87 :                 saw_deferrability = true;
    4247                 :          87 :                 lastprimarycon->deferrable = true;
    4248                 :          87 :                 break;
    4249                 :             : 
    4250                 :           4 :             case CONSTR_ATTR_NOT_DEFERRABLE:
    4251   [ +  -  +  -  :           4 :                 if (!SUPPORTS_ATTRS(lastprimarycon))
          +  -  +  -  -  
                      + ]
    4252         [ #  # ]:           0 :                     ereport(ERROR,
    4253                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4254                 :             :                              errmsg("misplaced NOT DEFERRABLE clause"),
    4255                 :             :                              parser_errposition(pstate, con->location)));
    4256         [ -  + ]:           4 :                 if (saw_deferrability)
    4257         [ #  # ]:           0 :                     ereport(ERROR,
    4258                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4259                 :             :                              errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
    4260                 :             :                              parser_errposition(pstate, con->location)));
    4261                 :           4 :                 saw_deferrability = true;
    4262                 :           4 :                 lastprimarycon->deferrable = false;
    4263         [ -  + ]:           4 :                 if (saw_initially &&
    4264         [ #  # ]:           0 :                     lastprimarycon->initdeferred)
    4265         [ #  # ]:           0 :                     ereport(ERROR,
    4266                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4267                 :             :                              errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
    4268                 :             :                              parser_errposition(pstate, con->location)));
    4269                 :           4 :                 break;
    4270                 :             : 
    4271                 :          69 :             case CONSTR_ATTR_DEFERRED:
    4272   [ +  -  +  +  :          69 :                 if (!SUPPORTS_ATTRS(lastprimarycon))
          +  +  +  -  -  
                      + ]
    4273         [ #  # ]:           0 :                     ereport(ERROR,
    4274                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4275                 :             :                              errmsg("misplaced INITIALLY DEFERRED clause"),
    4276                 :             :                              parser_errposition(pstate, con->location)));
    4277         [ -  + ]:          69 :                 if (saw_initially)
    4278         [ #  # ]:           0 :                     ereport(ERROR,
    4279                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4280                 :             :                              errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
    4281                 :             :                              parser_errposition(pstate, con->location)));
    4282                 :          69 :                 saw_initially = true;
    4283                 :          69 :                 lastprimarycon->initdeferred = true;
    4284                 :             : 
    4285                 :             :                 /*
    4286                 :             :                  * If only INITIALLY DEFERRED appears, assume DEFERRABLE
    4287                 :             :                  */
    4288         [ +  + ]:          69 :                 if (!saw_deferrability)
    4289                 :          15 :                     lastprimarycon->deferrable = true;
    4290         [ -  + ]:          54 :                 else if (!lastprimarycon->deferrable)
    4291         [ #  # ]:           0 :                     ereport(ERROR,
    4292                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4293                 :             :                              errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
    4294                 :             :                              parser_errposition(pstate, con->location)));
    4295                 :          69 :                 break;
    4296                 :             : 
    4297                 :           8 :             case CONSTR_ATTR_IMMEDIATE:
    4298   [ +  -  +  -  :           8 :                 if (!SUPPORTS_ATTRS(lastprimarycon))
          +  -  +  -  -  
                      + ]
    4299         [ #  # ]:           0 :                     ereport(ERROR,
    4300                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4301                 :             :                              errmsg("misplaced INITIALLY IMMEDIATE clause"),
    4302                 :             :                              parser_errposition(pstate, con->location)));
    4303         [ -  + ]:           8 :                 if (saw_initially)
    4304         [ #  # ]:           0 :                     ereport(ERROR,
    4305                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4306                 :             :                              errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
    4307                 :             :                              parser_errposition(pstate, con->location)));
    4308                 :           8 :                 saw_initially = true;
    4309                 :           8 :                 lastprimarycon->initdeferred = false;
    4310                 :           8 :                 break;
    4311                 :             : 
    4312                 :          48 :             case CONSTR_ATTR_ENFORCED:
    4313         [ +  - ]:          48 :                 if (lastprimarycon == NULL ||
    4314         [ +  + ]:          48 :                     (lastprimarycon->contype != CONSTR_CHECK &&
    4315         [ +  + ]:          12 :                      lastprimarycon->contype != CONSTR_FOREIGN))
    4316         [ +  - ]:           4 :                     ereport(ERROR,
    4317                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4318                 :             :                              errmsg("misplaced ENFORCED clause"),
    4319                 :             :                              parser_errposition(pstate, con->location)));
    4320         [ +  + ]:          44 :                 if (saw_enforced)
    4321         [ +  - ]:           4 :                     ereport(ERROR,
    4322                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4323                 :             :                              errmsg("multiple ENFORCED/NOT ENFORCED clauses not allowed"),
    4324                 :             :                              parser_errposition(pstate, con->location)));
    4325                 :          40 :                 saw_enforced = true;
    4326                 :          40 :                 lastprimarycon->is_enforced = true;
    4327                 :          40 :                 break;
    4328                 :             : 
    4329                 :          53 :             case CONSTR_ATTR_NOT_ENFORCED:
    4330         [ +  - ]:          53 :                 if (lastprimarycon == NULL ||
    4331         [ +  + ]:          53 :                     (lastprimarycon->contype != CONSTR_CHECK &&
    4332         [ +  + ]:          17 :                      lastprimarycon->contype != CONSTR_FOREIGN))
    4333         [ +  - ]:           4 :                     ereport(ERROR,
    4334                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4335                 :             :                              errmsg("misplaced NOT ENFORCED clause"),
    4336                 :             :                              parser_errposition(pstate, con->location)));
    4337         [ +  + ]:          49 :                 if (saw_enforced)
    4338         [ +  - ]:           4 :                     ereport(ERROR,
    4339                 :             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    4340                 :             :                              errmsg("multiple ENFORCED/NOT ENFORCED clauses not allowed"),
    4341                 :             :                              parser_errposition(pstate, con->location)));
    4342                 :          45 :                 saw_enforced = true;
    4343                 :          45 :                 lastprimarycon->is_enforced = false;
    4344                 :             : 
    4345                 :             :                 /* A NOT ENFORCED constraint must be marked as invalid. */
    4346                 :          45 :                 lastprimarycon->skip_validation = true;
    4347                 :          45 :                 lastprimarycon->initially_valid = false;
    4348                 :          45 :                 break;
    4349                 :             : 
    4350                 :       12700 :             default:
    4351                 :             :                 /* Otherwise it's not an attribute */
    4352                 :       12700 :                 lastprimarycon = con;
    4353                 :             :                 /* reset flags for new primary node */
    4354                 :       12700 :                 saw_deferrability = false;
    4355                 :       12700 :                 saw_initially = false;
    4356                 :       12700 :                 saw_enforced = false;
    4357                 :       12700 :                 break;
    4358                 :             :         }
    4359                 :             :     }
    4360                 :       45675 : }
    4361                 :             : 
    4362                 :             : /*
    4363                 :             :  * Special handling of type definition for a column
    4364                 :             :  */
    4365                 :             : static void
    4366                 :       45180 : transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
    4367                 :             : {
    4368                 :             :     /*
    4369                 :             :      * All we really need to do here is verify that the type is valid,
    4370                 :             :      * including any collation spec that might be present.
    4371                 :             :      */
    4372                 :       45180 :     Type        ctype = typenameType(cxt->pstate, column->typeName, NULL);
    4373                 :             : 
    4374         [ +  + ]:       45171 :     if (column->collClause)
    4375                 :             :     {
    4376                 :         359 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(ctype);
    4377                 :             : 
    4378                 :         359 :         LookupCollation(cxt->pstate,
    4379                 :         359 :                         column->collClause->collname,
    4380                 :         359 :                         column->collClause->location);
    4381                 :             :         /* Complain if COLLATE is applied to an uncollatable type */
    4382         [ +  + ]:         351 :         if (!OidIsValid(typtup->typcollation))
    4383         [ +  - ]:           8 :             ereport(ERROR,
    4384                 :             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    4385                 :             :                      errmsg("collations are not supported by type %s",
    4386                 :             :                             format_type_be(typtup->oid)),
    4387                 :             :                      parser_errposition(cxt->pstate,
    4388                 :             :                                         column->collClause->location)));
    4389                 :             :     }
    4390                 :             : 
    4391                 :       45155 :     ReleaseSysCache(ctype);
    4392                 :       45155 : }
    4393                 :             : 
    4394                 :             : 
    4395                 :             : /*
    4396                 :             :  * transformCreateSchemaStmtElements -
    4397                 :             :  *    analyzes the elements of a CREATE SCHEMA statement
    4398                 :             :  *
    4399                 :             :  * This presently has two responsibilities.  We verify that no subcommands are
    4400                 :             :  * trying to create objects outside the new schema.  We also pull out any
    4401                 :             :  * foreign-key constraint clauses embedded in CREATE TABLE subcommands, and
    4402                 :             :  * convert them to ALTER TABLE ADD CONSTRAINT commands appended to the list.
    4403                 :             :  * This supports forward references in foreign keys, which is required by the
    4404                 :             :  * SQL standard.
    4405                 :             :  *
    4406                 :             :  * We used to try to re-order the commands in a way that would work even if
    4407                 :             :  * the user-written order would not, but that's too hard (perhaps impossible)
    4408                 :             :  * to do correctly with not-yet-parse-analyzed commands.  Now we'll just
    4409                 :             :  * execute the elements in the order given, except for foreign keys.
    4410                 :             :  *
    4411                 :             :  * "schemaName" is the name of the schema that will be used for the creation
    4412                 :             :  * of the objects listed.  It may be obtained from the schema name defined
    4413                 :             :  * in the statement or a role specification.
    4414                 :             :  *
    4415                 :             :  * The result is a list of parse nodes that still need to be analyzed ---
    4416                 :             :  * but we can't analyze the later commands until we've executed the earlier
    4417                 :             :  * ones, because of possible inter-object references.
    4418                 :             :  *
    4419                 :             :  * Note it's important that we not modify the input data structure.  We create
    4420                 :             :  * a new result List, and we copy any CREATE TABLE subcommands that we might
    4421                 :             :  * modify.
    4422                 :             :  */
    4423                 :             : List *
    4424                 :         748 : transformCreateSchemaStmtElements(ParseState *pstate, List *schemaElts,
    4425                 :             :                                   const char *schemaName)
    4426                 :             : {
    4427                 :         748 :     List       *elements = NIL;
    4428                 :         748 :     List       *fk_elements = NIL;
    4429                 :             :     ListCell   *lc;
    4430                 :             : 
    4431                 :             :     /*
    4432                 :             :      * Run through each schema element in the schema element list.  Check
    4433                 :             :      * target schema names, and collect the list of actions to be done.
    4434                 :             :      */
    4435   [ +  +  +  +  :        1192 :     foreach(lc, schemaElts)
                   +  + ]
    4436                 :             :     {
    4437                 :         512 :         Node       *element = lfirst(lc);
    4438                 :             : 
    4439   [ +  +  +  +  :         512 :         switch (nodeTag(element))
          +  +  +  +  +  
             +  +  +  - ]
    4440                 :             :         {
    4441                 :          12 :             case T_CreateSeqStmt:
    4442                 :             :                 {
    4443                 :          12 :                     CreateSeqStmt *elp = (CreateSeqStmt *) element;
    4444                 :             : 
    4445                 :          12 :                     checkSchemaNameRV(pstate, schemaName, elp->sequence);
    4446                 :           0 :                     elements = lappend(elements, element);
    4447                 :             :                 }
    4448                 :           0 :                 break;
    4449                 :             : 
    4450                 :         336 :             case T_CreateStmt:
    4451                 :             :                 {
    4452                 :         336 :                     CreateStmt *elp = (CreateStmt *) element;
    4453                 :             : 
    4454                 :         336 :                     checkSchemaNameRV(pstate, schemaName, elp->relation);
    4455                 :             :                     /* Pull out any foreign key clauses, add to fk_elements */
    4456                 :         324 :                     elp = transformCreateSchemaCreateTable(pstate,
    4457                 :             :                                                            elp,
    4458                 :             :                                                            &fk_elements);
    4459                 :         324 :                     elements = lappend(elements, elp);
    4460                 :             :                 }
    4461                 :         324 :                 break;
    4462                 :             : 
    4463                 :          41 :             case T_ViewStmt:
    4464                 :             :                 {
    4465                 :          41 :                     ViewStmt   *elp = (ViewStmt *) element;
    4466                 :             : 
    4467                 :          41 :                     checkSchemaNameRV(pstate, schemaName, elp->view);
    4468                 :          25 :                     elements = lappend(elements, element);
    4469                 :             :                 }
    4470                 :          25 :                 break;
    4471                 :             : 
    4472                 :          26 :             case T_IndexStmt:
    4473                 :             :                 {
    4474                 :          26 :                     IndexStmt  *elp = (IndexStmt *) element;
    4475                 :             : 
    4476                 :          26 :                     checkSchemaNameRV(pstate, schemaName, elp->relation);
    4477                 :          14 :                     elements = lappend(elements, element);
    4478                 :             :                 }
    4479                 :          14 :                 break;
    4480                 :             : 
    4481                 :          12 :             case T_CreateTrigStmt:
    4482                 :             :                 {
    4483                 :          12 :                     CreateTrigStmt *elp = (CreateTrigStmt *) element;
    4484                 :             : 
    4485                 :          12 :                     checkSchemaNameRV(pstate, schemaName, elp->relation);
    4486                 :           0 :                     elements = lappend(elements, element);
    4487                 :             :                 }
    4488                 :           0 :                 break;
    4489                 :             : 
    4490                 :           5 :             case T_CreateDomainStmt:
    4491                 :             :                 {
    4492                 :           5 :                     CreateDomainStmt *elp = (CreateDomainStmt *) element;
    4493                 :             : 
    4494                 :           5 :                     checkSchemaNameList(schemaName, elp->domainname);
    4495                 :           5 :                     elements = lappend(elements, element);
    4496                 :             :                 }
    4497                 :           5 :                 break;
    4498                 :             : 
    4499                 :          22 :             case T_CreateFunctionStmt:
    4500                 :             :                 {
    4501                 :          22 :                     CreateFunctionStmt *elp = (CreateFunctionStmt *) element;
    4502                 :             : 
    4503                 :          22 :                     checkSchemaNameList(schemaName, elp->funcname);
    4504                 :          18 :                     elements = lappend(elements, element);
    4505                 :             :                 }
    4506                 :          18 :                 break;
    4507                 :             : 
    4508                 :             :                 /*
    4509                 :             :                  * CREATE TYPE can produce a DefineStmt, but also
    4510                 :             :                  * CreateEnumStmt, CreateRangeStmt, and CompositeTypeStmt.
    4511                 :             :                  * Allowing DefineStmt also provides support for several other
    4512                 :             :                  * commands: currently, CREATE AGGREGATE, CREATE COLLATION,
    4513                 :             :                  * CREATE OPERATOR, and text search objects.
    4514                 :             :                  */
    4515                 :             : 
    4516                 :          39 :             case T_DefineStmt:
    4517                 :             :                 {
    4518                 :          39 :                     DefineStmt *elp = (DefineStmt *) element;
    4519                 :             : 
    4520                 :          39 :                     checkSchemaNameList(schemaName, elp->defnames);
    4521                 :          39 :                     elements = lappend(elements, element);
    4522                 :             :                 }
    4523                 :          39 :                 break;
    4524                 :             : 
    4525                 :           5 :             case T_CreateEnumStmt:
    4526                 :             :                 {
    4527                 :           5 :                     CreateEnumStmt *elp = (CreateEnumStmt *) element;
    4528                 :             : 
    4529                 :           5 :                     checkSchemaNameList(schemaName, elp->typeName);
    4530                 :           5 :                     elements = lappend(elements, element);
    4531                 :             :                 }
    4532                 :           5 :                 break;
    4533                 :             : 
    4534                 :           5 :             case T_CreateRangeStmt:
    4535                 :             :                 {
    4536                 :           5 :                     CreateRangeStmt *elp = (CreateRangeStmt *) element;
    4537                 :             : 
    4538                 :           5 :                     checkSchemaNameList(schemaName, elp->typeName);
    4539                 :           5 :                     elements = lappend(elements, element);
    4540                 :             :                 }
    4541                 :           5 :                 break;
    4542                 :             : 
    4543                 :           5 :             case T_CompositeTypeStmt:
    4544                 :             :                 {
    4545                 :           5 :                     CompositeTypeStmt *elp = (CompositeTypeStmt *) element;
    4546                 :             : 
    4547                 :           5 :                     checkSchemaNameRV(pstate, schemaName, elp->typevar);
    4548                 :           5 :                     elements = lappend(elements, element);
    4549                 :             :                 }
    4550                 :           5 :                 break;
    4551                 :             : 
    4552                 :           4 :             case T_GrantStmt:
    4553                 :           4 :                 elements = lappend(elements, element);
    4554                 :           4 :                 break;
    4555                 :             : 
    4556                 :           0 :             default:
    4557         [ #  # ]:           0 :                 elog(ERROR, "unrecognized node type: %d",
    4558                 :             :                      (int) nodeTag(element));
    4559                 :             :         }
    4560                 :             :     }
    4561                 :             : 
    4562                 :         680 :     return list_concat(elements, fk_elements);
    4563                 :             : }
    4564                 :             : 
    4565                 :             : /*
    4566                 :             :  * checkSchemaNameRV
    4567                 :             :  *      Check schema name in an element of a CREATE SCHEMA command,
    4568                 :             :  *      where the element's name is given by a RangeVar
    4569                 :             :  *
    4570                 :             :  * It's okay if the command doesn't specify a target schema name, because
    4571                 :             :  * CreateSchemaCommand will set up the default creation schema to be the
    4572                 :             :  * new schema.  But if a target schema name is given, it had better match.
    4573                 :             :  * We also have to check that the command doesn't say CREATE TEMP, since
    4574                 :             :  * that would likewise put the object into the wrong schema.
    4575                 :             :  */
    4576                 :             : static void
    4577                 :         432 : checkSchemaNameRV(ParseState *pstate, const char *context_schema,
    4578                 :             :                   RangeVar *relation)
    4579                 :             : {
    4580         [ +  + ]:         432 :     if (relation->schemaname != NULL &&
    4581         [ +  + ]:          84 :         strcmp(context_schema, relation->schemaname) != 0)
    4582         [ +  - ]:          60 :         ereport(ERROR,
    4583                 :             :                 (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
    4584                 :             :                  errmsg("CREATE specifies a schema (%s) "
    4585                 :             :                         "different from the one being created (%s)",
    4586                 :             :                         relation->schemaname, context_schema),
    4587                 :             :                  parser_errposition(pstate, relation->location)));
    4588                 :             : 
    4589         [ +  + ]:         372 :     if (relation->relpersistence == RELPERSISTENCE_TEMP)
    4590                 :             :     {
    4591                 :             :         /* spell this error the same as in RangeVarAdjustRelationPersistence */
    4592         [ +  - ]:           4 :         ereport(ERROR,
    4593                 :             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4594                 :             :                  errmsg("cannot create temporary relation in non-temporary schema"),
    4595                 :             :                  parser_errposition(pstate, relation->location)));
    4596                 :             :     }
    4597                 :         368 : }
    4598                 :             : 
    4599                 :             : /*
    4600                 :             :  * checkSchemaNameList
    4601                 :             :  *      Check schema name in an element of a CREATE SCHEMA command,
    4602                 :             :  *      where the element's name is given by a List
    4603                 :             :  *
    4604                 :             :  * Much as above, but we don't have to worry about TEMP.
    4605                 :             :  * Sadly, this also means we don't have a parse location to report.
    4606                 :             :  */
    4607                 :             : static void
    4608                 :          76 : checkSchemaNameList(const char *context_schema, List *qualified_name)
    4609                 :             : {
    4610                 :             :     char       *obj_schema;
    4611                 :             :     char       *obj_name;
    4612                 :             : 
    4613                 :          76 :     DeconstructQualifiedName(qualified_name, &obj_schema, &obj_name);
    4614         [ +  + ]:          76 :     if (obj_schema != NULL &&
    4615         [ +  + ]:           8 :         strcmp(context_schema, obj_schema) != 0)
    4616         [ +  - ]:           4 :         ereport(ERROR,
    4617                 :             :                 (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
    4618                 :             :                  errmsg("CREATE specifies a schema (%s) "
    4619                 :             :                         "different from the one being created (%s)",
    4620                 :             :                         obj_schema, context_schema)));
    4621                 :          72 : }
    4622                 :             : 
    4623                 :             : /*
    4624                 :             :  * transformCreateSchemaCreateTable
    4625                 :             :  *      Process one CreateStmt for transformCreateSchemaStmtElements.
    4626                 :             :  *
    4627                 :             :  * We remove any foreign-key clauses in the statement and convert them into
    4628                 :             :  * ALTER TABLE commands, which we append to *fk_elements.
    4629                 :             :  */
    4630                 :             : static CreateStmt *
    4631                 :         324 : transformCreateSchemaCreateTable(ParseState *pstate,
    4632                 :             :                                  CreateStmt *stmt,
    4633                 :             :                                  List **fk_elements)
    4634                 :             : {
    4635                 :             :     CreateStmt *newstmt;
    4636                 :         324 :     List       *newElts = NIL;
    4637                 :             :     ListCell   *lc;
    4638                 :             : 
    4639                 :             :     /*
    4640                 :             :      * Flat-copy the CreateStmt node, allowing us to replace its tableElts
    4641                 :             :      * list without damaging the input data structure.  Most sub-nodes will be
    4642                 :             :      * shared with the input, though.
    4643                 :             :      */
    4644                 :         324 :     newstmt = makeNode(CreateStmt);
    4645                 :         324 :     memcpy(newstmt, stmt, sizeof(CreateStmt));
    4646                 :             : 
    4647                 :             :     /* Scan for foreign-key constraints */
    4648   [ +  +  +  +  :         699 :     foreach(lc, stmt->tableElts)
                   +  + ]
    4649                 :             :     {
    4650                 :         375 :         Node       *element = lfirst(lc);
    4651                 :             :         AlterTableStmt *alterstmt;
    4652                 :             :         AlterTableCmd *altercmd;
    4653                 :             : 
    4654         [ +  + ]:         375 :         if (IsA(element, Constraint))
    4655                 :             :         {
    4656                 :          59 :             Constraint *constr = (Constraint *) element;
    4657                 :             : 
    4658         [ +  + ]:          59 :             if (constr->contype != CONSTR_FOREIGN)
    4659                 :             :             {
    4660                 :             :                 /* Other constraint types pass through unchanged */
    4661                 :          14 :                 newElts = lappend(newElts, constr);
    4662                 :          14 :                 continue;
    4663                 :             :             }
    4664                 :             : 
    4665                 :             :             /* Make it into an ALTER TABLE ADD CONSTRAINT command */
    4666                 :          45 :             altercmd = makeNode(AlterTableCmd);
    4667                 :          45 :             altercmd->subtype = AT_AddConstraint;
    4668                 :          45 :             altercmd->name = NULL;
    4669                 :          45 :             altercmd->def = (Node *) copyObject(constr);
    4670                 :             : 
    4671                 :          45 :             alterstmt = makeNode(AlterTableStmt);
    4672                 :          45 :             alterstmt->relation = copyObject(stmt->relation);
    4673                 :          45 :             alterstmt->cmds = list_make1(altercmd);
    4674                 :          45 :             alterstmt->objtype = OBJECT_TABLE;
    4675                 :             : 
    4676                 :          45 :             *fk_elements = lappend(*fk_elements, alterstmt);
    4677                 :             :         }
    4678         [ +  - ]:         316 :         else if (IsA(element, ColumnDef))
    4679                 :             :         {
    4680                 :         316 :             ColumnDef  *entry = (ColumnDef *) element;
    4681                 :             :             ColumnDef  *newentry;
    4682                 :             :             List       *entryconstraints;
    4683                 :         316 :             bool        afterFK = false;
    4684                 :             : 
    4685                 :             :             /*
    4686                 :             :              * We must preprocess the list of column constraints to attach
    4687                 :             :              * attributes such as DEFERRED to the appropriate constraint node.
    4688                 :             :              * Do this on a copy.  (But execution of the CreateStmt will run
    4689                 :             :              * transformConstraintAttrs on the copy, so we are nonetheless
    4690                 :             :              * relying on transformConstraintAttrs to be idempotent.)
    4691                 :             :              */
    4692                 :         316 :             entryconstraints = copyObject(entry->constraints);
    4693                 :         316 :             transformConstraintAttrs(pstate, entryconstraints);
    4694                 :             : 
    4695                 :             :             /* Scan the column constraints ... */
    4696   [ +  +  +  +  :         865 :             foreach_node(Constraint, colconstr, entryconstraints)
                   +  + ]
    4697                 :             :             {
    4698      [ +  +  + ]:         233 :                 switch (colconstr->contype)
    4699                 :             :                 {
    4700                 :          38 :                     case CONSTR_FOREIGN:
    4701                 :             :                         /* colconstr is already a copy, OK to modify */
    4702                 :          38 :                         colconstr->fk_attrs = list_make1(makeString(entry->colname));
    4703                 :             : 
    4704                 :             :                         /* Make it into an ALTER TABLE ADD CONSTRAINT command */
    4705                 :          38 :                         altercmd = makeNode(AlterTableCmd);
    4706                 :          38 :                         altercmd->subtype = AT_AddConstraint;
    4707                 :          38 :                         altercmd->name = NULL;
    4708                 :          38 :                         altercmd->def = (Node *) colconstr;
    4709                 :             : 
    4710                 :          38 :                         alterstmt = makeNode(AlterTableStmt);
    4711                 :          38 :                         alterstmt->relation = copyObject(stmt->relation);
    4712                 :          38 :                         alterstmt->cmds = list_make1(altercmd);
    4713                 :          38 :                         alterstmt->objtype = OBJECT_TABLE;
    4714                 :             : 
    4715                 :          38 :                         *fk_elements = lappend(*fk_elements, alterstmt);
    4716                 :             : 
    4717                 :             :                         /* Remove the Constraint node from entryconstraints */
    4718                 :          38 :                         entryconstraints =
    4719                 :          38 :                             foreach_delete_current(entryconstraints, colconstr);
    4720                 :             : 
    4721                 :             :                         /*
    4722                 :             :                          * Immediately-following attribute constraints should
    4723                 :             :                          * be dropped, too.
    4724                 :             :                          */
    4725                 :          38 :                         afterFK = true;
    4726                 :          38 :                         break;
    4727                 :             : 
    4728                 :             :                         /*
    4729                 :             :                          * Column constraint lists separate a Constraint node
    4730                 :             :                          * from its attributes (e.g. NOT ENFORCED); so a
    4731                 :             :                          * column-level foreign key constraint may be
    4732                 :             :                          * represented by multiple Constraint nodes.  After
    4733                 :             :                          * transformConstraintAttrs, the foreign key
    4734                 :             :                          * Constraint node contains all required information,
    4735                 :             :                          * making it okay to put into *fk_elements as a
    4736                 :             :                          * stand-alone Constraint.  But since we removed the
    4737                 :             :                          * foreign key Constraint node from entryconstraints,
    4738                 :             :                          * we must remove any dependent attribute nodes too,
    4739                 :             :                          * else the later re-execution of
    4740                 :             :                          * transformConstraintAttrs will misbehave.
    4741                 :             :                          */
    4742                 :          65 :                     case CONSTR_ATTR_DEFERRABLE:
    4743                 :             :                     case CONSTR_ATTR_NOT_DEFERRABLE:
    4744                 :             :                     case CONSTR_ATTR_DEFERRED:
    4745                 :             :                     case CONSTR_ATTR_IMMEDIATE:
    4746                 :             :                     case CONSTR_ATTR_ENFORCED:
    4747                 :             :                     case CONSTR_ATTR_NOT_ENFORCED:
    4748         [ +  - ]:          65 :                         if (afterFK)
    4749                 :          65 :                             entryconstraints =
    4750                 :          65 :                                 foreach_delete_current(entryconstraints,
    4751                 :             :                                                        colconstr);
    4752                 :          65 :                         break;
    4753                 :             : 
    4754                 :         130 :                     default:
    4755                 :             :                         /* Any following constraint attributes are unrelated */
    4756                 :         130 :                         afterFK = false;
    4757                 :         130 :                         break;
    4758                 :             :                 }
    4759                 :             :             }
    4760                 :             : 
    4761                 :             :             /* Now make a modified ColumnDef to put into newElts */
    4762                 :         316 :             newentry = makeNode(ColumnDef);
    4763                 :         316 :             memcpy(newentry, entry, sizeof(ColumnDef));
    4764                 :         316 :             newentry->constraints = entryconstraints;
    4765                 :         316 :             newElts = lappend(newElts, newentry);
    4766                 :             :         }
    4767                 :             :         else
    4768                 :             :         {
    4769                 :             :             /* Other node types pass through unchanged */
    4770                 :           0 :             newElts = lappend(newElts, element);
    4771                 :             :         }
    4772                 :             :     }
    4773                 :             : 
    4774                 :         324 :     newstmt->tableElts = newElts;
    4775                 :         324 :     return newstmt;
    4776                 :             : }
    4777                 :             : 
    4778                 :             : /*
    4779                 :             :  * transformPartitionCmd
    4780                 :             :  *      Analyze the ATTACH/DETACH/SPLIT PARTITION command
    4781                 :             :  *
    4782                 :             :  * In case of the ATTACH/SPLIT PARTITION command, cxt->partbound is set to the
    4783                 :             :  * transformed value of bound.
    4784                 :             :  */
    4785                 :             : static void
    4786                 :        3032 : transformPartitionCmd(CreateStmtContext *cxt, PartitionBoundSpec *bound)
    4787                 :             : {
    4788                 :        3032 :     Relation    parentRel = cxt->rel;
    4789                 :             : 
    4790   [ +  +  -  -  :        3032 :     switch (parentRel->rd_rel->relkind)
                      - ]
    4791                 :             :     {
    4792                 :        2759 :         case RELKIND_PARTITIONED_TABLE:
    4793                 :             :             /* transform the partition bound, if any */
    4794                 :             :             Assert(RelationGetPartitionKey(parentRel) != NULL);
    4795         [ +  + ]:        2759 :             if (bound != NULL)
    4796                 :        2386 :                 cxt->partbound = transformPartitionBound(cxt->pstate, parentRel,
    4797                 :             :                                                          bound);
    4798                 :        2743 :             break;
    4799                 :         273 :         case RELKIND_PARTITIONED_INDEX:
    4800                 :             : 
    4801                 :             :             /*
    4802                 :             :              * A partitioned index cannot have a partition bound set.  ALTER
    4803                 :             :              * INDEX prevents that with its grammar, but not ALTER TABLE.
    4804                 :             :              */
    4805         [ +  + ]:         273 :             if (bound != NULL)
    4806         [ +  - ]:           4 :                 ereport(ERROR,
    4807                 :             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    4808                 :             :                          errmsg("\"%s\" is not a partitioned table",
    4809                 :             :                                 RelationGetRelationName(parentRel))));
    4810                 :         269 :             break;
    4811                 :           0 :         case RELKIND_RELATION:
    4812                 :             :             /* the table must be partitioned */
    4813         [ #  # ]:           0 :             ereport(ERROR,
    4814                 :             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    4815                 :             :                      errmsg("table \"%s\" is not partitioned",
    4816                 :             :                             RelationGetRelationName(parentRel))));
    4817                 :             :             break;
    4818                 :           0 :         case RELKIND_INDEX:
    4819                 :             :             /* the index must be partitioned */
    4820         [ #  # ]:           0 :             ereport(ERROR,
    4821                 :             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    4822                 :             :                      errmsg("index \"%s\" is not partitioned",
    4823                 :             :                             RelationGetRelationName(parentRel))));
    4824                 :             :             break;
    4825                 :           0 :         default:
    4826                 :             :             /* parser shouldn't let this case through */
    4827         [ #  # ]:           0 :             elog(ERROR, "\"%s\" is not a partitioned table or index",
    4828                 :             :                  RelationGetRelationName(parentRel));
    4829                 :             :             break;
    4830                 :             :     }
    4831                 :        3012 : }
    4832                 :             : 
    4833                 :             : /*
    4834                 :             :  * transformPartitionBound
    4835                 :             :  *
    4836                 :             :  * Transform a partition bound specification
    4837                 :             :  */
    4838                 :             : PartitionBoundSpec *
    4839                 :        8864 : transformPartitionBound(ParseState *pstate, Relation parent,
    4840                 :             :                         PartitionBoundSpec *spec)
    4841                 :             : {
    4842                 :             :     PartitionBoundSpec *result_spec;
    4843                 :        8864 :     PartitionKey key = RelationGetPartitionKey(parent);
    4844                 :        8864 :     char        strategy = get_partition_strategy(key);
    4845                 :        8864 :     int         partnatts = get_partition_natts(key);
    4846                 :        8864 :     List       *partexprs = get_partition_exprs(key);
    4847                 :             : 
    4848                 :             :     /* Avoid scribbling on input */
    4849                 :        8864 :     result_spec = copyObject(spec);
    4850                 :             : 
    4851         [ +  + ]:        8864 :     if (spec->is_default)
    4852                 :             :     {
    4853                 :             :         /*
    4854                 :             :          * Hash partitioning does not support a default partition; there's no
    4855                 :             :          * use case for it (since the set of partitions to create is perfectly
    4856                 :             :          * defined), and if users do get into it accidentally, it's hard to
    4857                 :             :          * back out from it afterwards.
    4858                 :             :          */
    4859         [ +  + ]:         556 :         if (strategy == PARTITION_STRATEGY_HASH)
    4860         [ +  - ]:           4 :             ereport(ERROR,
    4861                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4862                 :             :                      errmsg("a hash-partitioned table may not have a default partition")));
    4863                 :             : 
    4864                 :             :         /*
    4865                 :             :          * In case of the default partition, parser had no way to identify the
    4866                 :             :          * partition strategy. Assign the parent's strategy to the default
    4867                 :             :          * partition bound spec.
    4868                 :             :          */
    4869                 :         552 :         result_spec->strategy = strategy;
    4870                 :             : 
    4871                 :         552 :         return result_spec;
    4872                 :             :     }
    4873                 :             : 
    4874         [ +  + ]:        8308 :     if (strategy == PARTITION_STRATEGY_HASH)
    4875                 :             :     {
    4876         [ +  + ]:         488 :         if (spec->strategy != PARTITION_STRATEGY_HASH)
    4877         [ +  - ]:           8 :             ereport(ERROR,
    4878                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4879                 :             :                      errmsg("invalid bound specification for a hash partition"),
    4880                 :             :                      parser_errposition(pstate, exprLocation((Node *) spec))));
    4881                 :             : 
    4882         [ +  + ]:         480 :         if (spec->modulus <= 0)
    4883         [ +  - ]:           8 :             ereport(ERROR,
    4884                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4885                 :             :                      errmsg("modulus for hash partition must be an integer value greater than zero")));
    4886                 :             : 
    4887                 :             :         Assert(spec->remainder >= 0);
    4888                 :             : 
    4889         [ +  + ]:         472 :         if (spec->remainder >= spec->modulus)
    4890         [ +  - ]:           8 :             ereport(ERROR,
    4891                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4892                 :             :                      errmsg("remainder for hash partition must be less than modulus")));
    4893                 :             :     }
    4894         [ +  + ]:        7820 :     else if (strategy == PARTITION_STRATEGY_LIST)
    4895                 :             :     {
    4896                 :             :         ListCell   *cell;
    4897                 :             :         char       *colname;
    4898                 :             :         Oid         coltype;
    4899                 :             :         int32       coltypmod;
    4900                 :             :         Oid         partcollation;
    4901                 :             : 
    4902         [ +  + ]:        3328 :         if (spec->strategy != PARTITION_STRATEGY_LIST)
    4903         [ +  - ]:          12 :             ereport(ERROR,
    4904                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4905                 :             :                      errmsg("invalid bound specification for a list partition"),
    4906                 :             :                      parser_errposition(pstate, exprLocation((Node *) spec))));
    4907                 :             : 
    4908                 :             :         /* Get the only column's name in case we need to output an error */
    4909         [ +  + ]:        3316 :         if (key->partattrs[0] != 0)
    4910                 :        3229 :             colname = get_attname(RelationGetRelid(parent),
    4911                 :        3229 :                                   key->partattrs[0], false);
    4912                 :             :         else
    4913                 :          87 :             colname = deparse_expression((Node *) linitial(partexprs),
    4914                 :          87 :                                          deparse_context_for(RelationGetRelationName(parent),
    4915                 :             :                                                              RelationGetRelid(parent)),
    4916                 :             :                                          false, false);
    4917                 :             :         /* Need its type data too */
    4918                 :        3316 :         coltype = get_partition_col_typid(key, 0);
    4919                 :        3316 :         coltypmod = get_partition_col_typmod(key, 0);
    4920                 :        3316 :         partcollation = get_partition_col_collation(key, 0);
    4921                 :             : 
    4922                 :        3316 :         result_spec->listdatums = NIL;
    4923   [ +  -  +  +  :        8551 :         foreach(cell, spec->listdatums)
                   +  + ]
    4924                 :             :         {
    4925                 :        5275 :             Node       *expr = lfirst(cell);
    4926                 :             :             Const      *value;
    4927                 :             :             ListCell   *cell2;
    4928                 :             :             bool        duplicate;
    4929                 :             : 
    4930                 :        5275 :             value = transformPartitionBoundValue(pstate, expr,
    4931                 :             :                                                  colname, coltype, coltypmod,
    4932                 :             :                                                  partcollation);
    4933                 :             : 
    4934                 :             :             /* Don't add to the result if the value is a duplicate */
    4935                 :        5235 :             duplicate = false;
    4936   [ +  +  +  +  :        9601 :             foreach(cell2, result_spec->listdatums)
                   +  + ]
    4937                 :             :             {
    4938                 :        4366 :                 Const      *value2 = lfirst_node(Const, cell2);
    4939                 :             : 
    4940         [ -  + ]:        4366 :                 if (equal(value, value2))
    4941                 :             :                 {
    4942                 :           0 :                     duplicate = true;
    4943                 :           0 :                     break;
    4944                 :             :                 }
    4945                 :             :             }
    4946         [ -  + ]:        5235 :             if (duplicate)
    4947                 :           0 :                 continue;
    4948                 :             : 
    4949                 :        5235 :             result_spec->listdatums = lappend(result_spec->listdatums,
    4950                 :             :                                               value);
    4951                 :             :         }
    4952                 :             :     }
    4953         [ +  - ]:        4492 :     else if (strategy == PARTITION_STRATEGY_RANGE)
    4954                 :             :     {
    4955         [ +  + ]:        4492 :         if (spec->strategy != PARTITION_STRATEGY_RANGE)
    4956         [ +  - ]:          16 :             ereport(ERROR,
    4957                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4958                 :             :                      errmsg("invalid bound specification for a range partition"),
    4959                 :             :                      parser_errposition(pstate, exprLocation((Node *) spec))));
    4960                 :             : 
    4961         [ +  + ]:        4476 :         if (list_length(spec->lowerdatums) != partnatts)
    4962         [ +  - ]:           4 :             ereport(ERROR,
    4963                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4964                 :             :                      errmsg("FROM must specify exactly one value per partitioning column")));
    4965         [ +  + ]:        4472 :         if (list_length(spec->upperdatums) != partnatts)
    4966         [ +  - ]:           4 :             ereport(ERROR,
    4967                 :             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4968                 :             :                      errmsg("TO must specify exactly one value per partitioning column")));
    4969                 :             : 
    4970                 :             :         /*
    4971                 :             :          * Convert raw parse nodes into PartitionRangeDatum nodes and perform
    4972                 :             :          * any necessary validation.
    4973                 :             :          */
    4974                 :        4424 :         result_spec->lowerdatums =
    4975                 :        4468 :             transformPartitionRangeBounds(pstate, spec->lowerdatums,
    4976                 :             :                                           parent);
    4977                 :        4420 :         result_spec->upperdatums =
    4978                 :        4424 :             transformPartitionRangeBounds(pstate, spec->upperdatums,
    4979                 :             :                                           parent);
    4980                 :             :     }
    4981                 :             :     else
    4982         [ #  # ]:           0 :         elog(ERROR, "unexpected partition strategy: %d", (int) strategy);
    4983                 :             : 
    4984                 :        8160 :     return result_spec;
    4985                 :             : }
    4986                 :             : 
    4987                 :             : /*
    4988                 :             :  * transformPartitionRangeBounds
    4989                 :             :  *      This converts the expressions for range partition bounds from the raw
    4990                 :             :  *      grammar representation to PartitionRangeDatum structs
    4991                 :             :  */
    4992                 :             : static List *
    4993                 :        8892 : transformPartitionRangeBounds(ParseState *pstate, List *blist,
    4994                 :             :                               Relation parent)
    4995                 :             : {
    4996                 :        8892 :     List       *result = NIL;
    4997                 :        8892 :     PartitionKey key = RelationGetPartitionKey(parent);
    4998                 :        8892 :     List       *partexprs = get_partition_exprs(key);
    4999                 :             :     ListCell   *lc;
    5000                 :             :     int         i,
    5001                 :             :                 j;
    5002                 :             : 
    5003                 :        8892 :     j = 0;
    5004   [ +  -  +  +  :       19238 :     foreach(lc, blist)
                   +  + ]
    5005                 :             :     {
    5006                 :       10382 :         Node       *expr = lfirst(lc);
    5007                 :       10382 :         PartitionRangeDatum *prd = NULL;
    5008                 :             : 
    5009                 :       10382 :         i = foreach_current_index(lc);
    5010                 :             : 
    5011                 :             :         /*
    5012                 :             :          * Infinite range bounds -- "minvalue" and "maxvalue" -- get passed in
    5013                 :             :          * as ColumnRefs.
    5014                 :             :          */
    5015         [ +  + ]:       10382 :         if (IsA(expr, ColumnRef))
    5016                 :             :         {
    5017                 :         539 :             ColumnRef  *cref = (ColumnRef *) expr;
    5018                 :         539 :             char       *cname = NULL;
    5019                 :             : 
    5020                 :             :             /*
    5021                 :             :              * There should be a single field named either "minvalue" or
    5022                 :             :              * "maxvalue".
    5023                 :             :              */
    5024         [ +  + ]:         539 :             if (list_length(cref->fields) == 1 &&
    5025         [ +  - ]:         535 :                 IsA(linitial(cref->fields), String))
    5026                 :         535 :                 cname = strVal(linitial(cref->fields));
    5027                 :             : 
    5028         [ +  + ]:         539 :             if (cname == NULL)
    5029                 :             :             {
    5030                 :             :                 /*
    5031                 :             :                  * ColumnRef is not in the desired single-field-name form. For
    5032                 :             :                  * consistency between all partition strategies, let the
    5033                 :             :                  * expression transformation report any errors rather than
    5034                 :             :                  * doing it ourselves.
    5035                 :             :                  */
    5036                 :             :             }
    5037         [ +  + ]:         535 :             else if (strcmp("minvalue", cname) == 0)
    5038                 :             :             {
    5039                 :         260 :                 prd = makeNode(PartitionRangeDatum);
    5040                 :         260 :                 prd->kind = PARTITION_RANGE_DATUM_MINVALUE;
    5041                 :         260 :                 prd->value = NULL;
    5042                 :             :             }
    5043         [ +  + ]:         275 :             else if (strcmp("maxvalue", cname) == 0)
    5044                 :             :             {
    5045                 :         267 :                 prd = makeNode(PartitionRangeDatum);
    5046                 :         267 :                 prd->kind = PARTITION_RANGE_DATUM_MAXVALUE;
    5047                 :         267 :                 prd->value = NULL;
    5048                 :             :             }
    5049                 :             :         }
    5050                 :             : 
    5051         [ +  + ]:       10382 :         if (prd == NULL)
    5052                 :             :         {
    5053                 :             :             char       *colname;
    5054                 :             :             Oid         coltype;
    5055                 :             :             int32       coltypmod;
    5056                 :             :             Oid         partcollation;
    5057                 :             :             Const      *value;
    5058                 :             : 
    5059                 :             :             /* Get the column's name in case we need to output an error */
    5060         [ +  + ]:        9855 :             if (key->partattrs[i] != 0)
    5061                 :        9277 :                 colname = get_attname(RelationGetRelid(parent),
    5062                 :        9277 :                                       key->partattrs[i], false);
    5063                 :             :             else
    5064                 :             :             {
    5065                 :         578 :                 colname = deparse_expression((Node *) list_nth(partexprs, j),
    5066                 :         578 :                                              deparse_context_for(RelationGetRelationName(parent),
    5067                 :             :                                                                  RelationGetRelid(parent)),
    5068                 :             :                                              false, false);
    5069                 :         578 :                 ++j;
    5070                 :             :             }
    5071                 :             : 
    5072                 :             :             /* Need its type data too */
    5073                 :        9855 :             coltype = get_partition_col_typid(key, i);
    5074                 :        9855 :             coltypmod = get_partition_col_typmod(key, i);
    5075                 :        9855 :             partcollation = get_partition_col_collation(key, i);
    5076                 :             : 
    5077                 :        9855 :             value = transformPartitionBoundValue(pstate, expr,
    5078                 :             :                                                  colname,
    5079                 :             :                                                  coltype, coltypmod,
    5080                 :             :                                                  partcollation);
    5081         [ +  + ]:        9823 :             if (value->constisnull)
    5082         [ +  - ]:           4 :                 ereport(ERROR,
    5083                 :             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    5084                 :             :                          errmsg("cannot specify NULL in range bound")));
    5085                 :        9819 :             prd = makeNode(PartitionRangeDatum);
    5086                 :        9819 :             prd->kind = PARTITION_RANGE_DATUM_VALUE;
    5087                 :        9819 :             prd->value = (Node *) value;
    5088                 :             :         }
    5089                 :             : 
    5090                 :       10346 :         prd->location = exprLocation(expr);
    5091                 :             : 
    5092                 :       10346 :         result = lappend(result, prd);
    5093                 :             :     }
    5094                 :             : 
    5095                 :             :     /*
    5096                 :             :      * Once we see MINVALUE or MAXVALUE for one column, the remaining columns
    5097                 :             :      * must be the same.
    5098                 :             :      */
    5099                 :        8856 :     validateInfiniteBounds(pstate, result);
    5100                 :             : 
    5101                 :        8844 :     return result;
    5102                 :             : }
    5103                 :             : 
    5104                 :             : /*
    5105                 :             :  * validateInfiniteBounds
    5106                 :             :  *
    5107                 :             :  * Check that a MAXVALUE or MINVALUE specification in a partition bound is
    5108                 :             :  * followed only by more of the same.
    5109                 :             :  */
    5110                 :             : static void
    5111                 :        8856 : validateInfiniteBounds(ParseState *pstate, List *blist)
    5112                 :             : {
    5113                 :             :     ListCell   *lc;
    5114                 :        8856 :     PartitionRangeDatumKind kind = PARTITION_RANGE_DATUM_VALUE;
    5115                 :             : 
    5116   [ +  -  +  +  :       19186 :     foreach(lc, blist)
                   +  + ]
    5117                 :             :     {
    5118                 :       10342 :         PartitionRangeDatum *prd = lfirst_node(PartitionRangeDatum, lc);
    5119                 :             : 
    5120         [ +  + ]:       10342 :         if (kind == prd->kind)
    5121                 :        9959 :             continue;
    5122                 :             : 
    5123   [ +  +  +  - ]:         383 :         switch (kind)
    5124                 :             :         {
    5125                 :         371 :             case PARTITION_RANGE_DATUM_VALUE:
    5126                 :         371 :                 kind = prd->kind;
    5127                 :         371 :                 break;
    5128                 :             : 
    5129                 :           4 :             case PARTITION_RANGE_DATUM_MAXVALUE:
    5130         [ +  - ]:           4 :                 ereport(ERROR,
    5131                 :             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    5132                 :             :                          errmsg("every bound following MAXVALUE must also be MAXVALUE"),
    5133                 :             :                          parser_errposition(pstate, exprLocation((Node *) prd))));
    5134                 :             :                 break;
    5135                 :             : 
    5136                 :           8 :             case PARTITION_RANGE_DATUM_MINVALUE:
    5137         [ +  - ]:           8 :                 ereport(ERROR,
    5138                 :             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    5139                 :             :                          errmsg("every bound following MINVALUE must also be MINVALUE"),
    5140                 :             :                          parser_errposition(pstate, exprLocation((Node *) prd))));
    5141                 :             :                 break;
    5142                 :             :         }
    5143                 :             :     }
    5144                 :        8844 : }
    5145                 :             : 
    5146                 :             : /*
    5147                 :             :  * Transform one entry in a partition bound spec, producing a constant.
    5148                 :             :  */
    5149                 :             : static Const *
    5150                 :       15130 : transformPartitionBoundValue(ParseState *pstate, Node *val,
    5151                 :             :                              const char *colName, Oid colType, int32 colTypmod,
    5152                 :             :                              Oid partCollation)
    5153                 :             : {
    5154                 :             :     Node       *value;
    5155                 :             : 
    5156                 :             :     /* Transform raw parsetree */
    5157                 :       15130 :     value = transformExpr(pstate, val, EXPR_KIND_PARTITION_BOUND);
    5158                 :             : 
    5159                 :             :     /*
    5160                 :             :      * transformExpr() should have already rejected column references,
    5161                 :             :      * subqueries, aggregates, window functions, and SRFs, based on the
    5162                 :             :      * EXPR_KIND_ of a partition bound expression.
    5163                 :             :      */
    5164                 :             :     Assert(!contain_var_clause(value));
    5165                 :             : 
    5166                 :             :     /*
    5167                 :             :      * Coerce to the correct type.  This might cause an explicit coercion step
    5168                 :             :      * to be added on top of the expression, which must be evaluated before
    5169                 :             :      * returning the result to the caller.
    5170                 :             :      */
    5171                 :       15062 :     value = coerce_to_target_type(pstate,
    5172                 :             :                                   value, exprType(value),
    5173                 :             :                                   colType,
    5174                 :             :                                   colTypmod,
    5175                 :             :                                   COERCION_ASSIGNMENT,
    5176                 :             :                                   COERCE_IMPLICIT_CAST,
    5177                 :             :                                   -1);
    5178                 :             : 
    5179         [ +  + ]:       15062 :     if (value == NULL)
    5180         [ +  - ]:           4 :         ereport(ERROR,
    5181                 :             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    5182                 :             :                  errmsg("specified value cannot be cast to type %s for column \"%s\"",
    5183                 :             :                         format_type_be(colType), colName),
    5184                 :             :                  parser_errposition(pstate, exprLocation(val))));
    5185                 :             : 
    5186                 :             :     /*
    5187                 :             :      * Evaluate the expression, if needed, assigning the partition key's data
    5188                 :             :      * type and collation to the resulting Const node.
    5189                 :             :      */
    5190         [ +  + ]:       15058 :     if (!IsA(value, Const))
    5191                 :             :     {
    5192                 :         986 :         assign_expr_collations(pstate, value);
    5193                 :         986 :         value = (Node *) expression_planner((Expr *) value);
    5194                 :         986 :         value = (Node *) evaluate_expr((Expr *) value, colType, colTypmod,
    5195                 :             :                                        partCollation);
    5196         [ -  + ]:         986 :         if (!IsA(value, Const))
    5197         [ #  # ]:           0 :             elog(ERROR, "could not evaluate partition bound expression");
    5198                 :             :     }
    5199                 :             :     else
    5200                 :             :     {
    5201                 :             :         /*
    5202                 :             :          * If the expression is already a Const, as is often the case, we can
    5203                 :             :          * skip the rather expensive steps above.  But we still have to insert
    5204                 :             :          * the right collation, since coerce_to_target_type doesn't handle
    5205                 :             :          * that.
    5206                 :             :          */
    5207                 :       14072 :         ((Const *) value)->constcollid = partCollation;
    5208                 :             :     }
    5209                 :             : 
    5210                 :             :     /*
    5211                 :             :      * Attach original expression's parse location to the Const, so that
    5212                 :             :      * that's what will be reported for any later errors related to this
    5213                 :             :      * partition bound.
    5214                 :             :      */
    5215                 :       15058 :     ((Const *) value)->location = exprLocation(val);
    5216                 :             : 
    5217                 :       15058 :     return (Const *) value;
    5218                 :             : }
        

Generated by: LCOV version 2.0-1