LCOV - code coverage report
Current view: top level - src/backend/parser - parse_utilcmd.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.2 % 1722 1571
Test Date: 2026-09-05 06:15:58 Functions: 100.0 % 30 30
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 70.2 % 1417 995

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

Generated by: LCOV version 2.0-1