LCOV - code coverage report
Current view: top level - src/backend/parser - parse_utilcmd.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 91.2 % 2150 1961
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 31 31
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 61.3 % 1855 1138

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

Generated by: LCOV version 2.3.2-1