LCOV - code coverage report
Current view: top level - src/backend/parser - parse_utilcmd.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12devel Lines: 1166 1316 88.6 %
Date: 2019-01-18 15:20:34 Functions: 26 26 100.0 %
Legend: Lines: hit not hit

          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             :  * NOTE: in general we must avoid scribbling on the passed-in raw parse
      15             :  * tree, since it might be in a plan cache.  The simplest solution is
      16             :  * a quick copyObject() call before manipulating the query tree.
      17             :  *
      18             :  *
      19             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
      20             :  * Portions Copyright (c) 1994, Regents of the University of California
      21             :  *
      22             :  *  src/backend/parser/parse_utilcmd.c
      23             :  *
      24             :  *-------------------------------------------------------------------------
      25             :  */
      26             : 
      27             : #include "postgres.h"
      28             : 
      29             : #include "access/amapi.h"
      30             : #include "access/heapam.h"
      31             : #include "access/htup_details.h"
      32             : #include "access/reloptions.h"
      33             : #include "catalog/dependency.h"
      34             : #include "catalog/heap.h"
      35             : #include "catalog/index.h"
      36             : #include "catalog/namespace.h"
      37             : #include "catalog/pg_am.h"
      38             : #include "catalog/pg_collation.h"
      39             : #include "catalog/pg_constraint.h"
      40             : #include "catalog/pg_opclass.h"
      41             : #include "catalog/pg_operator.h"
      42             : #include "catalog/pg_statistic_ext.h"
      43             : #include "catalog/pg_type.h"
      44             : #include "commands/comment.h"
      45             : #include "commands/defrem.h"
      46             : #include "commands/sequence.h"
      47             : #include "commands/tablecmds.h"
      48             : #include "commands/tablespace.h"
      49             : #include "miscadmin.h"
      50             : #include "nodes/makefuncs.h"
      51             : #include "nodes/nodeFuncs.h"
      52             : #include "optimizer/planner.h"
      53             : #include "parser/analyze.h"
      54             : #include "parser/parse_clause.h"
      55             : #include "parser/parse_coerce.h"
      56             : #include "parser/parse_collate.h"
      57             : #include "parser/parse_expr.h"
      58             : #include "parser/parse_relation.h"
      59             : #include "parser/parse_target.h"
      60             : #include "parser/parse_type.h"
      61             : #include "parser/parse_utilcmd.h"
      62             : #include "parser/parser.h"
      63             : #include "rewrite/rewriteManip.h"
      64             : #include "utils/acl.h"
      65             : #include "utils/builtins.h"
      66             : #include "utils/lsyscache.h"
      67             : #include "utils/partcache.h"
      68             : #include "utils/rel.h"
      69             : #include "utils/ruleutils.h"
      70             : #include "utils/syscache.h"
      71             : #include "utils/typcache.h"
      72             : 
      73             : 
      74             : /* State shared by transformCreateStmt and its subroutines */
      75             : typedef struct
      76             : {
      77             :     ParseState *pstate;         /* overall parser state */
      78             :     const char *stmtType;       /* "CREATE [FOREIGN] TABLE" or "ALTER TABLE" */
      79             :     RangeVar   *relation;       /* relation to create */
      80             :     Relation    rel;            /* opened/locked rel, if ALTER */
      81             :     List       *inhRelations;   /* relations to inherit from */
      82             :     bool        isforeign;      /* true if CREATE/ALTER FOREIGN TABLE */
      83             :     bool        isalter;        /* true if altering existing table */
      84             :     List       *columns;        /* ColumnDef items */
      85             :     List       *ckconstraints;  /* CHECK constraints */
      86             :     List       *fkconstraints;  /* FOREIGN KEY constraints */
      87             :     List       *ixconstraints;  /* index-creating constraints */
      88             :     List       *inh_indexes;    /* cloned indexes from INCLUDING INDEXES */
      89             :     List       *extstats;       /* cloned extended statistics */
      90             :     List       *blist;          /* "before list" of things to do before
      91             :                                  * creating the table */
      92             :     List       *alist;          /* "after list" of things to do after creating
      93             :                                  * the table */
      94             :     IndexStmt  *pkey;           /* PRIMARY KEY index, if any */
      95             :     bool        ispartitioned;  /* true if table is partitioned */
      96             :     PartitionBoundSpec *partbound;  /* transformed FOR VALUES */
      97             :     bool        ofType;         /* true if statement contains OF typename */
      98             : } CreateStmtContext;
      99             : 
     100             : /* State shared by transformCreateSchemaStmt and its subroutines */
     101             : typedef struct
     102             : {
     103             :     const char *stmtType;       /* "CREATE SCHEMA" or "ALTER SCHEMA" */
     104             :     char       *schemaname;     /* name of schema */
     105             :     RoleSpec   *authrole;       /* owner of schema */
     106             :     List       *sequences;      /* CREATE SEQUENCE items */
     107             :     List       *tables;         /* CREATE TABLE items */
     108             :     List       *views;          /* CREATE VIEW items */
     109             :     List       *indexes;        /* CREATE INDEX items */
     110             :     List       *triggers;       /* CREATE TRIGGER items */
     111             :     List       *grants;         /* GRANT items */
     112             : } CreateSchemaStmtContext;
     113             : 
     114             : 
     115             : static void transformColumnDefinition(CreateStmtContext *cxt,
     116             :                           ColumnDef *column);
     117             : static void transformTableConstraint(CreateStmtContext *cxt,
     118             :                          Constraint *constraint);
     119             : static void transformTableLikeClause(CreateStmtContext *cxt,
     120             :                          TableLikeClause *table_like_clause);
     121             : static void transformOfType(CreateStmtContext *cxt,
     122             :                 TypeName *ofTypename);
     123             : static CreateStatsStmt *generateClonedExtStatsStmt(RangeVar *heapRel,
     124             :                            Oid heapRelid, Oid source_statsid);
     125             : static List *get_collation(Oid collation, Oid actual_datatype);
     126             : static List *get_opclass(Oid opclass, Oid actual_datatype);
     127             : static void transformIndexConstraints(CreateStmtContext *cxt);
     128             : static IndexStmt *transformIndexConstraint(Constraint *constraint,
     129             :                          CreateStmtContext *cxt);
     130             : static void transformExtendedStatistics(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(char *context_schema, char **stmt_schema_name);
     140             : static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd);
     141             : static void validateInfiniteBounds(ParseState *pstate, List *blist);
     142             : static Const *transformPartitionBoundValue(ParseState *pstate, A_Const *con,
     143             :                              const char *colName, Oid colType, int32 colTypmod);
     144             : 
     145             : 
     146             : /*
     147             :  * transformCreateStmt -
     148             :  *    parse analysis for CREATE TABLE
     149             :  *
     150             :  * Returns a List of utility commands to be done in sequence.  One of these
     151             :  * will be the transformed CreateStmt, but there may be additional actions
     152             :  * to be done before and after the actual DefineRelation() call.
     153             :  *
     154             :  * SQL allows constraints to be scattered all over, so thumb through
     155             :  * the columns and collect all constraints into one place.
     156             :  * If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
     157             :  * then expand those into multiple IndexStmt blocks.
     158             :  *    - thomas 1997-12-02
     159             :  */
     160             : List *
     161       18360 : transformCreateStmt(CreateStmt *stmt, const char *queryString)
     162             : {
     163             :     ParseState *pstate;
     164             :     CreateStmtContext cxt;
     165             :     List       *result;
     166             :     List       *save_alist;
     167             :     ListCell   *elements;
     168             :     Oid         namespaceid;
     169             :     Oid         existing_relid;
     170             :     ParseCallbackState pcbstate;
     171       18360 :     bool        is_foreign_table = IsA(stmt, CreateForeignTableStmt);
     172             : 
     173             :     /*
     174             :      * We must not scribble on the passed-in CreateStmt, so copy it.  (This is
     175             :      * overkill, but easy.)
     176             :      */
     177       18360 :     stmt = copyObject(stmt);
     178             : 
     179             :     /* Set up pstate */
     180       18360 :     pstate = make_parsestate(NULL);
     181       18360 :     pstate->p_sourcetext = queryString;
     182             : 
     183             :     /*
     184             :      * Look up the creation namespace.  This also checks permissions on the
     185             :      * target namespace, locks it against concurrent drops, checks for a
     186             :      * preexisting relation in that namespace with the same name, and updates
     187             :      * stmt->relation->relpersistence if the selected namespace is temporary.
     188             :      */
     189       18360 :     setup_parser_errposition_callback(&pcbstate, pstate,
     190       18360 :                                       stmt->relation->location);
     191       18360 :     namespaceid =
     192       18360 :         RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock,
     193             :                                              &existing_relid);
     194       18352 :     cancel_parser_errposition_callback(&pcbstate);
     195             : 
     196             :     /*
     197             :      * If the relation already exists and the user specified "IF NOT EXISTS",
     198             :      * bail out with a NOTICE.
     199             :      */
     200       18352 :     if (stmt->if_not_exists && OidIsValid(existing_relid))
     201             :     {
     202           8 :         ereport(NOTICE,
     203             :                 (errcode(ERRCODE_DUPLICATE_TABLE),
     204             :                  errmsg("relation \"%s\" already exists, skipping",
     205             :                         stmt->relation->relname)));
     206           8 :         return NIL;
     207             :     }
     208             : 
     209             :     /*
     210             :      * If the target relation name isn't schema-qualified, make it so.  This
     211             :      * prevents some corner cases in which added-on rewritten commands might
     212             :      * think they should apply to other relations that have the same name and
     213             :      * are earlier in the search path.  But a local temp table is effectively
     214             :      * specified to be in pg_temp, so no need for anything extra in that case.
     215             :      */
     216       18344 :     if (stmt->relation->schemaname == NULL
     217       17070 :         && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
     218       15320 :         stmt->relation->schemaname = get_namespace_name(namespaceid);
     219             : 
     220             :     /* Set up CreateStmtContext */
     221       18344 :     cxt.pstate = pstate;
     222       18344 :     if (IsA(stmt, CreateForeignTableStmt))
     223             :     {
     224         242 :         cxt.stmtType = "CREATE FOREIGN TABLE";
     225         242 :         cxt.isforeign = true;
     226             :     }
     227             :     else
     228             :     {
     229       18102 :         cxt.stmtType = "CREATE TABLE";
     230       18102 :         cxt.isforeign = false;
     231             :     }
     232       18344 :     cxt.relation = stmt->relation;
     233       18344 :     cxt.rel = NULL;
     234       18344 :     cxt.inhRelations = stmt->inhRelations;
     235       18344 :     cxt.isalter = false;
     236       18344 :     cxt.columns = NIL;
     237       18344 :     cxt.ckconstraints = NIL;
     238       18344 :     cxt.fkconstraints = NIL;
     239       18344 :     cxt.ixconstraints = NIL;
     240       18344 :     cxt.inh_indexes = NIL;
     241       18344 :     cxt.extstats = NIL;
     242       18344 :     cxt.blist = NIL;
     243       18344 :     cxt.alist = NIL;
     244       18344 :     cxt.pkey = NULL;
     245       18344 :     cxt.ispartitioned = stmt->partspec != NULL;
     246       18344 :     cxt.partbound = stmt->partbound;
     247       18344 :     cxt.ofType = (stmt->ofTypename != NULL);
     248             : 
     249             :     Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */
     250             : 
     251       18344 :     if (stmt->ofTypename)
     252          70 :         transformOfType(&cxt, stmt->ofTypename);
     253             : 
     254       18336 :     if (stmt->partspec)
     255             :     {
     256        1584 :         if (stmt->inhRelations && !stmt->partbound)
     257           4 :             ereport(ERROR,
     258             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     259             :                      errmsg("cannot create partitioned table as inheritance child")));
     260             :     }
     261             : 
     262             :     /*
     263             :      * Run through each primary element in the table creation clause. Separate
     264             :      * column defs from constraints, and do preliminary analysis.
     265             :      */
     266       63710 :     foreach(elements, stmt->tableElts)
     267             :     {
     268       45436 :         Node       *element = lfirst(elements);
     269             : 
     270       45436 :         switch (nodeTag(element))
     271             :         {
     272             :             case T_ColumnDef:
     273       44072 :                 transformColumnDefinition(&cxt, (ColumnDef *) element);
     274       44034 :                 break;
     275             : 
     276             :             case T_Constraint:
     277        1054 :                 transformTableConstraint(&cxt, (Constraint *) element);
     278        1042 :                 break;
     279             : 
     280             :             case T_TableLikeClause:
     281         310 :                 transformTableLikeClause(&cxt, (TableLikeClause *) element);
     282         302 :                 break;
     283             : 
     284             :             default:
     285           0 :                 elog(ERROR, "unrecognized node type: %d",
     286             :                      (int) nodeTag(element));
     287             :                 break;
     288             :         }
     289             :     }
     290             : 
     291             :     /*
     292             :      * transformIndexConstraints wants cxt.alist to contain only index
     293             :      * statements, so transfer anything we already have into save_alist.
     294             :      */
     295       18274 :     save_alist = cxt.alist;
     296       18274 :     cxt.alist = NIL;
     297             : 
     298             :     Assert(stmt->constraints == NIL);
     299             : 
     300             :     /*
     301             :      * Postprocess constraints that give rise to index definitions.
     302             :      */
     303       18274 :     transformIndexConstraints(&cxt);
     304             : 
     305             :     /*
     306             :      * Postprocess foreign-key constraints.
     307             :      */
     308       18270 :     transformFKConstraints(&cxt, true, false);
     309             : 
     310             :     /*
     311             :      * Postprocess check constraints.
     312             :      */
     313       18270 :     transformCheckConstraints(&cxt, !is_foreign_table ? true : false);
     314             : 
     315             :     /*
     316             :      * Postprocess extended statistics.
     317             :      */
     318       18270 :     transformExtendedStatistics(&cxt);
     319             : 
     320             :     /*
     321             :      * Output results.
     322             :      */
     323       18270 :     stmt->tableElts = cxt.columns;
     324       18270 :     stmt->constraints = cxt.ckconstraints;
     325             : 
     326       18270 :     result = lappend(cxt.blist, stmt);
     327       18270 :     result = list_concat(result, cxt.alist);
     328       18270 :     result = list_concat(result, save_alist);
     329             : 
     330       18270 :     return result;
     331             : }
     332             : 
     333             : /*
     334             :  * generateSerialExtraStmts
     335             :  *      Generate CREATE SEQUENCE and ALTER SEQUENCE ... OWNED BY statements
     336             :  *      to create the sequence for a serial or identity column.
     337             :  *
     338             :  * This includes determining the name the sequence will have.  The caller
     339             :  * can ask to get back the name components by passing non-null pointers
     340             :  * for snamespace_p and sname_p.
     341             :  */
     342             : static void
     343         572 : generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
     344             :                          Oid seqtypid, List *seqoptions, bool for_identity,
     345             :                          char **snamespace_p, char **sname_p)
     346             : {
     347             :     ListCell   *option;
     348         572 :     DefElem    *nameEl = NULL;
     349             :     Oid         snamespaceid;
     350             :     char       *snamespace;
     351             :     char       *sname;
     352             :     CreateSeqStmt *seqstmt;
     353             :     AlterSeqStmt *altseqstmt;
     354             :     List       *attnamelist;
     355             : 
     356             :     /*
     357             :      * Determine namespace and name to use for the sequence.
     358             :      *
     359             :      * First, check if a sequence name was passed in as an option.  This is
     360             :      * used by pg_dump.  Else, generate a name.
     361             :      *
     362             :      * Although we use ChooseRelationName, it's not guaranteed that the
     363             :      * selected sequence name won't conflict; given sufficiently long field
     364             :      * names, two different serial columns in the same table could be assigned
     365             :      * the same sequence name, and we'd not notice since we aren't creating
     366             :      * the sequence quite yet.  In practice this seems quite unlikely to be a
     367             :      * problem, especially since few people would need two serial columns in
     368             :      * one table.
     369             :      */
     370         752 :     foreach(option, seqoptions)
     371             :     {
     372         180 :         DefElem    *defel = lfirst_node(DefElem, option);
     373             : 
     374         180 :         if (strcmp(defel->defname, "sequence_name") == 0)
     375             :         {
     376          24 :             if (nameEl)
     377           0 :                 ereport(ERROR,
     378             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     379             :                          errmsg("conflicting or redundant options")));
     380          24 :             nameEl = defel;
     381             :         }
     382             :     }
     383             : 
     384         572 :     if (nameEl)
     385             :     {
     386          24 :         RangeVar   *rv = makeRangeVarFromNameList(castNode(List, nameEl->arg));
     387             : 
     388          24 :         snamespace = rv->schemaname;
     389          24 :         if (!snamespace)
     390             :         {
     391             :             /* Given unqualified SEQUENCE NAME, select namespace */
     392           0 :             if (cxt->rel)
     393           0 :                 snamespaceid = RelationGetNamespace(cxt->rel);
     394             :             else
     395           0 :                 snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
     396           0 :             snamespace = get_namespace_name(snamespaceid);
     397             :         }
     398          24 :         sname = rv->relname;
     399             :         /* Remove the SEQUENCE NAME item from seqoptions */
     400          24 :         seqoptions = list_delete_ptr(seqoptions, nameEl);
     401             :     }
     402             :     else
     403             :     {
     404         548 :         if (cxt->rel)
     405          44 :             snamespaceid = RelationGetNamespace(cxt->rel);
     406             :         else
     407             :         {
     408         504 :             snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
     409         504 :             RangeVarAdjustRelationPersistence(cxt->relation, snamespaceid);
     410             :         }
     411         548 :         snamespace = get_namespace_name(snamespaceid);
     412         548 :         sname = ChooseRelationName(cxt->relation->relname,
     413         548 :                                    column->colname,
     414             :                                    "seq",
     415             :                                    snamespaceid,
     416             :                                    false);
     417             :     }
     418             : 
     419         572 :     ereport(DEBUG1,
     420             :             (errmsg("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
     421             :                     cxt->stmtType, sname,
     422             :                     cxt->relation->relname, column->colname)));
     423             : 
     424             :     /*
     425             :      * Build a CREATE SEQUENCE command to create the sequence object, and add
     426             :      * it to the list of things to be done before this CREATE/ALTER TABLE.
     427             :      */
     428         572 :     seqstmt = makeNode(CreateSeqStmt);
     429         572 :     seqstmt->for_identity = for_identity;
     430         572 :     seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
     431         572 :     seqstmt->options = seqoptions;
     432             : 
     433             :     /*
     434             :      * If a sequence data type was specified, add it to the options.  Prepend
     435             :      * to the list rather than append; in case a user supplied their own AS
     436             :      * clause, the "redundant options" error will point to their occurrence,
     437             :      * not our synthetic one.
     438             :      */
     439         572 :     if (seqtypid)
     440        1136 :         seqstmt->options = lcons(makeDefElem("as",
     441         568 :                                              (Node *) makeTypeNameFromOid(seqtypid, -1),
     442             :                                              -1),
     443             :                                  seqstmt->options);
     444             : 
     445             :     /*
     446             :      * If this is ALTER ADD COLUMN, make sure the sequence will be owned by
     447             :      * the table's owner.  The current user might be someone else (perhaps a
     448             :      * superuser, or someone who's only a member of the owning role), but the
     449             :      * SEQUENCE OWNED BY mechanisms will bleat unless table and sequence have
     450             :      * exactly the same owning role.
     451             :      */
     452         572 :     if (cxt->rel)
     453          68 :         seqstmt->ownerId = cxt->rel->rd_rel->relowner;
     454             :     else
     455         504 :         seqstmt->ownerId = InvalidOid;
     456             : 
     457         572 :     cxt->blist = lappend(cxt->blist, seqstmt);
     458             : 
     459             :     /*
     460             :      * Store the identity sequence name that we decided on.  ALTER TABLE ...
     461             :      * ADD COLUMN ... IDENTITY needs this so that it can fill the new column
     462             :      * with values from the sequence, while the association of the sequence
     463             :      * with the table is not set until after the ALTER TABLE.
     464             :      */
     465         572 :     column->identitySequence = seqstmt->sequence;
     466             : 
     467             :     /*
     468             :      * Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence as
     469             :      * owned by this column, and add it to the list of things to be done after
     470             :      * this CREATE/ALTER TABLE.
     471             :      */
     472         572 :     altseqstmt = makeNode(AlterSeqStmt);
     473         572 :     altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
     474         572 :     attnamelist = list_make3(makeString(snamespace),
     475             :                              makeString(cxt->relation->relname),
     476             :                              makeString(column->colname));
     477         572 :     altseqstmt->options = list_make1(makeDefElem("owned_by",
     478             :                                                  (Node *) attnamelist, -1));
     479         572 :     altseqstmt->for_identity = for_identity;
     480             : 
     481         572 :     cxt->alist = lappend(cxt->alist, altseqstmt);
     482             : 
     483         572 :     if (snamespace_p)
     484         436 :         *snamespace_p = snamespace;
     485         572 :     if (sname_p)
     486         436 :         *sname_p = sname;
     487         572 : }
     488             : 
     489             : /*
     490             :  * transformColumnDefinition -
     491             :  *      transform a single ColumnDef within CREATE TABLE
     492             :  *      Also used in ALTER TABLE ADD COLUMN
     493             :  */
     494             : static void
     495       45022 : transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
     496             : {
     497             :     bool        is_serial;
     498             :     bool        saw_nullable;
     499             :     bool        saw_default;
     500             :     bool        saw_identity;
     501             :     ListCell   *clist;
     502             : 
     503       45022 :     cxt->columns = lappend(cxt->columns, column);
     504             : 
     505             :     /* Check for SERIAL pseudo-types */
     506       45022 :     is_serial = false;
     507       45022 :     if (column->typeName
     508       44910 :         && list_length(column->typeName->names) == 1
     509       26942 :         && !column->typeName->pct_type)
     510             :     {
     511       26942 :         char       *typname = strVal(linitial(column->typeName->names));
     512             : 
     513       53878 :         if (strcmp(typname, "smallserial") == 0 ||
     514       26936 :             strcmp(typname, "serial2") == 0)
     515             :         {
     516          10 :             is_serial = true;
     517          10 :             column->typeName->names = NIL;
     518          10 :             column->typeName->typeOid = INT2OID;
     519             :         }
     520       53452 :         else if (strcmp(typname, "serial") == 0 ||
     521       26520 :                  strcmp(typname, "serial4") == 0)
     522             :         {
     523         412 :             is_serial = true;
     524         412 :             column->typeName->names = NIL;
     525         412 :             column->typeName->typeOid = INT4OID;
     526             :         }
     527       53034 :         else if (strcmp(typname, "bigserial") == 0 ||
     528       26514 :                  strcmp(typname, "serial8") == 0)
     529             :         {
     530          14 :             is_serial = true;
     531          14 :             column->typeName->names = NIL;
     532          14 :             column->typeName->typeOid = INT8OID;
     533             :         }
     534             : 
     535             :         /*
     536             :          * We have to reject "serial[]" explicitly, because once we've set
     537             :          * typeid, LookupTypeName won't notice arrayBounds.  We don't need any
     538             :          * special coding for serial(typmod) though.
     539             :          */
     540       26942 :         if (is_serial && column->typeName->arrayBounds != NIL)
     541           0 :             ereport(ERROR,
     542             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     543             :                      errmsg("array of serial is not implemented"),
     544             :                      parser_errposition(cxt->pstate,
     545             :                                         column->typeName->location)));
     546             :     }
     547             : 
     548             :     /* Do necessary work on the column type declaration */
     549       45022 :     if (column->typeName)
     550       44910 :         transformColumnType(cxt, column);
     551             : 
     552             :     /* Special actions for SERIAL pseudo-types */
     553       45012 :     if (is_serial)
     554             :     {
     555             :         char       *snamespace;
     556             :         char       *sname;
     557             :         char       *qstring;
     558             :         A_Const    *snamenode;
     559             :         TypeCast   *castnode;
     560             :         FuncCall   *funccallnode;
     561             :         Constraint *constraint;
     562             : 
     563         436 :         generateSerialExtraStmts(cxt, column,
     564         436 :                                  column->typeName->typeOid, NIL, false,
     565             :                                  &snamespace, &sname);
     566             : 
     567             :         /*
     568             :          * Create appropriate constraints for SERIAL.  We do this in full,
     569             :          * rather than shortcutting, so that we will detect any conflicting
     570             :          * constraints the user wrote (like a different DEFAULT).
     571             :          *
     572             :          * Create an expression tree representing the function call
     573             :          * nextval('sequencename').  We cannot reduce the raw tree to cooked
     574             :          * form until after the sequence is created, but there's no need to do
     575             :          * so.
     576             :          */
     577         436 :         qstring = quote_qualified_identifier(snamespace, sname);
     578         436 :         snamenode = makeNode(A_Const);
     579         436 :         snamenode->val.type = T_String;
     580         436 :         snamenode->val.val.str = qstring;
     581         436 :         snamenode->location = -1;
     582         436 :         castnode = makeNode(TypeCast);
     583         436 :         castnode->typeName = SystemTypeName("regclass");
     584         436 :         castnode->arg = (Node *) snamenode;
     585         436 :         castnode->location = -1;
     586         436 :         funccallnode = makeFuncCall(SystemFuncName("nextval"),
     587             :                                     list_make1(castnode),
     588             :                                     -1);
     589         436 :         constraint = makeNode(Constraint);
     590         436 :         constraint->contype = CONSTR_DEFAULT;
     591         436 :         constraint->location = -1;
     592         436 :         constraint->raw_expr = (Node *) funccallnode;
     593         436 :         constraint->cooked_expr = NULL;
     594         436 :         column->constraints = lappend(column->constraints, constraint);
     595             : 
     596         436 :         constraint = makeNode(Constraint);
     597         436 :         constraint->contype = CONSTR_NOTNULL;
     598         436 :         constraint->location = -1;
     599         436 :         column->constraints = lappend(column->constraints, constraint);
     600             :     }
     601             : 
     602             :     /* Process column constraints, if any... */
     603       45012 :     transformConstraintAttrs(cxt, column->constraints);
     604             : 
     605       45012 :     saw_nullable = false;
     606       45012 :     saw_default = false;
     607       45012 :     saw_identity = false;
     608             : 
     609       54522 :     foreach(clist, column->constraints)
     610             :     {
     611        9538 :         Constraint *constraint = lfirst_node(Constraint, clist);
     612             : 
     613        9538 :         switch (constraint->contype)
     614             :         {
     615             :             case CONSTR_NULL:
     616           8 :                 if (saw_nullable && column->is_not_null)
     617           0 :                     ereport(ERROR,
     618             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     619             :                              errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
     620             :                                     column->colname, cxt->relation->relname),
     621             :                              parser_errposition(cxt->pstate,
     622             :                                                 constraint->location)));
     623           8 :                 column->is_not_null = false;
     624           8 :                 saw_nullable = true;
     625           8 :                 break;
     626             : 
     627             :             case CONSTR_NOTNULL:
     628        4506 :                 if (saw_nullable && !column->is_not_null)
     629           0 :                     ereport(ERROR,
     630             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     631             :                              errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
     632             :                                     column->colname, cxt->relation->relname),
     633             :                              parser_errposition(cxt->pstate,
     634             :                                                 constraint->location)));
     635        4506 :                 column->is_not_null = true;
     636        4506 :                 saw_nullable = true;
     637        4506 :                 break;
     638             : 
     639             :             case CONSTR_DEFAULT:
     640        1162 :                 if (saw_default)
     641           0 :                     ereport(ERROR,
     642             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     643             :                              errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
     644             :                                     column->colname, cxt->relation->relname),
     645             :                              parser_errposition(cxt->pstate,
     646             :                                                 constraint->location)));
     647        1162 :                 column->raw_default = constraint->raw_expr;
     648             :                 Assert(constraint->cooked_expr == NULL);
     649        1162 :                 saw_default = true;
     650        1162 :                 break;
     651             : 
     652             :             case CONSTR_IDENTITY:
     653             :                 {
     654             :                     Type        ctype;
     655             :                     Oid         typeOid;
     656             : 
     657          92 :                     if (cxt->ofType)
     658           4 :                         ereport(ERROR,
     659             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     660             :                                  errmsg("identity columns are not supported on typed tables")));
     661          88 :                     if (cxt->partbound)
     662           4 :                         ereport(ERROR,
     663             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     664             :                                  errmsg("identity columns are not supported on partitions")));
     665             : 
     666          84 :                     ctype = typenameType(cxt->pstate, column->typeName, NULL);
     667          84 :                     typeOid = ((Form_pg_type) GETSTRUCT(ctype))->oid;
     668          84 :                     ReleaseSysCache(ctype);
     669             : 
     670          84 :                     if (saw_identity)
     671           4 :                         ereport(ERROR,
     672             :                                 (errcode(ERRCODE_SYNTAX_ERROR),
     673             :                                  errmsg("multiple identity specifications for column \"%s\" of table \"%s\"",
     674             :                                         column->colname, cxt->relation->relname),
     675             :                                  parser_errposition(cxt->pstate,
     676             :                                                     constraint->location)));
     677             : 
     678          80 :                     generateSerialExtraStmts(cxt, column,
     679             :                                              typeOid, constraint->options, true,
     680             :                                              NULL, NULL);
     681             : 
     682          80 :                     column->identity = constraint->generated_when;
     683          80 :                     saw_identity = true;
     684          80 :                     column->is_not_null = true;
     685          80 :                     break;
     686             :                 }
     687             : 
     688             :             case CONSTR_CHECK:
     689         170 :                 cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
     690         170 :                 break;
     691             : 
     692             :             case CONSTR_PRIMARY:
     693        3034 :                 if (cxt->isforeign)
     694           4 :                     ereport(ERROR,
     695             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     696             :                              errmsg("primary key constraints are not supported on foreign tables"),
     697             :                              parser_errposition(cxt->pstate,
     698             :                                                 constraint->location)));
     699             :                 /* FALL THRU */
     700             : 
     701             :             case CONSTR_UNIQUE:
     702        3194 :                 if (cxt->isforeign)
     703           0 :                     ereport(ERROR,
     704             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     705             :                              errmsg("unique constraints are not supported on foreign tables"),
     706             :                              parser_errposition(cxt->pstate,
     707             :                                                 constraint->location)));
     708        3194 :                 if (constraint->keys == NIL)
     709        3194 :                     constraint->keys = list_make1(makeString(column->colname));
     710        3194 :                 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
     711        3194 :                 break;
     712             : 
     713             :             case CONSTR_EXCLUSION:
     714             :                 /* grammar does not allow EXCLUDE as a column constraint */
     715           0 :                 elog(ERROR, "column exclusion constraints are not supported");
     716             :                 break;
     717             : 
     718             :             case CONSTR_FOREIGN:
     719         346 :                 if (cxt->isforeign)
     720           4 :                     ereport(ERROR,
     721             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     722             :                              errmsg("foreign key constraints are not supported on foreign tables"),
     723             :                              parser_errposition(cxt->pstate,
     724             :                                                 constraint->location)));
     725             : 
     726             :                 /*
     727             :                  * Fill in the current attribute's name and throw it into the
     728             :                  * list of FK constraints to be processed later.
     729             :                  */
     730         342 :                 constraint->fk_attrs = list_make1(makeString(column->colname));
     731         342 :                 cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
     732         342 :                 break;
     733             : 
     734             :             case CONSTR_ATTR_DEFERRABLE:
     735             :             case CONSTR_ATTR_NOT_DEFERRABLE:
     736             :             case CONSTR_ATTR_DEFERRED:
     737             :             case CONSTR_ATTR_IMMEDIATE:
     738             :                 /* transformConstraintAttrs took care of these */
     739          56 :                 break;
     740             : 
     741             :             default:
     742           0 :                 elog(ERROR, "unrecognized constraint type: %d",
     743             :                      constraint->contype);
     744             :                 break;
     745             :         }
     746             : 
     747        9518 :         if (saw_default && saw_identity)
     748           8 :             ereport(ERROR,
     749             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     750             :                      errmsg("both default and identity specified for column \"%s\" of table \"%s\"",
     751             :                             column->colname, cxt->relation->relname),
     752             :                      parser_errposition(cxt->pstate,
     753             :                                         constraint->location)));
     754             :     }
     755             : 
     756             :     /*
     757             :      * If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
     758             :      * per-column foreign data wrapper options to this column after creation.
     759             :      */
     760       44984 :     if (column->fdwoptions != NIL)
     761             :     {
     762             :         AlterTableStmt *stmt;
     763             :         AlterTableCmd *cmd;
     764             : 
     765         124 :         cmd = makeNode(AlterTableCmd);
     766         124 :         cmd->subtype = AT_AlterColumnGenericOptions;
     767         124 :         cmd->name = column->colname;
     768         124 :         cmd->def = (Node *) column->fdwoptions;
     769         124 :         cmd->behavior = DROP_RESTRICT;
     770         124 :         cmd->missing_ok = false;
     771             : 
     772         124 :         stmt = makeNode(AlterTableStmt);
     773         124 :         stmt->relation = cxt->relation;
     774         124 :         stmt->cmds = NIL;
     775         124 :         stmt->relkind = OBJECT_FOREIGN_TABLE;
     776         124 :         stmt->cmds = lappend(stmt->cmds, cmd);
     777             : 
     778         124 :         cxt->alist = lappend(cxt->alist, stmt);
     779             :     }
     780       44984 : }
     781             : 
     782             : /*
     783             :  * transformTableConstraint
     784             :  *      transform a Constraint node within CREATE TABLE or ALTER TABLE
     785             :  */
     786             : static void
     787        2468 : transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
     788             : {
     789        2468 :     switch (constraint->contype)
     790             :     {
     791             :         case CONSTR_PRIMARY:
     792         796 :             if (cxt->isforeign)
     793           4 :                 ereport(ERROR,
     794             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     795             :                          errmsg("primary key constraints are not supported on foreign tables"),
     796             :                          parser_errposition(cxt->pstate,
     797             :                                             constraint->location)));
     798         792 :             cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
     799         792 :             break;
     800             : 
     801             :         case CONSTR_UNIQUE:
     802         200 :             if (cxt->isforeign)
     803           4 :                 ereport(ERROR,
     804             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     805             :                          errmsg("unique constraints are not supported on foreign tables"),
     806             :                          parser_errposition(cxt->pstate,
     807             :                                             constraint->location)));
     808         196 :             cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
     809         196 :             break;
     810             : 
     811             :         case CONSTR_EXCLUSION:
     812          60 :             if (cxt->isforeign)
     813           0 :                 ereport(ERROR,
     814             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     815             :                          errmsg("exclusion constraints are not supported on foreign tables"),
     816             :                          parser_errposition(cxt->pstate,
     817             :                                             constraint->location)));
     818          60 :             if (cxt->ispartitioned)
     819          16 :                 ereport(ERROR,
     820             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     821             :                          errmsg("exclusion constraints are not supported on partitioned tables"),
     822             :                          parser_errposition(cxt->pstate,
     823             :                                             constraint->location)));
     824          44 :             cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
     825          44 :             break;
     826             : 
     827             :         case CONSTR_CHECK:
     828         556 :             cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
     829         556 :             break;
     830             : 
     831             :         case CONSTR_FOREIGN:
     832         856 :             if (cxt->isforeign)
     833           0 :                 ereport(ERROR,
     834             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     835             :                          errmsg("foreign key constraints are not supported on foreign tables"),
     836             :                          parser_errposition(cxt->pstate,
     837             :                                             constraint->location)));
     838         856 :             cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
     839         856 :             break;
     840             : 
     841             :         case CONSTR_NULL:
     842             :         case CONSTR_NOTNULL:
     843             :         case CONSTR_DEFAULT:
     844             :         case CONSTR_ATTR_DEFERRABLE:
     845             :         case CONSTR_ATTR_NOT_DEFERRABLE:
     846             :         case CONSTR_ATTR_DEFERRED:
     847             :         case CONSTR_ATTR_IMMEDIATE:
     848           0 :             elog(ERROR, "invalid context for constraint type %d",
     849             :                  constraint->contype);
     850             :             break;
     851             : 
     852             :         default:
     853           0 :             elog(ERROR, "unrecognized constraint type: %d",
     854             :                  constraint->contype);
     855             :             break;
     856             :     }
     857        2444 : }
     858             : 
     859             : /*
     860             :  * transformTableLikeClause
     861             :  *
     862             :  * Change the LIKE <srctable> portion of a CREATE TABLE statement into
     863             :  * column definitions which recreate the user defined column portions of
     864             :  * <srctable>.
     865             :  */
     866             : static void
     867         310 : transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_clause)
     868             : {
     869             :     AttrNumber  parent_attno;
     870             :     Relation    relation;
     871             :     TupleDesc   tupleDesc;
     872             :     TupleConstr *constr;
     873             :     AttrNumber *attmap;
     874             :     AclResult   aclresult;
     875             :     char       *comment;
     876             :     ParseCallbackState pcbstate;
     877             : 
     878         310 :     setup_parser_errposition_callback(&pcbstate, cxt->pstate,
     879         310 :                                       table_like_clause->relation->location);
     880             : 
     881             :     /* we could support LIKE in many cases, but worry about it another day */
     882         310 :     if (cxt->isforeign)
     883           0 :         ereport(ERROR,
     884             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     885             :                  errmsg("LIKE is not supported for creating foreign tables")));
     886             : 
     887         310 :     relation = relation_openrv(table_like_clause->relation, AccessShareLock);
     888             : 
     889         488 :     if (relation->rd_rel->relkind != RELKIND_RELATION &&
     890         356 :         relation->rd_rel->relkind != RELKIND_VIEW &&
     891         348 :         relation->rd_rel->relkind != RELKIND_MATVIEW &&
     892         344 :         relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
     893         340 :         relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
     894         170 :         relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
     895           4 :         ereport(ERROR,
     896             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     897             :                  errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
     898             :                         RelationGetRelationName(relation))));
     899             : 
     900         302 :     cancel_parser_errposition_callback(&pcbstate);
     901             : 
     902             :     /*
     903             :      * Check for privileges
     904             :      */
     905         302 :     if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
     906             :     {
     907           4 :         aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(),
     908             :                                      ACL_USAGE);
     909           4 :         if (aclresult != ACLCHECK_OK)
     910           0 :             aclcheck_error(aclresult, OBJECT_TYPE,
     911           0 :                            RelationGetRelationName(relation));
     912             :     }
     913             :     else
     914             :     {
     915         298 :         aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
     916             :                                       ACL_SELECT);
     917         298 :         if (aclresult != ACLCHECK_OK)
     918           0 :             aclcheck_error(aclresult, get_relkind_objtype(relation->rd_rel->relkind),
     919           0 :                            RelationGetRelationName(relation));
     920             :     }
     921             : 
     922         302 :     tupleDesc = RelationGetDescr(relation);
     923         302 :     constr = tupleDesc->constr;
     924             : 
     925             :     /*
     926             :      * Initialize column number map for map_variable_attnos().  We need this
     927             :      * since dropped columns in the source table aren't copied, so the new
     928             :      * table can have different column numbers.
     929             :      */
     930         302 :     attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) * tupleDesc->natts);
     931             : 
     932             :     /*
     933             :      * Insert the copied attributes into the cxt for the new table definition.
     934             :      */
     935        1238 :     for (parent_attno = 1; parent_attno <= tupleDesc->natts;
     936         634 :          parent_attno++)
     937             :     {
     938         634 :         Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
     939             :                                                     parent_attno - 1);
     940         634 :         char       *attributeName = NameStr(attribute->attname);
     941             :         ColumnDef  *def;
     942             : 
     943             :         /*
     944             :          * Ignore dropped columns in the parent.  attmap entry is left zero.
     945             :          */
     946         634 :         if (attribute->attisdropped)
     947           0 :             continue;
     948             : 
     949             :         /*
     950             :          * Create a new column, which is marked as NOT inherited.
     951             :          *
     952             :          * For constraints, ONLY the NOT NULL constraint is inherited by the
     953             :          * new column definition per SQL99.
     954             :          */
     955         634 :         def = makeNode(ColumnDef);
     956         634 :         def->colname = pstrdup(attributeName);
     957         634 :         def->typeName = makeTypeNameFromOid(attribute->atttypid,
     958             :                                             attribute->atttypmod);
     959         634 :         def->inhcount = 0;
     960         634 :         def->is_local = true;
     961         634 :         def->is_not_null = attribute->attnotnull;
     962         634 :         def->is_from_type = false;
     963         634 :         def->storage = 0;
     964         634 :         def->raw_default = NULL;
     965         634 :         def->cooked_default = NULL;
     966         634 :         def->collClause = NULL;
     967         634 :         def->collOid = attribute->attcollation;
     968         634 :         def->constraints = NIL;
     969         634 :         def->location = -1;
     970             : 
     971             :         /*
     972             :          * Add to column list
     973             :          */
     974         634 :         cxt->columns = lappend(cxt->columns, def);
     975             : 
     976         634 :         attmap[parent_attno - 1] = list_length(cxt->columns);
     977             : 
     978             :         /*
     979             :          * Copy default, if present and the default has been requested
     980             :          */
     981         678 :         if (attribute->atthasdef &&
     982          44 :             (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS))
     983             :         {
     984           6 :             Node       *this_default = NULL;
     985             :             AttrDefault *attrdef;
     986             :             int         i;
     987             : 
     988             :             /* Find default in constraint structure */
     989             :             Assert(constr != NULL);
     990           6 :             attrdef = constr->defval;
     991           6 :             for (i = 0; i < constr->num_defval; i++)
     992             :             {
     993           6 :                 if (attrdef[i].adnum == parent_attno)
     994             :                 {
     995           6 :                     this_default = stringToNode(attrdef[i].adbin);
     996           6 :                     break;
     997             :                 }
     998             :             }
     999             :             Assert(this_default != NULL);
    1000             : 
    1001             :             /*
    1002             :              * If default expr could contain any vars, we'd need to fix 'em,
    1003             :              * but it can't; so default is ready to apply to child.
    1004             :              */
    1005             : 
    1006           6 :             def->cooked_default = this_default;
    1007             :         }
    1008             : 
    1009             :         /*
    1010             :          * Copy identity if requested
    1011             :          */
    1012         642 :         if (attribute->attidentity &&
    1013           8 :             (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY))
    1014             :         {
    1015             :             Oid         seq_relid;
    1016             :             List       *seq_options;
    1017             : 
    1018             :             /*
    1019             :              * find sequence owned by old column; extract sequence parameters;
    1020             :              * build new create sequence command
    1021             :              */
    1022           4 :             seq_relid = getOwnedSequence(RelationGetRelid(relation), attribute->attnum);
    1023           4 :             seq_options = sequence_options(seq_relid);
    1024           4 :             generateSerialExtraStmts(cxt, def,
    1025             :                                      InvalidOid, seq_options, true,
    1026             :                                      NULL, NULL);
    1027           4 :             def->identity = attribute->attidentity;
    1028             :         }
    1029             : 
    1030             :         /* Likewise, copy storage if requested */
    1031         634 :         if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE)
    1032          60 :             def->storage = attribute->attstorage;
    1033             :         else
    1034         574 :             def->storage = 0;
    1035             : 
    1036             :         /* Likewise, copy comment if requested */
    1037         682 :         if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
    1038          48 :             (comment = GetComment(attribute->attrelid,
    1039             :                                   RelationRelationId,
    1040          48 :                                   attribute->attnum)) != NULL)
    1041             :         {
    1042          36 :             CommentStmt *stmt = makeNode(CommentStmt);
    1043             : 
    1044          36 :             stmt->objtype = OBJECT_COLUMN;
    1045          36 :             stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
    1046             :                                                makeString(cxt->relation->relname),
    1047             :                                                makeString(def->colname));
    1048          36 :             stmt->comment = comment;
    1049             : 
    1050          36 :             cxt->alist = lappend(cxt->alist, stmt);
    1051             :         }
    1052             :     }
    1053             : 
    1054             :     /*
    1055             :      * Copy CHECK constraints if requested, being careful to adjust attribute
    1056             :      * numbers so they match the child.
    1057             :      */
    1058         346 :     if ((table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) &&
    1059          44 :         tupleDesc->constr)
    1060             :     {
    1061             :         int         ccnum;
    1062             : 
    1063          80 :         for (ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++)
    1064             :         {
    1065          40 :             char       *ccname = tupleDesc->constr->check[ccnum].ccname;
    1066          40 :             char       *ccbin = tupleDesc->constr->check[ccnum].ccbin;
    1067          40 :             Constraint *n = makeNode(Constraint);
    1068             :             Node       *ccbin_node;
    1069             :             bool        found_whole_row;
    1070             : 
    1071          40 :             ccbin_node = map_variable_attnos(stringToNode(ccbin),
    1072             :                                              1, 0,
    1073             :                                              attmap, tupleDesc->natts,
    1074             :                                              InvalidOid, &found_whole_row);
    1075             : 
    1076             :             /*
    1077             :              * We reject whole-row variables because the whole point of LIKE
    1078             :              * is that the new table's rowtype might later diverge from the
    1079             :              * parent's.  So, while translation might be possible right now,
    1080             :              * it wouldn't be possible to guarantee it would work in future.
    1081             :              */
    1082          40 :             if (found_whole_row)
    1083           0 :                 ereport(ERROR,
    1084             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1085             :                          errmsg("cannot convert whole-row table reference"),
    1086             :                          errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
    1087             :                                    ccname,
    1088             :                                    RelationGetRelationName(relation))));
    1089             : 
    1090          40 :             n->contype = CONSTR_CHECK;
    1091          40 :             n->location = -1;
    1092          40 :             n->conname = pstrdup(ccname);
    1093          40 :             n->raw_expr = NULL;
    1094          40 :             n->cooked_expr = nodeToString(ccbin_node);
    1095          40 :             cxt->ckconstraints = lappend(cxt->ckconstraints, n);
    1096             : 
    1097             :             /* Copy comment on constraint */
    1098          56 :             if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
    1099          16 :                 (comment = GetComment(get_relation_constraint_oid(RelationGetRelid(relation),
    1100          16 :                                                                   n->conname, false),
    1101             :                                       ConstraintRelationId,
    1102             :                                       0)) != NULL)
    1103             :             {
    1104          12 :                 CommentStmt *stmt = makeNode(CommentStmt);
    1105             : 
    1106          12 :                 stmt->objtype = OBJECT_TABCONSTRAINT;
    1107          12 :                 stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
    1108             :                                                    makeString(cxt->relation->relname),
    1109             :                                                    makeString(n->conname));
    1110          12 :                 stmt->comment = comment;
    1111             : 
    1112          12 :                 cxt->alist = lappend(cxt->alist, stmt);
    1113             :             }
    1114             :         }
    1115             :     }
    1116             : 
    1117             :     /*
    1118             :      * Likewise, copy indexes if requested
    1119             :      */
    1120         332 :     if ((table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) &&
    1121          30 :         relation->rd_rel->relhasindex)
    1122             :     {
    1123             :         List       *parent_indexes;
    1124             :         ListCell   *l;
    1125             : 
    1126          26 :         parent_indexes = RelationGetIndexList(relation);
    1127             : 
    1128          70 :         foreach(l, parent_indexes)
    1129             :         {
    1130          44 :             Oid         parent_index_oid = lfirst_oid(l);
    1131             :             Relation    parent_index;
    1132             :             IndexStmt  *index_stmt;
    1133             : 
    1134          44 :             parent_index = index_open(parent_index_oid, AccessShareLock);
    1135             : 
    1136             :             /* Build CREATE INDEX statement to recreate the parent_index */
    1137          44 :             index_stmt = generateClonedIndexStmt(cxt->relation, InvalidOid,
    1138             :                                                  parent_index,
    1139             :                                                  attmap, tupleDesc->natts, NULL);
    1140             : 
    1141             :             /* Copy comment on index, if requested */
    1142          44 :             if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
    1143             :             {
    1144          16 :                 comment = GetComment(parent_index_oid, RelationRelationId, 0);
    1145             : 
    1146             :                 /*
    1147             :                  * We make use of IndexStmt's idxcomment option, so as not to
    1148             :                  * need to know now what name the index will have.
    1149             :                  */
    1150          16 :                 index_stmt->idxcomment = comment;
    1151             :             }
    1152             : 
    1153             :             /* Save it in the inh_indexes list for the time being */
    1154          44 :             cxt->inh_indexes = lappend(cxt->inh_indexes, index_stmt);
    1155             : 
    1156          44 :             index_close(parent_index, AccessShareLock);
    1157             :         }
    1158             :     }
    1159             : 
    1160             :     /*
    1161             :      * Likewise, copy extended statistics if requested
    1162             :      */
    1163         302 :     if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS)
    1164             :     {
    1165             :         List       *parent_extstats;
    1166             :         ListCell   *l;
    1167             : 
    1168          12 :         parent_extstats = RelationGetStatExtList(relation);
    1169             : 
    1170          16 :         foreach(l, parent_extstats)
    1171             :         {
    1172           4 :             Oid         parent_stat_oid = lfirst_oid(l);
    1173             :             CreateStatsStmt *stats_stmt;
    1174             : 
    1175           4 :             stats_stmt = generateClonedExtStatsStmt(cxt->relation,
    1176             :                                                     RelationGetRelid(relation),
    1177             :                                                     parent_stat_oid);
    1178             : 
    1179             :             /* Copy comment on statistics object, if requested */
    1180           4 :             if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
    1181             :             {
    1182           4 :                 comment = GetComment(parent_stat_oid, StatisticExtRelationId, 0);
    1183             : 
    1184             :                 /*
    1185             :                  * We make use of CreateStatsStmt's stxcomment option, so as
    1186             :                  * not to need to know now what name the statistics will have.
    1187             :                  */
    1188           4 :                 stats_stmt->stxcomment = comment;
    1189             :             }
    1190             : 
    1191           4 :             cxt->extstats = lappend(cxt->extstats, stats_stmt);
    1192             :         }
    1193             : 
    1194          12 :         list_free(parent_extstats);
    1195             :     }
    1196             : 
    1197             :     /*
    1198             :      * Close the parent rel, but keep our AccessShareLock on it until xact
    1199             :      * commit.  That will prevent someone else from deleting or ALTERing the
    1200             :      * parent before the child is committed.
    1201             :      */
    1202         302 :     heap_close(relation, NoLock);
    1203         302 : }
    1204             : 
    1205             : static void
    1206          70 : transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
    1207             : {
    1208             :     HeapTuple   tuple;
    1209             :     TupleDesc   tupdesc;
    1210             :     int         i;
    1211             :     Oid         ofTypeId;
    1212             : 
    1213             :     AssertArg(ofTypename);
    1214             : 
    1215          70 :     tuple = typenameType(NULL, ofTypename, NULL);
    1216          66 :     check_of_type(tuple);
    1217          62 :     ofTypeId = ((Form_pg_type) GETSTRUCT(tuple))->oid;
    1218          62 :     ofTypename->typeOid = ofTypeId; /* cached for later */
    1219             : 
    1220          62 :     tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
    1221         178 :     for (i = 0; i < tupdesc->natts; i++)
    1222             :     {
    1223         116 :         Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
    1224             :         ColumnDef  *n;
    1225             : 
    1226         116 :         if (attr->attisdropped)
    1227           0 :             continue;
    1228             : 
    1229         116 :         n = makeNode(ColumnDef);
    1230         116 :         n->colname = pstrdup(NameStr(attr->attname));
    1231         116 :         n->typeName = makeTypeNameFromOid(attr->atttypid, attr->atttypmod);
    1232         116 :         n->inhcount = 0;
    1233         116 :         n->is_local = true;
    1234         116 :         n->is_not_null = false;
    1235         116 :         n->is_from_type = true;
    1236         116 :         n->storage = 0;
    1237         116 :         n->raw_default = NULL;
    1238         116 :         n->cooked_default = NULL;
    1239         116 :         n->collClause = NULL;
    1240         116 :         n->collOid = attr->attcollation;
    1241         116 :         n->constraints = NIL;
    1242         116 :         n->location = -1;
    1243         116 :         cxt->columns = lappend(cxt->columns, n);
    1244             :     }
    1245          62 :     DecrTupleDescRefCount(tupdesc);
    1246             : 
    1247          62 :     ReleaseSysCache(tuple);
    1248          62 : }
    1249             : 
    1250             : /*
    1251             :  * Generate an IndexStmt node using information from an already existing index
    1252             :  * "source_idx", for the rel identified either by heapRel or heapRelid.
    1253             :  *
    1254             :  * Attribute numbers should be adjusted according to attmap.
    1255             :  */
    1256             : IndexStmt *
    1257         336 : generateClonedIndexStmt(RangeVar *heapRel, Oid heapRelid, Relation source_idx,
    1258             :                         const AttrNumber *attmap, int attmap_length, Oid *constraintOid)
    1259             : {
    1260         336 :     Oid         source_relid = RelationGetRelid(source_idx);
    1261             :     HeapTuple   ht_idxrel;
    1262             :     HeapTuple   ht_idx;
    1263             :     HeapTuple   ht_am;
    1264             :     Form_pg_class idxrelrec;
    1265             :     Form_pg_index idxrec;
    1266             :     Form_pg_am  amrec;
    1267             :     oidvector  *indcollation;
    1268             :     oidvector  *indclass;
    1269             :     IndexStmt  *index;
    1270             :     List       *indexprs;
    1271             :     ListCell   *indexpr_item;
    1272             :     Oid         indrelid;
    1273             :     int         keyno;
    1274             :     Oid         keycoltype;
    1275             :     Datum       datum;
    1276             :     bool        isnull;
    1277             : 
    1278             :     Assert((heapRel == NULL && OidIsValid(heapRelid)) ||
    1279             :            (heapRel != NULL && !OidIsValid(heapRelid)));
    1280             : 
    1281             :     /*
    1282             :      * Fetch pg_class tuple of source index.  We can't use the copy in the
    1283             :      * relcache entry because it doesn't include optional fields.
    1284             :      */
    1285         336 :     ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(source_relid));
    1286         336 :     if (!HeapTupleIsValid(ht_idxrel))
    1287           0 :         elog(ERROR, "cache lookup failed for relation %u", source_relid);
    1288         336 :     idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
    1289             : 
    1290             :     /* Fetch pg_index tuple for source index from relcache entry */
    1291         336 :     ht_idx = source_idx->rd_indextuple;
    1292         336 :     idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
    1293         336 :     indrelid = idxrec->indrelid;
    1294             : 
    1295             :     /* Fetch the pg_am tuple of the index' access method */
    1296         336 :     ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
    1297         336 :     if (!HeapTupleIsValid(ht_am))
    1298           0 :         elog(ERROR, "cache lookup failed for access method %u",
    1299             :              idxrelrec->relam);
    1300         336 :     amrec = (Form_pg_am) GETSTRUCT(ht_am);
    1301             : 
    1302             :     /* Extract indcollation from the pg_index tuple */
    1303         336 :     datum = SysCacheGetAttr(INDEXRELID, ht_idx,
    1304             :                             Anum_pg_index_indcollation, &isnull);
    1305             :     Assert(!isnull);
    1306         336 :     indcollation = (oidvector *) DatumGetPointer(datum);
    1307             : 
    1308             :     /* Extract indclass from the pg_index tuple */
    1309         336 :     datum = SysCacheGetAttr(INDEXRELID, ht_idx,
    1310             :                             Anum_pg_index_indclass, &isnull);
    1311             :     Assert(!isnull);
    1312         336 :     indclass = (oidvector *) DatumGetPointer(datum);
    1313             : 
    1314             :     /* Begin building the IndexStmt */
    1315         336 :     index = makeNode(IndexStmt);
    1316         336 :     index->relation = heapRel;
    1317         336 :     index->accessMethod = pstrdup(NameStr(amrec->amname));
    1318         336 :     if (OidIsValid(idxrelrec->reltablespace))
    1319           4 :         index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
    1320             :     else
    1321         332 :         index->tableSpace = NULL;
    1322         336 :     index->excludeOpNames = NIL;
    1323         336 :     index->idxcomment = NULL;
    1324         336 :     index->indexOid = InvalidOid;
    1325         336 :     index->oldNode = InvalidOid;
    1326         336 :     index->unique = idxrec->indisunique;
    1327         336 :     index->primary = idxrec->indisprimary;
    1328         336 :     index->transformed = true;   /* don't need transformIndexStmt */
    1329         336 :     index->concurrent = false;
    1330         336 :     index->if_not_exists = false;
    1331             : 
    1332             :     /*
    1333             :      * We don't try to preserve the name of the source index; instead, just
    1334             :      * let DefineIndex() choose a reasonable name.  (If we tried to preserve
    1335             :      * the name, we'd get duplicate-relation-name failures unless the source
    1336             :      * table was in a different schema.)
    1337             :      */
    1338         336 :     index->idxname = NULL;
    1339             : 
    1340             :     /*
    1341             :      * If the index is marked PRIMARY or has an exclusion condition, it's
    1342             :      * certainly from a constraint; else, if it's not marked UNIQUE, it
    1343             :      * certainly isn't.  If it is or might be from a constraint, we have to
    1344             :      * fetch the pg_constraint record.
    1345             :      */
    1346         336 :     if (index->primary || index->unique || idxrec->indisexclusion)
    1347         240 :     {
    1348         240 :         Oid         constraintId = get_index_constraint(source_relid);
    1349             : 
    1350         240 :         if (OidIsValid(constraintId))
    1351             :         {
    1352             :             HeapTuple   ht_constr;
    1353             :             Form_pg_constraint conrec;
    1354             : 
    1355         216 :             if (constraintOid)
    1356         192 :                 *constraintOid = constraintId;
    1357             : 
    1358         216 :             ht_constr = SearchSysCache1(CONSTROID,
    1359             :                                         ObjectIdGetDatum(constraintId));
    1360         216 :             if (!HeapTupleIsValid(ht_constr))
    1361           0 :                 elog(ERROR, "cache lookup failed for constraint %u",
    1362             :                      constraintId);
    1363         216 :             conrec = (Form_pg_constraint) GETSTRUCT(ht_constr);
    1364             : 
    1365         216 :             index->isconstraint = true;
    1366         216 :             index->deferrable = conrec->condeferrable;
    1367         216 :             index->initdeferred = conrec->condeferred;
    1368             : 
    1369             :             /* If it's an exclusion constraint, we need the operator names */
    1370         216 :             if (idxrec->indisexclusion)
    1371             :             {
    1372             :                 Datum      *elems;
    1373             :                 int         nElems;
    1374             :                 int         i;
    1375             : 
    1376             :                 Assert(conrec->contype == CONSTRAINT_EXCLUSION);
    1377             :                 /* Extract operator OIDs from the pg_constraint tuple */
    1378           2 :                 datum = SysCacheGetAttr(CONSTROID, ht_constr,
    1379             :                                         Anum_pg_constraint_conexclop,
    1380             :                                         &isnull);
    1381           2 :                 if (isnull)
    1382           0 :                     elog(ERROR, "null conexclop for constraint %u",
    1383             :                          constraintId);
    1384             : 
    1385           2 :                 deconstruct_array(DatumGetArrayTypeP(datum),
    1386             :                                   OIDOID, sizeof(Oid), true, 'i',
    1387             :                                   &elems, NULL, &nElems);
    1388             : 
    1389           4 :                 for (i = 0; i < nElems; i++)
    1390             :                 {
    1391           2 :                     Oid         operid = DatumGetObjectId(elems[i]);
    1392             :                     HeapTuple   opertup;
    1393             :                     Form_pg_operator operform;
    1394             :                     char       *oprname;
    1395             :                     char       *nspname;
    1396             :                     List       *namelist;
    1397             : 
    1398           2 :                     opertup = SearchSysCache1(OPEROID,
    1399             :                                               ObjectIdGetDatum(operid));
    1400           2 :                     if (!HeapTupleIsValid(opertup))
    1401           0 :                         elog(ERROR, "cache lookup failed for operator %u",
    1402             :                              operid);
    1403           2 :                     operform = (Form_pg_operator) GETSTRUCT(opertup);
    1404           2 :                     oprname = pstrdup(NameStr(operform->oprname));
    1405             :                     /* For simplicity we always schema-qualify the op name */
    1406           2 :                     nspname = get_namespace_name(operform->oprnamespace);
    1407           2 :                     namelist = list_make2(makeString(nspname),
    1408             :                                           makeString(oprname));
    1409           2 :                     index->excludeOpNames = lappend(index->excludeOpNames,
    1410             :                                                     namelist);
    1411           2 :                     ReleaseSysCache(opertup);
    1412             :                 }
    1413             :             }
    1414             : 
    1415         216 :             ReleaseSysCache(ht_constr);
    1416             :         }
    1417             :         else
    1418          24 :             index->isconstraint = false;
    1419             :     }
    1420             :     else
    1421          96 :         index->isconstraint = false;
    1422             : 
    1423             :     /* Get the index expressions, if any */
    1424         336 :     datum = SysCacheGetAttr(INDEXRELID, ht_idx,
    1425             :                             Anum_pg_index_indexprs, &isnull);
    1426         336 :     if (!isnull)
    1427             :     {
    1428             :         char       *exprsString;
    1429             : 
    1430          20 :         exprsString = TextDatumGetCString(datum);
    1431          20 :         indexprs = (List *) stringToNode(exprsString);
    1432             :     }
    1433             :     else
    1434         316 :         indexprs = NIL;
    1435             : 
    1436             :     /* Build the list of IndexElem */
    1437         336 :     index->indexParams = NIL;
    1438         336 :     index->indexIncludingParams = NIL;
    1439             : 
    1440         336 :     indexpr_item = list_head(indexprs);
    1441         732 :     for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++)
    1442             :     {
    1443             :         IndexElem  *iparam;
    1444         396 :         AttrNumber  attnum = idxrec->indkey.values[keyno];
    1445         396 :         Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
    1446             :                                                keyno);
    1447         396 :         int16       opt = source_idx->rd_indoption[keyno];
    1448             : 
    1449         396 :         iparam = makeNode(IndexElem);
    1450             : 
    1451         396 :         if (AttributeNumberIsValid(attnum))
    1452             :         {
    1453             :             /* Simple index column */
    1454             :             char       *attname;
    1455             : 
    1456         376 :             attname = get_attname(indrelid, attnum, false);
    1457         376 :             keycoltype = get_atttype(indrelid, attnum);
    1458             : 
    1459         376 :             iparam->name = attname;
    1460         376 :             iparam->expr = NULL;
    1461             :         }
    1462             :         else
    1463             :         {
    1464             :             /* Expressional index */
    1465             :             Node       *indexkey;
    1466             :             bool        found_whole_row;
    1467             : 
    1468          20 :             if (indexpr_item == NULL)
    1469           0 :                 elog(ERROR, "too few entries in indexprs list");
    1470          20 :             indexkey = (Node *) lfirst(indexpr_item);
    1471          20 :             indexpr_item = lnext(indexpr_item);
    1472             : 
    1473             :             /* Adjust Vars to match new table's column numbering */
    1474          20 :             indexkey = map_variable_attnos(indexkey,
    1475             :                                            1, 0,
    1476             :                                            attmap, attmap_length,
    1477             :                                            InvalidOid, &found_whole_row);
    1478             : 
    1479             :             /* As in transformTableLikeClause, reject whole-row variables */
    1480          20 :             if (found_whole_row)
    1481           0 :                 ereport(ERROR,
    1482             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1483             :                          errmsg("cannot convert whole-row table reference"),
    1484             :                          errdetail("Index \"%s\" contains a whole-row table reference.",
    1485             :                                    RelationGetRelationName(source_idx))));
    1486             : 
    1487          20 :             iparam->name = NULL;
    1488          20 :             iparam->expr = indexkey;
    1489             : 
    1490          20 :             keycoltype = exprType(indexkey);
    1491             :         }
    1492             : 
    1493             :         /* Copy the original index column name */
    1494         396 :         iparam->indexcolname = pstrdup(NameStr(attr->attname));
    1495             : 
    1496             :         /* Add the collation name, if non-default */
    1497         396 :         iparam->collation = get_collation(indcollation->values[keyno], keycoltype);
    1498             : 
    1499             :         /* Add the operator class name, if non-default */
    1500         396 :         iparam->opclass = get_opclass(indclass->values[keyno], keycoltype);
    1501             : 
    1502         396 :         iparam->ordering = SORTBY_DEFAULT;
    1503         396 :         iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
    1504             : 
    1505             :         /* Adjust options if necessary */
    1506         396 :         if (source_idx->rd_amroutine->amcanorder)
    1507             :         {
    1508             :             /*
    1509             :              * If it supports sort ordering, copy DESC and NULLS opts. Don't
    1510             :              * set non-default settings unnecessarily, though, so as to
    1511             :              * improve the chance of recognizing equivalence to constraint
    1512             :              * indexes.
    1513             :              */
    1514         396 :             if (opt & INDOPTION_DESC)
    1515             :             {
    1516           0 :                 iparam->ordering = SORTBY_DESC;
    1517           0 :                 if ((opt & INDOPTION_NULLS_FIRST) == 0)
    1518           0 :                     iparam->nulls_ordering = SORTBY_NULLS_LAST;
    1519             :             }
    1520             :             else
    1521             :             {
    1522         396 :                 if (opt & INDOPTION_NULLS_FIRST)
    1523           0 :                     iparam->nulls_ordering = SORTBY_NULLS_FIRST;
    1524             :             }
    1525             :         }
    1526             : 
    1527         396 :         index->indexParams = lappend(index->indexParams, iparam);
    1528             :     }
    1529             : 
    1530             :     /* Handle included columns separately */
    1531         348 :     for (keyno = idxrec->indnkeyatts; keyno < idxrec->indnatts; keyno++)
    1532             :     {
    1533             :         IndexElem  *iparam;
    1534          12 :         AttrNumber  attnum = idxrec->indkey.values[keyno];
    1535          12 :         Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
    1536             :                                                keyno);
    1537             : 
    1538          12 :         iparam = makeNode(IndexElem);
    1539             : 
    1540          12 :         if (AttributeNumberIsValid(attnum))
    1541             :         {
    1542             :             /* Simple index column */
    1543             :             char       *attname;
    1544             : 
    1545          12 :             attname = get_attname(indrelid, attnum, false);
    1546          12 :             keycoltype = get_atttype(indrelid, attnum);
    1547             : 
    1548          12 :             iparam->name = attname;
    1549          12 :             iparam->expr = NULL;
    1550             :         }
    1551             :         else
    1552           0 :             ereport(ERROR,
    1553             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1554             :                      errmsg("expressions are not supported in included columns")));
    1555             : 
    1556             :         /* Copy the original index column name */
    1557          12 :         iparam->indexcolname = pstrdup(NameStr(attr->attname));
    1558             : 
    1559          12 :         index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
    1560             :     }
    1561             :     /* Copy reloptions if any */
    1562         336 :     datum = SysCacheGetAttr(RELOID, ht_idxrel,
    1563             :                             Anum_pg_class_reloptions, &isnull);
    1564         336 :     if (!isnull)
    1565           0 :         index->options = untransformRelOptions(datum);
    1566             : 
    1567             :     /* If it's a partial index, decompile and append the predicate */
    1568         336 :     datum = SysCacheGetAttr(INDEXRELID, ht_idx,
    1569             :                             Anum_pg_index_indpred, &isnull);
    1570         336 :     if (!isnull)
    1571             :     {
    1572             :         char       *pred_str;
    1573             :         Node       *pred_tree;
    1574             :         bool        found_whole_row;
    1575             : 
    1576             :         /* Convert text string to node tree */
    1577           4 :         pred_str = TextDatumGetCString(datum);
    1578           4 :         pred_tree = (Node *) stringToNode(pred_str);
    1579             : 
    1580             :         /* Adjust Vars to match new table's column numbering */
    1581           4 :         pred_tree = map_variable_attnos(pred_tree,
    1582             :                                         1, 0,
    1583             :                                         attmap, attmap_length,
    1584             :                                         InvalidOid, &found_whole_row);
    1585             : 
    1586             :         /* As in transformTableLikeClause, reject whole-row variables */
    1587           4 :         if (found_whole_row)
    1588           0 :             ereport(ERROR,
    1589             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1590             :                      errmsg("cannot convert whole-row table reference"),
    1591             :                      errdetail("Index \"%s\" contains a whole-row table reference.",
    1592             :                                RelationGetRelationName(source_idx))));
    1593             : 
    1594           4 :         index->whereClause = pred_tree;
    1595             :     }
    1596             : 
    1597             :     /* Clean up */
    1598         336 :     ReleaseSysCache(ht_idxrel);
    1599         336 :     ReleaseSysCache(ht_am);
    1600             : 
    1601         336 :     return index;
    1602             : }
    1603             : 
    1604             : /*
    1605             :  * Generate a CreateStatsStmt node using information from an already existing
    1606             :  * extended statistic "source_statsid", for the rel identified by heapRel and
    1607             :  * heapRelid.
    1608             :  */
    1609             : static CreateStatsStmt *
    1610           4 : generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid,
    1611             :                            Oid source_statsid)
    1612             : {
    1613             :     HeapTuple   ht_stats;
    1614             :     Form_pg_statistic_ext statsrec;
    1615             :     CreateStatsStmt *stats;
    1616           4 :     List       *stat_types = NIL;
    1617           4 :     List       *def_names = NIL;
    1618             :     bool        isnull;
    1619             :     Datum       datum;
    1620             :     ArrayType  *arr;
    1621             :     char       *enabled;
    1622             :     int         i;
    1623             : 
    1624             :     Assert(OidIsValid(heapRelid));
    1625             :     Assert(heapRel != NULL);
    1626             : 
    1627             :     /*
    1628             :      * Fetch pg_statistic_ext tuple of source statistics object.
    1629             :      */
    1630           4 :     ht_stats = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(source_statsid));
    1631           4 :     if (!HeapTupleIsValid(ht_stats))
    1632           0 :         elog(ERROR, "cache lookup failed for statistics object %u", source_statsid);
    1633           4 :     statsrec = (Form_pg_statistic_ext) GETSTRUCT(ht_stats);
    1634             : 
    1635             :     /* Determine which statistics types exist */
    1636           4 :     datum = SysCacheGetAttr(STATEXTOID, ht_stats,
    1637             :                             Anum_pg_statistic_ext_stxkind, &isnull);
    1638             :     Assert(!isnull);
    1639           4 :     arr = DatumGetArrayTypeP(datum);
    1640           8 :     if (ARR_NDIM(arr) != 1 ||
    1641           8 :         ARR_HASNULL(arr) ||
    1642           4 :         ARR_ELEMTYPE(arr) != CHAROID)
    1643           0 :         elog(ERROR, "stxkind is not a 1-D char array");
    1644           4 :     enabled = (char *) ARR_DATA_PTR(arr);
    1645          12 :     for (i = 0; i < ARR_DIMS(arr)[0]; i++)
    1646             :     {
    1647           8 :         if (enabled[i] == STATS_EXT_NDISTINCT)
    1648           4 :             stat_types = lappend(stat_types, makeString("ndistinct"));
    1649           4 :         else if (enabled[i] == STATS_EXT_DEPENDENCIES)
    1650           4 :             stat_types = lappend(stat_types, makeString("dependencies"));
    1651             :         else
    1652           0 :             elog(ERROR, "unrecognized statistics kind %c", enabled[i]);
    1653             :     }
    1654             : 
    1655             :     /* Determine which columns the statistics are on */
    1656          12 :     for (i = 0; i < statsrec->stxkeys.dim1; i++)
    1657             :     {
    1658           8 :         ColumnRef  *cref = makeNode(ColumnRef);
    1659           8 :         AttrNumber  attnum = statsrec->stxkeys.values[i];
    1660             : 
    1661           8 :         cref->fields = list_make1(makeString(get_attname(heapRelid,
    1662             :                                                          attnum, false)));
    1663           8 :         cref->location = -1;
    1664             : 
    1665           8 :         def_names = lappend(def_names, cref);
    1666             :     }
    1667             : 
    1668             :     /* finally, build the output node */
    1669           4 :     stats = makeNode(CreateStatsStmt);
    1670           4 :     stats->defnames = NULL;
    1671           4 :     stats->stat_types = stat_types;
    1672           4 :     stats->exprs = def_names;
    1673           4 :     stats->relations = list_make1(heapRel);
    1674           4 :     stats->stxcomment = NULL;
    1675           4 :     stats->if_not_exists = false;
    1676             : 
    1677             :     /* Clean up */
    1678           4 :     ReleaseSysCache(ht_stats);
    1679             : 
    1680           4 :     return stats;
    1681             : }
    1682             : 
    1683             : /*
    1684             :  * get_collation        - fetch qualified name of a collation
    1685             :  *
    1686             :  * If collation is InvalidOid or is the default for the given actual_datatype,
    1687             :  * then the return value is NIL.
    1688             :  */
    1689             : static List *
    1690         396 : get_collation(Oid collation, Oid actual_datatype)
    1691             : {
    1692             :     List       *result;
    1693             :     HeapTuple   ht_coll;
    1694             :     Form_pg_collation coll_rec;
    1695             :     char       *nsp_name;
    1696             :     char       *coll_name;
    1697             : 
    1698         396 :     if (!OidIsValid(collation))
    1699         336 :         return NIL;             /* easy case */
    1700          60 :     if (collation == get_typcollation(actual_datatype))
    1701          56 :         return NIL;             /* just let it default */
    1702             : 
    1703           4 :     ht_coll = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation));
    1704           4 :     if (!HeapTupleIsValid(ht_coll))
    1705           0 :         elog(ERROR, "cache lookup failed for collation %u", collation);
    1706           4 :     coll_rec = (Form_pg_collation) GETSTRUCT(ht_coll);
    1707             : 
    1708             :     /* For simplicity, we always schema-qualify the name */
    1709           4 :     nsp_name = get_namespace_name(coll_rec->collnamespace);
    1710           4 :     coll_name = pstrdup(NameStr(coll_rec->collname));
    1711           4 :     result = list_make2(makeString(nsp_name), makeString(coll_name));
    1712             : 
    1713           4 :     ReleaseSysCache(ht_coll);
    1714           4 :     return result;
    1715             : }
    1716             : 
    1717             : /*
    1718             :  * get_opclass          - fetch qualified name of an index operator class
    1719             :  *
    1720             :  * If the opclass is the default for the given actual_datatype, then
    1721             :  * the return value is NIL.
    1722             :  */
    1723             : static List *
    1724         396 : get_opclass(Oid opclass, Oid actual_datatype)
    1725             : {
    1726         396 :     List       *result = NIL;
    1727             :     HeapTuple   ht_opc;
    1728             :     Form_pg_opclass opc_rec;
    1729             : 
    1730         396 :     ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    1731         396 :     if (!HeapTupleIsValid(ht_opc))
    1732           0 :         elog(ERROR, "cache lookup failed for opclass %u", opclass);
    1733         396 :     opc_rec = (Form_pg_opclass) GETSTRUCT(ht_opc);
    1734             : 
    1735         396 :     if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
    1736             :     {
    1737             :         /* For simplicity, we always schema-qualify the name */
    1738           4 :         char       *nsp_name = get_namespace_name(opc_rec->opcnamespace);
    1739           4 :         char       *opc_name = pstrdup(NameStr(opc_rec->opcname));
    1740             : 
    1741           4 :         result = list_make2(makeString(nsp_name), makeString(opc_name));
    1742             :     }
    1743             : 
    1744         396 :     ReleaseSysCache(ht_opc);
    1745         396 :     return result;
    1746             : }
    1747             : 
    1748             : 
    1749             : /*
    1750             :  * transformIndexConstraints
    1751             :  *      Handle UNIQUE, PRIMARY KEY, EXCLUDE constraints, which create indexes.
    1752             :  *      We also merge in any index definitions arising from
    1753             :  *      LIKE ... INCLUDING INDEXES.
    1754             :  */
    1755             : static void
    1756       27004 : transformIndexConstraints(CreateStmtContext *cxt)
    1757             : {
    1758             :     IndexStmt  *index;
    1759       27004 :     List       *indexlist = NIL;
    1760             :     ListCell   *lc;
    1761             : 
    1762             :     /*
    1763             :      * Run through the constraints that need to generate an index. For PRIMARY
    1764             :      * KEY, mark each column as NOT NULL and create an index. For UNIQUE or
    1765             :      * EXCLUDE, create an index as for PRIMARY KEY, but do not insist on NOT
    1766             :      * NULL.
    1767             :      */
    1768       31230 :     foreach(lc, cxt->ixconstraints)
    1769             :     {
    1770        4226 :         Constraint *constraint = lfirst_node(Constraint, lc);
    1771             : 
    1772             :         Assert(constraint->contype == CONSTR_PRIMARY ||
    1773             :                constraint->contype == CONSTR_UNIQUE ||
    1774             :                constraint->contype == CONSTR_EXCLUSION);
    1775             : 
    1776        4226 :         index = transformIndexConstraint(constraint, cxt);
    1777             : 
    1778        4226 :         indexlist = lappend(indexlist, index);
    1779             :     }
    1780             : 
    1781             :     /* Add in any indexes defined by LIKE ... INCLUDING INDEXES */
    1782       27044 :     foreach(lc, cxt->inh_indexes)
    1783             :     {
    1784          44 :         index = (IndexStmt *) lfirst(lc);
    1785             : 
    1786          44 :         if (index->primary)
    1787             :         {
    1788          18 :             if (cxt->pkey != NULL)
    1789           4 :                 ereport(ERROR,
    1790             :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    1791             :                          errmsg("multiple primary keys for table \"%s\" are not allowed",
    1792             :                                 cxt->relation->relname)));
    1793          14 :             cxt->pkey = index;
    1794             :         }
    1795             : 
    1796          40 :         indexlist = lappend(indexlist, index);
    1797             :     }
    1798             : 
    1799             :     /*
    1800             :      * Scan the index list and remove any redundant index specifications. This
    1801             :      * can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
    1802             :      * strict reading of SQL would suggest raising an error instead, but that
    1803             :      * strikes me as too anal-retentive. - tgl 2001-02-14
    1804             :      *
    1805             :      * XXX in ALTER TABLE case, it'd be nice to look for duplicate
    1806             :      * pre-existing indexes, too.
    1807             :      */
    1808             :     Assert(cxt->alist == NIL);
    1809       27000 :     if (cxt->pkey != NULL)
    1810             :     {
    1811             :         /* Make sure we keep the PKEY index in preference to others... */
    1812        3832 :         cxt->alist = list_make1(cxt->pkey);
    1813             :     }
    1814             : 
    1815       31262 :     foreach(lc, indexlist)
    1816             :     {
    1817        4262 :         bool        keep = true;
    1818             :         ListCell   *k;
    1819             : 
    1820        4262 :         index = lfirst(lc);
    1821             : 
    1822             :         /* if it's pkey, it's already in cxt->alist */
    1823        4262 :         if (index == cxt->pkey)
    1824        3832 :             continue;
    1825             : 
    1826         556 :         foreach(k, cxt->alist)
    1827             :         {
    1828         126 :             IndexStmt  *priorindex = lfirst(k);
    1829             : 
    1830         130 :             if (equal(index->indexParams, priorindex->indexParams) &&
    1831           8 :                 equal(index->indexIncludingParams, priorindex->indexIncludingParams) &&
    1832           8 :                 equal(index->whereClause, priorindex->whereClause) &&
    1833           8 :                 equal(index->excludeOpNames, priorindex->excludeOpNames) &&
    1834           8 :                 strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
    1835           4 :                 index->deferrable == priorindex->deferrable &&
    1836           0 :                 index->initdeferred == priorindex->initdeferred)
    1837             :             {
    1838           0 :                 priorindex->unique |= index->unique;
    1839             : 
    1840             :                 /*
    1841             :                  * If the prior index is as yet unnamed, and this one is
    1842             :                  * named, then transfer the name to the prior index. This
    1843             :                  * ensures that if we have named and unnamed constraints,
    1844             :                  * we'll use (at least one of) the names for the index.
    1845             :                  */
    1846           0 :                 if (priorindex->idxname == NULL)
    1847           0 :                     priorindex->idxname = index->idxname;
    1848           0 :                 keep = false;
    1849           0 :                 break;
    1850             :             }
    1851             :         }
    1852             : 
    1853         430 :         if (keep)
    1854         430 :             cxt->alist = lappend(cxt->alist, index);
    1855             :     }
    1856       27000 : }
    1857             : 
    1858             : /*
    1859             :  * transformIndexConstraint
    1860             :  *      Transform one UNIQUE, PRIMARY KEY, or EXCLUDE constraint for
    1861             :  *      transformIndexConstraints.
    1862             :  */
    1863             : static IndexStmt *
    1864        4226 : transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
    1865             : {
    1866             :     IndexStmt  *index;
    1867             :     ListCell   *lc;
    1868             : 
    1869        4226 :     index = makeNode(IndexStmt);
    1870             : 
    1871        4226 :     index->unique = (constraint->contype != CONSTR_EXCLUSION);
    1872        4226 :     index->primary = (constraint->contype == CONSTR_PRIMARY);
    1873        4226 :     if (index->primary)
    1874             :     {
    1875        3822 :         if (cxt->pkey != NULL)
    1876           0 :             ereport(ERROR,
    1877             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    1878             :                      errmsg("multiple primary keys for table \"%s\" are not allowed",
    1879             :                             cxt->relation->relname),
    1880             :                      parser_errposition(cxt->pstate, constraint->location)));
    1881        3822 :         cxt->pkey = index;
    1882             : 
    1883             :         /*
    1884             :          * In ALTER TABLE case, a primary index might already exist, but
    1885             :          * DefineIndex will check for it.
    1886             :          */
    1887             :     }
    1888        4226 :     index->isconstraint = true;
    1889        4226 :     index->deferrable = constraint->deferrable;
    1890        4226 :     index->initdeferred = constraint->initdeferred;
    1891             : 
    1892        4226 :     if (constraint->conname != NULL)
    1893         372 :         index->idxname = pstrdup(constraint->conname);
    1894             :     else
    1895        3854 :         index->idxname = NULL;   /* DefineIndex will choose name */
    1896             : 
    1897        4226 :     index->relation = cxt->relation;
    1898        4226 :     index->accessMethod = constraint->access_method ? constraint->access_method : DEFAULT_INDEX_TYPE;
    1899        4226 :     index->options = constraint->options;
    1900        4226 :     index->tableSpace = constraint->indexspace;
    1901        4226 :     index->whereClause = constraint->where_clause;
    1902        4226 :     index->indexParams = NIL;
    1903        4226 :     index->indexIncludingParams = NIL;
    1904        4226 :     index->excludeOpNames = NIL;
    1905        4226 :     index->idxcomment = NULL;
    1906        4226 :     index->indexOid = InvalidOid;
    1907        4226 :     index->oldNode = InvalidOid;
    1908        4226 :     index->transformed = false;
    1909        4226 :     index->concurrent = false;
    1910        4226 :     index->if_not_exists = false;
    1911             : 
    1912             :     /*
    1913             :      * If it's ALTER TABLE ADD CONSTRAINT USING INDEX, look up the index and
    1914             :      * verify it's usable, then extract the implied column name list.  (We
    1915             :      * will not actually need the column name list at runtime, but we need it
    1916             :      * now to check for duplicate column entries below.)
    1917             :      */
    1918        4226 :     if (constraint->indexname != NULL)
    1919             :     {
    1920          24 :         char       *index_name = constraint->indexname;
    1921          24 :         Relation    heap_rel = cxt->rel;
    1922             :         Oid         index_oid;
    1923             :         Relation    index_rel;
    1924             :         Form_pg_index index_form;
    1925             :         oidvector  *indclass;
    1926             :         Datum       indclassDatum;
    1927             :         bool        isnull;
    1928             :         int         i;
    1929             : 
    1930             :         /* Grammar should not allow this with explicit column list */
    1931             :         Assert(constraint->keys == NIL);
    1932             : 
    1933             :         /* Grammar should only allow PRIMARY and UNIQUE constraints */
    1934             :         Assert(constraint->contype == CONSTR_PRIMARY ||
    1935             :                constraint->contype == CONSTR_UNIQUE);
    1936             : 
    1937             :         /* Must be ALTER, not CREATE, but grammar doesn't enforce that */
    1938          24 :         if (!cxt->isalter)
    1939           0 :             ereport(ERROR,
    1940             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1941             :                      errmsg("cannot use an existing index in CREATE TABLE"),
    1942             :                      parser_errposition(cxt->pstate, constraint->location)));
    1943             : 
    1944             :         /* Look for the index in the same schema as the table */
    1945          24 :         index_oid = get_relname_relid(index_name, RelationGetNamespace(heap_rel));
    1946             : 
    1947          24 :         if (!OidIsValid(index_oid))
    1948           0 :             ereport(ERROR,
    1949             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    1950             :                      errmsg("index \"%s\" does not exist", index_name),
    1951             :                      parser_errposition(cxt->pstate, constraint->location)));
    1952             : 
    1953             :         /* Open the index (this will throw an error if it is not an index) */
    1954          24 :         index_rel = index_open(index_oid, AccessShareLock);
    1955          24 :         index_form = index_rel->rd_index;
    1956             : 
    1957             :         /* Check that it does not have an associated constraint already */
    1958          24 :         if (OidIsValid(get_index_constraint(index_oid)))
    1959           0 :             ereport(ERROR,
    1960             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1961             :                      errmsg("index \"%s\" is already associated with a constraint",
    1962             :                             index_name),
    1963             :                      parser_errposition(cxt->pstate, constraint->location)));
    1964             : 
    1965             :         /* Perform validity checks on the index */
    1966          24 :         if (index_form->indrelid != RelationGetRelid(heap_rel))
    1967           0 :             ereport(ERROR,
    1968             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1969             :                      errmsg("index \"%s\" does not belong to table \"%s\"",
    1970             :                             index_name, RelationGetRelationName(heap_rel)),
    1971             :                      parser_errposition(cxt->pstate, constraint->location)));
    1972             : 
    1973          24 :         if (!index_form->indisvalid)
    1974           0 :             ereport(ERROR,
    1975             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1976             :                      errmsg("index \"%s\" is not valid", index_name),
    1977             :                      parser_errposition(cxt->pstate, constraint->location)));
    1978             : 
    1979          24 :         if (!index_form->indisunique)
    1980           0 :             ereport(ERROR,
    1981             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1982             :                      errmsg("\"%s\" is not a unique index", index_name),
    1983             :                      errdetail("Cannot create a primary key or unique constraint using such an index."),
    1984             :                      parser_errposition(cxt->pstate, constraint->location)));
    1985             : 
    1986          24 :         if (RelationGetIndexExpressions(index_rel) != NIL)
    1987           0 :             ereport(ERROR,
    1988             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1989             :                      errmsg("index \"%s\" contains expressions", index_name),
    1990             :                      errdetail("Cannot create a primary key or unique constraint using such an index."),
    1991             :                      parser_errposition(cxt->pstate, constraint->location)));
    1992             : 
    1993          24 :         if (RelationGetIndexPredicate(index_rel) != NIL)
    1994           0 :             ereport(ERROR,
    1995             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1996             :                      errmsg("\"%s\" is a partial index", index_name),
    1997             :                      errdetail("Cannot create a primary key or unique constraint using such an index."),
    1998             :                      parser_errposition(cxt->pstate, constraint->location)));
    1999             : 
    2000             :         /*
    2001             :          * It's probably unsafe to change a deferred index to non-deferred. (A
    2002             :          * non-constraint index couldn't be deferred anyway, so this case
    2003             :          * should never occur; no need to sweat, but let's check it.)
    2004             :          */
    2005          24 :         if (!index_form->indimmediate && !constraint->deferrable)
    2006           0 :             ereport(ERROR,
    2007             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2008             :                      errmsg("\"%s\" is a deferrable index", index_name),
    2009             :                      errdetail("Cannot create a non-deferrable constraint using a deferrable index."),
    2010             :                      parser_errposition(cxt->pstate, constraint->location)));
    2011             : 
    2012             :         /*
    2013             :          * Insist on it being a btree.  That's the only kind that supports
    2014             :          * uniqueness at the moment anyway; but we must have an index that
    2015             :          * exactly matches what you'd get from plain ADD CONSTRAINT syntax,
    2016             :          * else dump and reload will produce a different index (breaking
    2017             :          * pg_upgrade in particular).
    2018             :          */
    2019          24 :         if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false))
    2020           0 :             ereport(ERROR,
    2021             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2022             :                      errmsg("index \"%s\" is not a btree", index_name),
    2023             :                      parser_errposition(cxt->pstate, constraint->location)));
    2024             : 
    2025             :         /* Must get indclass the hard way */
    2026          24 :         indclassDatum = SysCacheGetAttr(INDEXRELID, index_rel->rd_indextuple,
    2027             :                                         Anum_pg_index_indclass, &isnull);
    2028             :         Assert(!isnull);
    2029          24 :         indclass = (oidvector *) DatumGetPointer(indclassDatum);
    2030             : 
    2031          88 :         for (i = 0; i < index_form->indnatts; i++)
    2032             :         {
    2033          64 :             int16       attnum = index_form->indkey.values[i];
    2034             :             const FormData_pg_attribute *attform;
    2035             :             char       *attname;
    2036             :             Oid         defopclass;
    2037             : 
    2038             :             /*
    2039             :              * We shouldn't see attnum == 0 here, since we already rejected
    2040             :              * expression indexes.  If we do, SystemAttributeDefinition will
    2041             :              * throw an error.
    2042             :              */
    2043          64 :             if (attnum > 0)
    2044             :             {
    2045             :                 Assert(attnum <= heap_rel->rd_att->natts);
    2046          64 :                 attform = TupleDescAttr(heap_rel->rd_att, attnum - 1);
    2047             :             }
    2048             :             else
    2049           0 :                 attform = SystemAttributeDefinition(attnum);
    2050          64 :             attname = pstrdup(NameStr(attform->attname));
    2051             : 
    2052          64 :             if (i < index_form->indnkeyatts)
    2053             :             {
    2054             :                 /*
    2055             :                  * Insist on default opclass and sort options.  While the
    2056             :                  * index would still work as a constraint with non-default
    2057             :                  * settings, it might not provide exactly the same uniqueness
    2058             :                  * semantics as you'd get from a normally-created constraint;
    2059             :                  * and there's also the dump/reload problem mentioned above.
    2060             :                  */
    2061          44 :                 defopclass = GetDefaultOpClass(attform->atttypid,
    2062          44 :                                                index_rel->rd_rel->relam);
    2063          88 :                 if (indclass->values[i] != defopclass ||
    2064          44 :                     index_rel->rd_indoption[i] != 0)
    2065           0 :                     ereport(ERROR,
    2066             :                             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2067             :                              errmsg("index \"%s\" column number %d does not have default sorting behavior", index_name, i + 1),
    2068             :                              errdetail("Cannot create a primary key or unique constraint using such an index."),
    2069             :                              parser_errposition(cxt->pstate, constraint->location)));
    2070             : 
    2071          44 :                 constraint->keys = lappend(constraint->keys, makeString(attname));
    2072             :             }
    2073             :             else
    2074          20 :                 constraint->including = lappend(constraint->including, makeString(attname));
    2075             :         }
    2076             : 
    2077             :         /* Close the index relation but keep the lock */
    2078          24 :         relation_close(index_rel, NoLock);
    2079             : 
    2080          24 :         index->indexOid = index_oid;
    2081             :     }
    2082             : 
    2083             :     /*
    2084             :      * If it's an EXCLUDE constraint, the grammar returns a list of pairs of
    2085             :      * IndexElems and operator names.  We have to break that apart into
    2086             :      * separate lists.
    2087             :      */
    2088        4226 :     if (constraint->contype == CONSTR_EXCLUSION)
    2089             :     {
    2090         110 :         foreach(lc, constraint->exclusions)
    2091             :         {
    2092          66 :             List       *pair = (List *) lfirst(lc);
    2093             :             IndexElem  *elem;
    2094             :             List       *opname;
    2095             : 
    2096             :             Assert(list_length(pair) == 2);
    2097          66 :             elem = linitial_node(IndexElem, pair);
    2098          66 :             opname = lsecond_node(List, pair);
    2099             : 
    2100          66 :             index->indexParams = lappend(index->indexParams, elem);
    2101          66 :             index->excludeOpNames = lappend(index->excludeOpNames, opname);
    2102             :         }
    2103             :     }
    2104             : 
    2105             :     /*
    2106             :      * For UNIQUE and PRIMARY KEY, we just have a list of column names.
    2107             :      *
    2108             :      * Make sure referenced keys exist.  If we are making a PRIMARY KEY index,
    2109             :      * also make sure they are NOT NULL, if possible. (Although we could leave
    2110             :      * it to DefineIndex to mark the columns NOT NULL, it's more efficient to
    2111             :      * get it right the first time.)
    2112             :      */
    2113             :     else
    2114             :     {
    2115        8884 :         foreach(lc, constraint->keys)
    2116             :         {
    2117        4702 :             char       *key = strVal(lfirst(lc));
    2118        4702 :             bool        found = false;
    2119        4702 :             ColumnDef  *column = NULL;
    2120             :             ListCell   *columns;
    2121             :             IndexElem  *iparam;
    2122             : 
    2123             :             /* Make sure referenced column exist. */
    2124        5354 :             foreach(columns, cxt->columns)
    2125             :             {
    2126        4812 :                 column = castNode(ColumnDef, lfirst(columns));
    2127        4812 :                 if (strcmp(column->colname, key) == 0)
    2128             :                 {
    2129        4160 :                     found = true;
    2130        4160 :                     break;
    2131             :                 }
    2132             :             }
    2133        4702 :             if (found)
    2134             :             {
    2135             :                 /* found column in the new table; force it to be NOT NULL */
    2136        4160 :                 if (constraint->contype == CONSTR_PRIMARY)
    2137        3838 :                     column->is_not_null = true;
    2138             :             }
    2139         542 :             else if (SystemAttributeByName(key) != NULL)
    2140             :             {
    2141             :                 /*
    2142             :                  * column will be a system column in the new table, so accept
    2143             :                  * it. System columns can't ever be null, so no need to worry
    2144             :                  * about PRIMARY/NOT NULL constraint.
    2145             :                  */
    2146           0 :                 found = true;
    2147             :             }
    2148         542 :             else if (cxt->inhRelations)
    2149             :             {
    2150             :                 /* try inherited tables */
    2151             :                 ListCell   *inher;
    2152             : 
    2153          40 :                 foreach(inher, cxt->inhRelations)
    2154             :                 {
    2155          40 :                     RangeVar   *inh = castNode(RangeVar, lfirst(inher));
    2156             :                     Relation    rel;
    2157             :                     int         count;
    2158             : 
    2159          40 :                     rel = heap_openrv(inh, AccessShareLock);
    2160             :                     /* check user requested inheritance from valid relkind */
    2161          40 :                     if (rel->rd_rel->relkind != RELKIND_RELATION &&
    2162           0 :                         rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
    2163           0 :                         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
    2164           0 :                         ereport(ERROR,
    2165             :                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2166             :                                  errmsg("inherited relation \"%s\" is not a table or foreign table",
    2167             :                                         inh->relname)));
    2168          40 :                     for (count = 0; count < rel->rd_att->natts; count++)
    2169             :                     {
    2170          40 :                         Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
    2171             :                                                                   count);
    2172          40 :                         char       *inhname = NameStr(inhattr->attname);
    2173             : 
    2174          40 :                         if (inhattr->attisdropped)
    2175           0 :                             continue;
    2176          40 :                         if (strcmp(key, inhname) == 0)
    2177             :                         {
    2178          40 :                             found = true;
    2179             : 
    2180             :                             /*
    2181             :                              * We currently have no easy way to force an
    2182             :                              * inherited column to be NOT NULL at creation, if
    2183             :                              * its parent wasn't so already. We leave it to
    2184             :                              * DefineIndex to fix things up in this case.
    2185             :                              */
    2186          40 :                             break;
    2187             :                         }
    2188             :                     }
    2189          40 :                     heap_close(rel, NoLock);
    2190          40 :                     if (found)
    2191          40 :                         break;
    2192             :                 }
    2193             :             }
    2194             : 
    2195             :             /*
    2196             :              * In the ALTER TABLE case, don't complain about index keys not
    2197             :              * created in the command; they may well exist already.
    2198             :              * DefineIndex will complain about them if not, and will also take
    2199             :              * care of marking them NOT NULL.
    2200             :              */
    2201        4702 :             if (!found && !cxt->isalter)
    2202           0 :                 ereport(ERROR,
    2203             :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    2204             :                          errmsg("column \"%s\" named in key does not exist", key),
    2205             :                          parser_errposition(cxt->pstate, constraint->location)));
    2206             : 
    2207             :             /* Check for PRIMARY KEY(foo, foo) */
    2208        5280 :             foreach(columns, index->indexParams)
    2209             :             {
    2210         578 :                 iparam = (IndexElem *) lfirst(columns);
    2211         578 :                 if (iparam->name && strcmp(key, iparam->name) == 0)
    2212             :                 {
    2213           0 :                     if (index->primary)
    2214           0 :                         ereport(ERROR,
    2215             :                                 (errcode(ERRCODE_DUPLICATE_COLUMN),
    2216             :                                  errmsg("column \"%s\" appears twice in primary key constraint",
    2217             :                                         key),
    2218             :                                  parser_errposition(cxt->pstate, constraint->location)));
    2219             :                     else
    2220           0 :                         ereport(ERROR,
    2221             :                                 (errcode(ERRCODE_DUPLICATE_COLUMN),
    2222             :                                  errmsg("column \"%s\" appears twice in unique constraint",
    2223             :                                         key),
    2224             :                                  parser_errposition(cxt->pstate, constraint->location)));
    2225             :                 }
    2226             :             }
    2227             : 
    2228             :             /* OK, add it to the index definition */
    2229        4702 :             iparam = makeNode(IndexElem);
    2230        4702 :             iparam->name = pstrdup(key);
    2231        4702 :             iparam->expr = NULL;
    2232        4702 :             iparam->indexcolname = NULL;
    2233        4702 :             iparam->collation = NIL;
    2234        4702 :             iparam->opclass = NIL;
    2235        4702 :             iparam->ordering = SORTBY_DEFAULT;
    2236        4702 :             iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
    2237        4702 :             index->indexParams = lappend(index->indexParams, iparam);
    2238             :         }
    2239             :     }
    2240             : 
    2241             :     /* Add included columns to index definition */
    2242        4446 :     foreach(lc, constraint->including)
    2243             :     {
    2244         220 :         char       *key = strVal(lfirst(lc));
    2245         220 :         bool        found = false;
    2246         220 :         ColumnDef  *column = NULL;
    2247             :         ListCell   *columns;
    2248             :         IndexElem  *iparam;
    2249             : 
    2250         466 :         foreach(columns, cxt->columns)
    2251             :         {
    2252         382 :             column = lfirst_node(ColumnDef, columns);
    2253         382 :             if (strcmp(column->colname, key) == 0)
    2254             :             {
    2255         136 :                 found = true;
    2256         136 :                 break;
    2257             :             }
    2258             :         }
    2259             : 
    2260         220 :         if (!found)
    2261             :         {
    2262          84 :             if (SystemAttributeByName(key) != NULL)
    2263             :             {
    2264             :                 /*
    2265             :                  * column will be a system column in the new table, so accept
    2266             :                  * it. System columns can't ever be null, so no need to worry
    2267             :                  * about PRIMARY/NOT NULL constraint.
    2268             :                  */
    2269           0 :                 found = true;
    2270             :             }
    2271          84 :             else if (cxt->inhRelations)
    2272             :             {
    2273             :                 /* try inherited tables */
    2274             :                 ListCell   *inher;
    2275             : 
    2276           0 :                 foreach(inher, cxt->inhRelations)
    2277             :                 {
    2278           0 :                     RangeVar   *inh = lfirst_node(RangeVar, inher);
    2279             :                     Relation    rel;
    2280             :                     int         count;
    2281             : 
    2282           0 :                     rel = heap_openrv(inh, AccessShareLock);
    2283             :                     /* check user requested inheritance from valid relkind */
    2284           0 :                     if (rel->rd_rel->relkind != RELKIND_RELATION &&
    2285           0 :                         rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
    2286           0 :                         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
    2287           0 :                         ereport(ERROR,
    2288             :                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2289             :                                  errmsg("inherited relation \"%s\" is not a table or foreign table",
    2290             :                                         inh->relname)));
    2291           0 :                     for (count = 0; count < rel->rd_att->natts; count++)
    2292             :                     {
    2293           0 :                         Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
    2294             :                                                                   count);
    2295           0 :                         char       *inhname = NameStr(inhattr->attname);
    2296             : 
    2297           0 :                         if (inhattr->attisdropped)
    2298           0 :                             continue;
    2299           0 :                         if (strcmp(key, inhname) == 0)
    2300             :                         {
    2301           0 :                             found = true;
    2302             : 
    2303             :                             /*
    2304             :                              * We currently have no easy way to force an
    2305             :                              * inherited column to be NOT NULL at creation, if
    2306             :                              * its parent wasn't so already. We leave it to
    2307             :                              * DefineIndex to fix things up in this case.
    2308             :                              */
    2309           0 :                             break;
    2310             :                         }
    2311             :                     }
    2312           0 :                     heap_close(rel, NoLock);
    2313           0 :                     if (found)
    2314           0 :                         break;
    2315             :                 }
    2316             :             }
    2317             :         }
    2318             : 
    2319             :         /*
    2320             :          * In the ALTER TABLE case, don't complain about index keys not
    2321             :          * created in the command; they may well exist already. DefineIndex
    2322             :          * will complain about them if not, and will also take care of marking
    2323             :          * them NOT NULL.
    2324             :          */
    2325         220 :         if (!found && !cxt->isalter)
    2326           0 :             ereport(ERROR,
    2327             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    2328             :                      errmsg("column \"%s\" named in key does not exist", key),
    2329             :                      parser_errposition(cxt->pstate, constraint->location)));
    2330             : 
    2331             :         /* OK, add it to the index definition */
    2332         220 :         iparam = makeNode(IndexElem);
    2333         220 :         iparam->name = pstrdup(key);
    2334         220 :         iparam->expr = NULL;
    2335         220 :         iparam->indexcolname = NULL;
    2336         220 :         iparam->collation = NIL;
    2337         220 :         iparam->opclass = NIL;
    2338         220 :         index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
    2339             :     }
    2340             : 
    2341        4226 :     return index;
    2342             : }
    2343             : 
    2344             : /*
    2345             :  * transformExtendedStatistics
    2346             :  *     Handle extended statistic objects
    2347             :  *
    2348             :  * Right now, there's nothing to do here, so we just append the list to
    2349             :  * the existing "after" list.
    2350             :  */
    2351             : static void
    2352       27000 : transformExtendedStatistics(CreateStmtContext *cxt)
    2353             : {
    2354       27000 :     cxt->alist = list_concat(cxt->alist, cxt->extstats);
    2355       27000 : }
    2356             : 
    2357             : /*
    2358             :  * transformCheckConstraints
    2359             :  *      handle CHECK constraints
    2360             :  *
    2361             :  * Right now, there's nothing to do here when called from ALTER TABLE,
    2362             :  * but the other constraint-transformation functions are called in both
    2363             :  * the CREATE TABLE and ALTER TABLE paths, so do the same here, and just
    2364             :  * don't do anything if we're not authorized to skip validation.
    2365             :  */
    2366             : static void
    2367       27000 : transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation)
    2368             : {
    2369             :     ListCell   *ckclist;
    2370             : 
    2371       27000 :     if (cxt->ckconstraints == NIL)
    2372       26292 :         return;
    2373             : 
    2374             :     /*
    2375             :      * If creating a new table (but not a foreign table), we can safely skip
    2376             :      * validation of check constraints, and nonetheless mark them valid. (This
    2377             :      * will override any user-supplied NOT VALID flag.)
    2378             :      */
    2379         708 :     if (skipValidation)
    2380             :     {
    2381         668 :         foreach(ckclist, cxt->ckconstraints)
    2382             :         {
    2383         360 :             Constraint *constraint = (Constraint *) lfirst(ckclist);
    2384             : 
    2385         360 :             constraint->skip_validation = true;
    2386         360 :             constraint->initially_valid = true;
    2387             :         }
    2388             :     }
    2389             : }
    2390             : 
    2391             : /*
    2392             :  * transformFKConstraints
    2393             :  *      handle FOREIGN KEY constraints
    2394             :  */
    2395             : static void
    2396       27000 : transformFKConstraints(CreateStmtContext *cxt,
    2397             :                        bool skipValidation, bool isAddConstraint)
    2398             : {
    2399             :     ListCell   *fkclist;
    2400             : 
    2401       27000 :     if (cxt->fkconstraints == NIL)
    2402       25832 :         return;
    2403             : 
    2404             :     /*
    2405             :      * If CREATE TABLE or adding a column with NULL default, we can safely
    2406             :      * skip validation of FK constraints, and nonetheless mark them valid.
    2407             :      * (This will override any user-supplied NOT VALID flag.)
    2408             :      */
    2409        1168 :     if (skipValidation)
    2410             :     {
    2411        1078 :         foreach(fkclist, cxt->fkconstraints)
    2412             :         {
    2413         554 :             Constraint *constraint = (Constraint *) lfirst(fkclist);
    2414             : 
    2415         554 :             constraint->skip_validation = true;
    2416         554 :             constraint->initially_valid = true;
    2417             :         }
    2418             :     }
    2419             : 
    2420             :     /*
    2421             :      * For CREATE TABLE or ALTER TABLE ADD COLUMN, gin up an ALTER TABLE ADD
    2422             :      * CONSTRAINT command to execute after the basic command is complete. (If
    2423             :      * called from ADD CONSTRAINT, that routine will add the FK constraints to
    2424             :      * its own subcommand list.)
    2425             :      *
    2426             :      * Note: the ADD CONSTRAINT command must also execute after any index
    2427             :      * creation commands.  Thus, this should run after
    2428             :      * transformIndexConstraints, so that the CREATE INDEX commands are
    2429             :      * already in cxt->alist.
    2430             :      */
    2431        1168 :     if (!isAddConstraint)
    2432             :     {
    2433         524 :         AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
    2434             : 
    2435         524 :         alterstmt->relation = cxt->relation;
    2436         524 :         alterstmt->cmds = NIL;
    2437         524 :         alterstmt->relkind = OBJECT_TABLE;
    2438             : 
    2439        1078 :         foreach(fkclist, cxt->fkconstraints)
    2440             :         {
    2441         554 :             Constraint *constraint = (Constraint *) lfirst(fkclist);
    2442         554 :             AlterTableCmd *altercmd = makeNode(AlterTableCmd);
    2443             : 
    2444         554 :             altercmd->subtype = AT_ProcessedConstraint;
    2445         554 :             altercmd->name = NULL;
    2446         554 :             altercmd->def = (Node *) constraint;
    2447         554 :             alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
    2448             :         }
    2449             : 
    2450         524 :         cxt->alist = lappend(cxt->alist, alterstmt);
    2451             :     }
    2452             : }
    2453             : 
    2454             : /*
    2455             :  * transformIndexStmt - parse analysis for CREATE INDEX and ALTER TABLE
    2456             :  *
    2457             :  * Note: this is a no-op for an index not using either index expressions or
    2458             :  * a predicate expression.  There are several code paths that create indexes
    2459             :  * without bothering to call this, because they know they don't have any
    2460             :  * such expressions to deal with.
    2461             :  *
    2462             :  * To avoid race conditions, it's important that this function rely only on
    2463             :  * the passed-in relid (and not on stmt->relation) to determine the target
    2464             :  * relation.
    2465             :  */
    2466             : IndexStmt *
    2467        6844 : transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
    2468             : {
    2469             :     ParseState *pstate;
    2470             :     RangeTblEntry *rte;
    2471             :     ListCell   *l;
    2472             :     Relation    rel;
    2473             : 
    2474             :     /* Nothing to do if statement already transformed. */
    2475        6844 :     if (stmt->transformed)
    2476          40 :         return stmt;
    2477             : 
    2478             :     /*
    2479             :      * We must not scribble on the passed-in IndexStmt, so copy it.  (This is
    2480             :      * overkill, but easy.)
    2481             :      */
    2482        6804 :     stmt = copyObject(stmt);
    2483             : 
    2484             :     /* Set up pstate */
    2485        6804 :     pstate = make_parsestate(NULL);
    2486        6804 :     pstate->p_sourcetext = queryString;
    2487             : 
    2488             :     /*
    2489             :      * Put the parent table into the rtable so that the expressions can refer
    2490             :      * to its fields without qualification.  Caller is responsible for locking
    2491             :      * relation, but we still need to open it.
    2492             :      */
    2493        6804 :     rel = relation_open(relid, NoLock);
    2494        6804 :     rte = addRangeTableEntryForRelation(pstate, rel,
    2495             :                                         AccessShareLock,
    2496             :                                         NULL, false, true);
    2497             : 
    2498             :     /* no to join list, yes to namespaces */
    2499        6804 :     addRTEtoQuery(pstate, rte, false, true, true);
    2500             : 
    2501             :     /* take care of the where clause */
    2502        6804 :     if (stmt->whereClause)
    2503             :     {
    2504         154 :         stmt->whereClause = transformWhereClause(pstate,
    2505             :                                                  stmt->whereClause,
    2506             :                                                  EXPR_KIND_INDEX_PREDICATE,
    2507             :                                                  "WHERE");
    2508             :         /* we have to fix its collations too */
    2509         154 :         assign_expr_collations(pstate, stmt->whereClause);
    2510             :     }
    2511             : 
    2512             :     /* take care of any index expressions */
    2513       14788 :     foreach(l, stmt->indexParams)
    2514             :     {
    2515        7988 :         IndexElem  *ielem = (IndexElem *) lfirst(l);
    2516             : 
    2517        7988 :         if (ielem->expr)
    2518             :         {
    2519             :             /* Extract preliminary index col name before transforming expr */
    2520         242 :             if (ielem->indexcolname == NULL)
    2521         242 :                 ielem->indexcolname = FigureIndexColname(ielem->expr);
    2522             : 
    2523             :             /* Now do parse transformation of the expression */
    2524         242 :             ielem->expr = transformExpr(pstate, ielem->expr,
    2525             :                                         EXPR_KIND_INDEX_EXPRESSION);
    2526             : 
    2527             :             /* We have to fix its collations too */
    2528         238 :             assign_expr_collations(pstate, ielem->expr);
    2529             : 
    2530             :             /*
    2531             :              * transformExpr() should have already rejected subqueries,
    2532             :              * aggregates, window functions, and SRFs, based on the EXPR_KIND_
    2533             :              * for an index expression.
    2534             :              *
    2535             :              * DefineIndex() will make more checks.
    2536             :              */
    2537             :         }
    2538             :     }
    2539             : 
    2540             :     /*
    2541             :      * Check that only the base rel is mentioned.  (This should be dead code
    2542             :      * now that add_missing_from is history.)
    2543             :      */
    2544        6800 :     if (list_length(pstate->p_rtable) != 1)
    2545           0 :         ereport(ERROR,
    2546             :                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
    2547             :                  errmsg("index expressions and predicates can refer only to the table being indexed")));
    2548             : 
    2549        6800 :     free_parsestate(pstate);
    2550             : 
    2551             :     /* Close relation */
    2552        6800 :     heap_close(rel, NoLock);
    2553             : 
    2554             :     /* Mark statement as successfully transformed */
    2555        6800 :     stmt->transformed = true;
    2556             : 
    2557        6800 :     return stmt;
    2558             : }
    2559             : 
    2560             : 
    2561             : /*
    2562             :  * transformRuleStmt -
    2563             :  *    transform a CREATE RULE Statement. The action is a list of parse
    2564             :  *    trees which is transformed into a list of query trees, and we also
    2565             :  *    transform the WHERE clause if any.
    2566             :  *
    2567             :  * actions and whereClause are output parameters that receive the
    2568             :  * transformed results.
    2569             :  *
    2570             :  * Note that we must not scribble on the passed-in RuleStmt, so we do
    2571             :  * copyObject() on the actions and WHERE clause.
    2572             :  */
    2573             : void
    2574        1070 : transformRuleStmt(RuleStmt *stmt, const char *queryString,
    2575             :                   List **actions, Node **whereClause)
    2576             : {
    2577             :     Relation    rel;
    2578             :     ParseState *pstate;
    2579             :     RangeTblEntry *oldrte;
    2580             :     RangeTblEntry *newrte;
    2581             : 
    2582             :     /*
    2583             :      * To avoid deadlock, make sure the first thing we do is grab
    2584             :      * AccessExclusiveLock on the target relation.  This will be needed by
    2585             :      * DefineQueryRewrite(), and we don't want to grab a lesser lock
    2586             :      * beforehand.
    2587             :      */
    2588        1070 :     rel = heap_openrv(stmt->relation, AccessExclusiveLock);
    2589             : 
    2590        1070 :     if (rel->rd_rel->relkind == RELKIND_MATVIEW)
    2591           0 :         ereport(ERROR,
    2592             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2593             :                  errmsg("rules on materialized views are not supported")));
    2594             : 
    2595             :     /* Set up pstate */
    2596        1070 :     pstate = make_parsestate(NULL);
    2597        1070 :     pstate->p_sourcetext = queryString;
    2598             : 
    2599             :     /*
    2600             :      * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to 2.
    2601             :      * Set up their RTEs in the main pstate for use in parsing the rule
    2602             :      * qualification.
    2603             :      */
    2604        1070 :     oldrte = addRangeTableEntryForRelation(pstate, rel,
    2605             :                                            AccessShareLock,
    2606             :                                            makeAlias("old", NIL),
    2607             :                                            false, false);
    2608        1070 :     newrte = addRangeTableEntryForRelation(pstate, rel,
    2609             :                                            AccessShareLock,
    2610             :                                            makeAlias("new", NIL),
    2611             :                                            false, false);
    2612             :     /* Must override addRangeTableEntry's default access-check flags */
    2613        1070 :     oldrte->requiredPerms = 0;
    2614        1070 :     newrte->requiredPerms = 0;
    2615             : 
    2616             :     /*
    2617             :      * They must be in the namespace too for lookup purposes, but only add the
    2618             :      * one(s) that are relevant for the current kind of rule.  In an UPDATE
    2619             :      * rule, quals must refer to OLD.field or NEW.field to be unambiguous, but
    2620             :      * there's no need to be so picky for INSERT & DELETE.  We do not add them
    2621             :      * to the joinlist.
    2622             :      */
    2623        1070 :     switch (stmt->event)
    2624             :     {
    2625             :         case CMD_SELECT:
    2626          26 :             addRTEtoQuery(pstate, oldrte, false, true, true);
    2627          26 :             break;
    2628             :         case CMD_UPDATE:
    2629         704 :             addRTEtoQuery(pstate, oldrte, false, true, true);
    2630         704 :             addRTEtoQuery(pstate, newrte, false, true, true);
    2631         704 :             break;
    2632             :         case CMD_INSERT:
    2633         248 :             addRTEtoQuery(pstate, newrte, false, true, true);
    2634         248 :             break;
    2635             :         case CMD_DELETE:
    2636          92 :             addRTEtoQuery(pstate, oldrte, false, true, true);
    2637          92 :             break;
    2638             :         default:
    2639           0 :             elog(ERROR, "unrecognized event type: %d",
    2640             :                  (int) stmt->event);
    2641             :             break;
    2642             :     }
    2643             : 
    2644             :     /* take care of the where clause */
    2645        1070 :     *whereClause = transformWhereClause(pstate,
    2646        1070 :                                         (Node *) copyObject(stmt->whereClause),
    2647             :                                         EXPR_KIND_WHERE,
    2648             :                                         "WHERE");
    2649             :     /* we have to fix its collations too */
    2650        1070 :     assign_expr_collations(pstate, *whereClause);
    2651             : 
    2652             :     /* this is probably dead code without add_missing_from: */
    2653        1070 :     if (list_length(pstate->p_rtable) != 2) /* naughty, naughty... */
    2654           0 :         ereport(ERROR,
    2655             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2656             :                  errmsg("rule WHERE condition cannot contain references to other relations")));
    2657             : 
    2658             :     /*
    2659             :      * 'instead nothing' rules with a qualification need a query rangetable so
    2660             :      * the rewrite handler can add the negated rule qualification to the
    2661             :      * original query. We create a query with the new command type CMD_NOTHING
    2662             :      * here that is treated specially by the rewrite system.
    2663             :      */
    2664        1070 :     if (stmt->actions == NIL)
    2665             :     {
    2666         334 :         Query      *nothing_qry = makeNode(Query);
    2667             : 
    2668         334 :         nothing_qry->commandType = CMD_NOTHING;
    2669         334 :         nothing_qry->rtable = pstate->p_rtable;
    2670         334 :         nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
    2671             : 
    2672         334 :         *actions = list_make1(nothing_qry);
    2673             :     }
    2674             :     else
    2675             :     {
    2676             :         ListCell   *l;
    2677         736 :         List       *newactions = NIL;
    2678             : 
    2679             :         /*
    2680             :          * transform each statement, like parse_sub_analyze()
    2681             :          */
    2682        1492 :         foreach(l, stmt->actions)
    2683             :         {
    2684         764 :             Node       *action = (Node *) lfirst(l);
    2685         764 :             ParseState *sub_pstate = make_parsestate(NULL);
    2686             :             Query      *sub_qry,
    2687             :                        *top_subqry;
    2688             :             bool        has_old,
    2689             :                         has_new;
    2690             : 
    2691             :             /*
    2692             :              * Since outer ParseState isn't parent of inner, have to pass down
    2693             :              * the query text by hand.
    2694             :              */
    2695         764 :             sub_pstate->p_sourcetext = queryString;
    2696             : 
    2697             :             /*
    2698             :              * Set up OLD/NEW in the rtable for this statement.  The entries
    2699             :              * are added only to relnamespace, not varnamespace, because we
    2700             :              * don't want them to be referred to by unqualified field names
    2701             :              * nor "*" in the rule actions.  We decide later whether to put
    2702             :              * them in the joinlist.
    2703             :              */
    2704         764 :             oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
    2705             :                                                    AccessShareLock,
    2706             :                                                    makeAlias("old", NIL),
    2707             :                                                    false, false);
    2708         764 :             newrte = addRangeTableEntryForRelation(sub_pstate, rel,
    2709             :                                                    AccessShareLock,
    2710             :                                                    makeAlias("new", NIL),
    2711             :                                                    false, false);
    2712         764 :             oldrte->requiredPerms = 0;
    2713         764 :             newrte->requiredPerms = 0;
    2714         764 :             addRTEtoQuery(sub_pstate, oldrte, false, true, false);
    2715         764 :             addRTEtoQuery(sub_pstate, newrte, false, true, false);
    2716             : 
    2717             :             /* Transform the rule action statement */
    2718         764 :             top_subqry = transformStmt(sub_pstate,
    2719         764 :                                        (Node *) copyObject(action));
    2720             : 
    2721             :             /*
    2722             :              * We cannot support utility-statement actions (eg NOTIFY) with
    2723             :              * nonempty rule WHERE conditions, because there's no way to make
    2724             :              * the utility action execute conditionally.
    2725             :              */
    2726         766 :             if (top_subqry->commandType == CMD_UTILITY &&
    2727           6 :                 *whereClause != NULL)
    2728           0 :                 ereport(ERROR,
    2729             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2730             :                          errmsg("rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions")));
    2731             : 
    2732             :             /*
    2733             :              * If the action is INSERT...SELECT, OLD/NEW have been pushed down
    2734             :              * into the SELECT, and that's what we need to look at. (Ugly
    2735             :              * kluge ... try to fix this when we redesign querytrees.)
    2736             :              */
    2737         760 :             sub_qry = getInsertSelectQuery(top_subqry, NULL);
    2738             : 
    2739             :             /*
    2740             :              * If the sub_qry is a setop, we cannot attach any qualifications
    2741             :              * to it, because the planner won't notice them.  This could
    2742             :              * perhaps be relaxed someday, but for now, we may as well reject
    2743             :              * such a rule immediately.
    2744             :              */
    2745         760 :             if (sub_qry->setOperations != NULL && *whereClause != NULL)
    2746           0 :                 ereport(ERROR,
    2747             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2748             :                          errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
    2749             : 
    2750             :             /*
    2751             :              * Validate action's use of OLD/NEW, qual too
    2752             :              */
    2753         760 :             has_old =
    2754        1074 :                 rangeTableEntry_used((Node *) sub_qry, PRS2_OLD_VARNO, 0) ||
    2755         314 :                 rangeTableEntry_used(*whereClause, PRS2_OLD_VARNO, 0);
    2756         760 :             has_new =
    2757         930 :                 rangeTableEntry_used((Node *) sub_qry, PRS2_NEW_VARNO, 0) ||
    2758         170 :                 rangeTableEntry_used(*whereClause, PRS2_NEW_VARNO, 0);
    2759             : 
    2760         760 :             switch (stmt->event)
    2761             :             {
    2762             :                 case CMD_SELECT:
    2763          26 :                     if (has_old)
    2764           0 :                         ereport(ERROR,
    2765             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2766             :                                  errmsg("ON SELECT rule cannot use OLD")));
    2767          26 :                     if (has_new)
    2768           0 :                         ereport(ERROR,
    2769             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2770             :                                  errmsg("ON SELECT rule cannot use NEW")));
    2771          26 :                     break;
    2772             :                 case CMD_UPDATE:
    2773             :                     /* both are OK */
    2774         420 :                     break;
    2775             :                 case CMD_INSERT:
    2776         220 :                     if (has_old)
    2777           0 :                         ereport(ERROR,
    2778             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2779             :                                  errmsg("ON INSERT rule cannot use OLD")));
    2780         220 :                     break;
    2781             :                 case CMD_DELETE:
    2782          94 :                     if (has_new)
    2783           0 :                         ereport(ERROR,
    2784             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2785             :                                  errmsg("ON DELETE rule cannot use NEW")));
    2786          94 :                     break;
    2787             :                 default:
    2788           0 :                     elog(ERROR, "unrecognized event type: %d",
    2789             :                          (int) stmt->event);
    2790             :                     break;
    2791             :             }
    2792             : 
    2793             :             /*
    2794             :              * OLD/NEW are not allowed in WITH queries, because they would
    2795             :              * amount to outer references for the WITH, which we disallow.
    2796             :              * However, they were already in the outer rangetable when we
    2797             :              * analyzed the query, so we have to check.
    2798             :              *
    2799             :              * Note that in the INSERT...SELECT case, we need to examine the
    2800             :              * CTE lists of both top_subqry and sub_qry.
    2801             :              *
    2802             :              * Note that we aren't digging into the body of the query looking
    2803             :              * for WITHs in nested sub-SELECTs.  A WITH down there can
    2804             :              * legitimately refer to OLD/NEW, because it'd be an
    2805             :              * indirect-correlated outer reference.
    2806             :              */
    2807         760 :             if (rangeTableEntry_used((Node *) top_subqry->cteList,
    2808         756 :                                      PRS2_OLD_VARNO, 0) ||
    2809         756 :                 rangeTableEntry_used((Node *) sub_qry->cteList,
    2810             :                                      PRS2_OLD_VARNO, 0))
    2811           4 :                 ereport(ERROR,
    2812             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2813             :                          errmsg("cannot refer to OLD within WITH query")));
    2814         756 :             if (rangeTableEntry_used((Node *) top_subqry->cteList,
    2815         756 :                                      PRS2_NEW_VARNO, 0) ||
    2816         756 :                 rangeTableEntry_used((Node *) sub_qry->cteList,
    2817             :                                      PRS2_NEW_VARNO, 0))
    2818           0 :                 ereport(ERROR,
    2819             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2820             :                          errmsg("cannot refer to NEW within WITH query")));
    2821             : 
    2822             :             /*
    2823             :              * For efficiency's sake, add OLD to the rule action's jointree
    2824             :              * only if it was actually referenced in the statement or qual.
    2825             :              *
    2826             :              * For INSERT, NEW is not really a relation (only a reference to
    2827             :              * the to-be-inserted tuple) and should never be added to the
    2828             :              * jointree.
    2829             :              *
    2830             :              * For UPDATE, we treat NEW as being another kind of reference to
    2831             :              * OLD, because it represents references to *transformed* tuples
    2832             :              * of the existing relation.  It would be wrong to enter NEW
    2833             :              * separately in the jointree, since that would cause a double
    2834             :              * join of the updated relation.  It's also wrong to fail to make
    2835             :              * a jointree entry if only NEW and not OLD is mentioned.
    2836             :              */
    2837         756 :             if (has_old || (has_new && stmt->event == CMD_UPDATE))
    2838             :             {
    2839             :                 /*
    2840             :                  * If sub_qry is a setop, manipulating its jointree will do no
    2841             :                  * good at all, because the jointree is dummy. (This should be
    2842             :                  * a can't-happen case because of prior tests.)
    2843             :                  */
    2844         468 :                 if (sub_qry->setOperations != NULL)
    2845           0 :                     ereport(ERROR,
    2846             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2847             :                              errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
    2848             :                 /* hack so we can use addRTEtoQuery() */
    2849         468 :                 sub_pstate->p_rtable = sub_qry->rtable;
    2850         468 :                 sub_pstate->p_joinlist = sub_qry->jointree->fromlist;
    2851         468 :                 addRTEtoQuery(sub_pstate, oldrte, true, false, false);
    2852         468 :                 sub_qry->jointree->fromlist = sub_pstate->p_joinlist;
    2853             :             }
    2854             : 
    2855         756 :             newactions = lappend(newactions, top_subqry);
    2856             : 
    2857         756 :             free_parsestate(sub_pstate);
    2858             :         }
    2859             : 
    2860         728 :         *actions = newactions;
    2861             :     }
    2862             : 
    2863        1062 :     free_parsestate(pstate);
    2864             : 
    2865             :     /* Close relation, but keep the exclusive lock */
    2866        1062 :     heap_close(rel, NoLock);
    2867        1062 : }
    2868             : 
    2869             : 
    2870             : /*
    2871             :  * transformAlterTableStmt -
    2872             :  *      parse analysis for ALTER TABLE
    2873             :  *
    2874             :  * Returns a List of utility commands to be done in sequence.  One of these
    2875             :  * will be the transformed AlterTableStmt, but there may be additional actions
    2876             :  * to be done before and after the actual AlterTable() call.
    2877             :  *
    2878             :  * To avoid race conditions, it's important that this function rely only on
    2879             :  * the passed-in relid (and not on stmt->relation) to determine the target
    2880             :  * relation.
    2881             :  */
    2882             : List *
    2883        8762 : transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
    2884             :                         const char *queryString)
    2885             : {
    2886             :     Relation    rel;
    2887             :     TupleDesc   tupdesc;
    2888             :     ParseState *pstate;
    2889             :     CreateStmtContext cxt;
    2890             :     List       *result;
    2891             :     List       *save_alist;
    2892             :     ListCell   *lcmd,
    2893             :                *l;
    2894        8762 :     List       *newcmds = NIL;
    2895        8762 :     bool        skipValidation = true;
    2896             :     AlterTableCmd *newcmd;
    2897             :     RangeTblEntry *rte;
    2898             : 
    2899             :     /*
    2900             :      * We must not scribble on the passed-in AlterTableStmt, so copy it. (This
    2901             :      * is overkill, but easy.)
    2902             :      */
    2903        8762 :     stmt = copyObject(stmt);
    2904             : 
    2905             :     /* Caller is responsible for locking the relation */
    2906        8762 :     rel = relation_open(relid, NoLock);
    2907        8762 :     tupdesc = RelationGetDescr(rel);
    2908             : 
    2909             :     /* Set up pstate */
    2910        8762 :     pstate = make_parsestate(NULL);
    2911        8762 :     pstate->p_sourcetext = queryString;
    2912        8762 :     rte = addRangeTableEntryForRelation(pstate,
    2913             :                                         rel,
    2914             :                                         AccessShareLock,
    2915             :                                         NULL,
    2916             :                                         false,
    2917             :                                         true);
    2918        8762 :     addRTEtoQuery(pstate, rte, false, true, true);
    2919             : 
    2920             :     /* Set up CreateStmtContext */
    2921        8762 :     cxt.pstate = pstate;
    2922        8762 :     if (stmt->relkind == OBJECT_FOREIGN_TABLE)
    2923             :     {
    2924         328 :         cxt.stmtType = "ALTER FOREIGN TABLE";
    2925         328 :         cxt.isforeign = true;
    2926             :     }
    2927             :     else
    2928             :     {
    2929        8434 :         cxt.stmtType = "ALTER TABLE";
    2930        8434 :         cxt.isforeign = false;
    2931             :     }
    2932        8762 :     cxt.relation = stmt->relation;
    2933        8762 :     cxt.rel = rel;
    2934        8762 :     cxt.inhRelations = NIL;
    2935        8762 :     cxt.isalter = true;
    2936        8762 :     cxt.columns = NIL;
    2937        8762 :     cxt.ckconstraints = NIL;
    2938        8762 :     cxt.fkconstraints = NIL;
    2939        8762 :     cxt.ixconstraints = NIL;
    2940        8762 :     cxt.inh_indexes = NIL;
    2941        8762 :     cxt.extstats = NIL;
    2942        8762 :     cxt.blist = NIL;
    2943        8762 :     cxt.alist = NIL;
    2944        8762 :     cxt.pkey = NULL;
    2945        8762 :     cxt.ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    2946        8762 :     cxt.partbound = NULL;
    2947        8762 :     cxt.ofType = false;
    2948             : 
    2949             :     /*
    2950             :      * The only subtypes that currently require parse transformation handling
    2951             :      * are ADD COLUMN, ADD CONSTRAINT and SET DATA TYPE.  These largely re-use
    2952             :      * code from CREATE TABLE.
    2953             :      */
    2954       17852 :     foreach(lcmd, stmt->cmds)
    2955             :     {
    2956        9122 :         AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
    2957             : 
    2958        9122 :         switch (cmd->subtype)
    2959             :         {
    2960             :             case AT_AddColumn:
    2961             :             case AT_AddColumnToView:
    2962             :                 {
    2963         950 :                     ColumnDef  *def = castNode(ColumnDef, cmd->def);
    2964             : 
    2965         950 :                     transformColumnDefinition(&cxt, def);
    2966             : 
    2967             :                     /*
    2968             :                      * If the column has a non-null default, we can't skip
    2969             :                      * validation of foreign keys.
    2970             :                      */
    2971         950 :                     if (def->raw_default != NULL)
    2972         260 :                         skipValidation = false;
    2973             : 
    2974             :                     /*
    2975             :                      * All constraints are processed in other ways. Remove the
    2976             :                      * original list
    2977             :                      */
    2978         950 :                     def->constraints = NIL;
    2979             : 
    2980         950 :                     newcmds = lappend(newcmds, cmd);
    2981         950 :                     break;
    2982             :                 }
    2983             : 
    2984             :             case AT_AddConstraint:
    2985             : 
    2986             :                 /*
    2987             :                  * The original AddConstraint cmd node doesn't go to newcmds
    2988             :                  */
    2989        1414 :                 if (IsA(cmd->def, Constraint))
    2990             :                 {
    2991        1414 :                     transformTableConstraint(&cxt, (Constraint *) cmd->def);
    2992        1402 :                     if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN)
    2993         644 :                         skipValidation = false;
    2994             :                 }
    2995             :                 else
    2996           0 :                     elog(ERROR, "unrecognized node type: %d",
    2997             :                          (int) nodeTag(cmd->def));
    2998        1402 :                 break;
    2999             : 
    3000             :             case AT_ProcessedConstraint:
    3001             : 
    3002             :                 /*
    3003             :                  * Already-transformed ADD CONSTRAINT, so just make it look
    3004             :                  * like the standard case.
    3005             :                  */
    3006         554 :                 cmd->subtype = AT_AddConstraint;
    3007         554 :                 newcmds = lappend(newcmds, cmd);
    3008         554 :                 break;
    3009             : 
    3010             :             case AT_AlterColumnType:
    3011             :                 {
    3012         374 :                     ColumnDef  *def = (ColumnDef *) cmd->def;
    3013             :                     AttrNumber  attnum;
    3014             : 
    3015             :                     /*
    3016             :                      * For ALTER COLUMN TYPE, transform the USING clause if
    3017             :                      * one was specified.
    3018             :                      */
    3019         374 :                     if (def->raw_default)
    3020             :                     {
    3021          88 :                         def->cooked_default =
    3022          88 :                             transformExpr(pstate, def->raw_default,
    3023             :                                           EXPR_KIND_ALTER_COL_TRANSFORM);
    3024             :                     }
    3025             : 
    3026             :                     /*
    3027             :                      * For identity column, create ALTER SEQUENCE command to
    3028             :                      * change the data type of the sequence.
    3029             :                      */
    3030         374 :                     attnum = get_attnum(relid, cmd->name);
    3031             : 
    3032             :                     /*
    3033             :                      * if attribute not found, something will error about it
    3034             :                      * later
    3035             :                      */
    3036         748 :                     if (attnum != InvalidAttrNumber &&
    3037         374 :                         TupleDescAttr(tupdesc, attnum - 1)->attidentity)
    3038             :                     {
    3039           8 :                         Oid         seq_relid = getOwnedSequence(relid, attnum);
    3040           8 :                         Oid         typeOid = typenameTypeId(pstate, def->typeName);
    3041           8 :                         AlterSeqStmt *altseqstmt = makeNode(AlterSeqStmt);
    3042             : 
    3043           8 :                         altseqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
    3044             :                                                             get_rel_name(seq_relid),
    3045             :                                                             -1);
    3046           8 :                         altseqstmt->options = list_make1(makeDefElem("as", (Node *) makeTypeNameFromOid(typeOid, -1), -1));
    3047           8 :                         altseqstmt->for_identity = true;
    3048           8 :                         cxt.blist = lappend(cxt.blist, altseqstmt);
    3049             :                     }
    3050             : 
    3051         374 :                     newcmds = lappend(newcmds, cmd);
    3052         374 :                     break;
    3053             :                 }
    3054             : 
    3055             :             case AT_AddIdentity:
    3056             :                 {
    3057          52 :                     Constraint *def = castNode(Constraint, cmd->def);
    3058          52 :                     ColumnDef  *newdef = makeNode(ColumnDef);
    3059             :                     AttrNumber  attnum;
    3060             : 
    3061          52 :                     newdef->colname = cmd->name;
    3062          52 :                     newdef->identity = def->generated_when;
    3063          52 :                     cmd->def = (Node *) newdef;
    3064             : 
    3065          52 :                     attnum = get_attnum(relid, cmd->name);
    3066             : 
    3067             :                     /*
    3068             :                      * if attribute not found, something will error about it
    3069             :                      * later
    3070             :                      */
    3071          52 :                     if (attnum != InvalidAttrNumber)
    3072          52 :                         generateSerialExtraStmts(&cxt, newdef,
    3073             :                                                  get_atttype(relid, attnum),
    3074             :                                                  def->options, true,
    3075             :                                                  NULL, NULL);
    3076             : 
    3077          52 :                     newcmds = lappend(newcmds, cmd);
    3078          52 :                     break;
    3079             :                 }
    3080             : 
    3081             :             case AT_SetIdentity:
    3082             :                 {
    3083             :                     /*
    3084             :                      * Create an ALTER SEQUENCE statement for the internal
    3085             :                      * sequence of the identity column.
    3086             :                      */
    3087             :                     ListCell   *lc;
    3088          16 :                     List       *newseqopts = NIL;
    3089          16 :                     List       *newdef = NIL;
    3090             :                     List       *seqlist;
    3091             :                     AttrNumber  attnum;
    3092             : 
    3093             :                     /*
    3094             :                      * Split options into those handled by ALTER SEQUENCE and
    3095             :                      * those for ALTER TABLE proper.
    3096             :                      */
    3097          44 :                     foreach(lc, castNode(List, cmd->def))
    3098             :                     {
    3099          28 :                         DefElem    *def = lfirst_node(DefElem, lc);
    3100             : 
    3101          28 :                         if (strcmp(def->defname, "generated") == 0)
    3102           8 :                             newdef = lappend(newdef, def);
    3103             :                         else
    3104          20 :                             newseqopts = lappend(newseqopts, def);
    3105             :                     }
    3106             : 
    3107          16 :                     attnum = get_attnum(relid, cmd->name);
    3108             : 
    3109          16 :                     if (attnum)
    3110             :                     {
    3111          16 :                         seqlist = getOwnedSequences(relid, attnum);
    3112          16 :                         if (seqlist)
    3113             :                         {
    3114             :                             AlterSeqStmt *seqstmt;
    3115             :                             Oid         seq_relid;
    3116             : 
    3117          12 :                             seqstmt = makeNode(AlterSeqStmt);
    3118          12 :                             seq_relid = linitial_oid(seqlist);
    3119          12 :                             seqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
    3120             :                                                              get_rel_name(seq_relid), -1);
    3121          12 :                             seqstmt->options = newseqopts;
    3122          12 :                             seqstmt->for_identity = true;
    3123          12 :                             seqstmt->missing_ok = false;
    3124             : 
    3125          12 :                             cxt.alist = lappend(cxt.alist, seqstmt);
    3126             :                         }
    3127             :                     }
    3128             : 
    3129             :                     /*
    3130             :                      * If column was not found or was not an identity column,
    3131             :                      * we just let the ALTER TABLE command error out later.
    3132             :                      */
    3133             : 
    3134          16 :                     cmd->def = (Node *) newdef;
    3135          16 :                     newcmds = lappend(newcmds, cmd);
    3136          16 :                     break;
    3137             :                 }
    3138             : 
    3139             :             case AT_AttachPartition:
    3140             :             case AT_DetachPartition:
    3141             :                 {
    3142        1184 :                     PartitionCmd *partcmd = (PartitionCmd *) cmd->def;
    3143             : 
    3144        1184 :                     transformPartitionCmd(&cxt, partcmd);
    3145             :                     /* assign transformed value of the partition bound */
    3146        1164 :                     partcmd->bound = cxt.partbound;
    3147             :                 }
    3148             : 
    3149        1164 :                 newcmds = lappend(newcmds, cmd);
    3150        1164 :                 break;
    3151             : 
    3152             :             default:
    3153        4578 :                 newcmds = lappend(newcmds, cmd);
    3154        4578 :                 break;
    3155             :         }
    3156             :     }
    3157             : 
    3158             :     /*
    3159             :      * transformIndexConstraints wants cxt.alist to contain only index
    3160             :      * statements, so transfer anything we already have into save_alist
    3161             :      * immediately.
    3162             :      */
    3163        8730 :     save_alist = cxt.alist;
    3164        8730 :     cxt.alist = NIL;
    3165             : 
    3166             :     /* Postprocess constraints */
    3167        8730 :     transformIndexConstraints(&cxt);
    3168        8730 :     transformFKConstraints(&cxt, skipValidation, true);
    3169        8730 :     transformCheckConstraints(&cxt, false);
    3170             : 
    3171             :     /*
    3172             :      * Push any index-creation commands into the ALTER, so that they can be
    3173             :      * scheduled nicely by tablecmds.c.  Note that tablecmds.c assumes that
    3174             :      * the IndexStmt attached to an AT_AddIndex or AT_AddIndexConstraint
    3175             :      * subcommand has already been through transformIndexStmt.
    3176             :      */
    3177        9132 :     foreach(l, cxt.alist)
    3178             :     {
    3179         402 :         IndexStmt  *idxstmt = lfirst_node(IndexStmt, l);
    3180             : 
    3181         402 :         idxstmt = transformIndexStmt(relid, idxstmt, queryString);
    3182         402 :         newcmd = makeNode(AlterTableCmd);
    3183         402 :         newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex;
    3184         402 :         newcmd->def = (Node *) idxstmt;
    3185         402 :         newcmds = lappend(newcmds, newcmd);
    3186             :     }
    3187        8730 :     cxt.alist = NIL;
    3188             : 
    3189             :     /* Append any CHECK or FK constraints to the commands list */
    3190        9112 :     foreach(l, cxt.ckconstraints)
    3191             :     {
    3192         382 :         newcmd = makeNode(AlterTableCmd);
    3193         382 :         newcmd->subtype = AT_AddConstraint;
    3194         382 :         newcmd->def = (Node *) lfirst(l);
    3195         382 :         newcmds = lappend(newcmds, newcmd);
    3196             :     }
    3197        9374 :     foreach(l, cxt.fkconstraints)
    3198             :     {
    3199         644 :         newcmd = makeNode(AlterTableCmd);
    3200         644 :         newcmd->subtype = AT_AddConstraint;
    3201         644 :         newcmd->def = (Node *) lfirst(l);
    3202         644 :         newcmds = lappend(newcmds, newcmd);
    3203             :     }
    3204             : 
    3205             :     /* Append extended statistic objects */
    3206        8730 :     transformExtendedStatistics(&cxt);
    3207             : 
    3208             :     /* Close rel */
    3209        8730 :     relation_close(rel, NoLock);
    3210             : 
    3211             :     /*
    3212             :      * Output results.
    3213             :      */
    3214        8730 :     stmt->cmds = newcmds;
    3215             : 
    3216        8730 :     result = lappend(cxt.blist, stmt);
    3217        8730 :     result = list_concat(result, cxt.alist);
    3218        8730 :     result = list_concat(result, save_alist);
    3219             : 
    3220        8730 :     return result;
    3221             : }
    3222             : 
    3223             : 
    3224             : /*
    3225             :  * Preprocess a list of column constraint clauses
    3226             :  * to attach constraint attributes to their primary constraint nodes
    3227             :  * and detect inconsistent/misplaced constraint attributes.
    3228             :  *
    3229             :  * NOTE: currently, attributes are only supported for FOREIGN KEY, UNIQUE,
    3230             :  * EXCLUSION, and PRIMARY KEY constraints, but someday they ought to be
    3231             :  * supported for other constraint types.
    3232             :  */
    3233             : static void
    3234       45012 : transformConstraintAttrs(CreateStmtContext *cxt, List *constraintList)
    3235             : {
    3236       45012 :     Constraint *lastprimarycon = NULL;
    3237       45012 :     bool        saw_deferrability = false;
    3238       45012 :     bool        saw_initially = false;
    3239             :     ListCell   *clist;
    3240             : 
    3241             : #define SUPPORTS_ATTRS(node)                \
    3242             :     ((node) != NULL &&                      \
    3243             :      ((node)->contype == CONSTR_PRIMARY ||   \
    3244             :       (node)->contype == CONSTR_UNIQUE ||    \
    3245             :       (node)->contype == CONSTR_EXCLUSION || \
    3246             :       (node)->contype == CONSTR_FOREIGN))
    3247             : 
    3248       54554 :     foreach(clist, constraintList)
    3249             :     {
    3250        9542 :         Constraint *con = (Constraint *) lfirst(clist);
    3251             : 
    3252        9542 :         if (!IsA(con, Constraint))
    3253           0 :             elog(ERROR, "unrecognized node type: %d",
    3254             :                  (int) nodeTag(con));
    3255        9542 :         switch (con->contype)
    3256             :         {
    3257             :             case CONSTR_ATTR_DEFERRABLE:
    3258          38 :                 if (!SUPPORTS_ATTRS(lastprimarycon))
    3259           0 :                     ereport(ERROR,
    3260             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3261             :                              errmsg("misplaced DEFERRABLE clause"),
    3262             :                              parser_errposition(cxt->pstate, con->location)));
    3263          38 :                 if (saw_deferrability)
    3264           0 :                     ereport(ERROR,
    3265             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3266             :                              errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
    3267             :                              parser_errposition(cxt->pstate, con->location)));
    3268          38 :                 saw_deferrability = true;
    3269          38 :                 lastprimarycon->deferrable = true;
    3270          38 :                 break;
    3271             : 
    3272             :             case CONSTR_ATTR_NOT_DEFERRABLE:
    3273           0 :                 if (!SUPPORTS_ATTRS(lastprimarycon))
    3274           0 :                     ereport(ERROR,
    3275             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3276             :                              errmsg("misplaced NOT DEFERRABLE clause"),
    3277             :                              parser_errposition(cxt->pstate, con->location)));
    3278           0 :                 if (saw_deferrability)
    3279           0 :                     ereport(ERROR,
    3280             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3281             :                              errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
    3282             :                              parser_errposition(cxt->pstate, con->location)));
    3283           0 :                 saw_deferrability = true;
    3284           0 :                 lastprimarycon->deferrable = false;
    3285           0 :                 if (saw_initially &&
    3286           0 :                     lastprimarycon->initdeferred)
    3287           0 :                     ereport(ERROR,
    3288             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3289             :                              errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
    3290             :                              parser_errposition(cxt->pstate, con->location)));
    3291           0 :                 break;
    3292             : 
    3293             :             case CONSTR_ATTR_DEFERRED:
    3294          18 :                 if (!SUPPORTS_ATTRS(lastprimarycon))
    3295           0 :                     ereport(ERROR,
    3296             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3297             :                              errmsg("misplaced INITIALLY DEFERRED clause"),
    3298             :                              parser_errposition(cxt->pstate, con->location)));
    3299          18 :                 if (saw_initially)
    3300           0 :                     ereport(ERROR,
    3301             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3302             :                              errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
    3303             :                              parser_errposition(cxt->pstate, con->location)));
    3304          18 :                 saw_initially = true;
    3305          18 :                 lastprimarycon->initdeferred = true;
    3306             : 
    3307             :                 /*
    3308             :                  * If only INITIALLY DEFERRED appears, assume DEFERRABLE
    3309             :                  */
    3310          18 :                 if (!saw_deferrability)
    3311           0 :                     lastprimarycon->deferrable = true;
    3312          18 :                 else if (!lastprimarycon->deferrable)
    3313           0 :                     ereport(ERROR,
    3314             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3315             :                              errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
    3316             :                              parser_errposition(cxt->pstate, con->location)));
    3317          18 :                 break;
    3318             : 
    3319             :             case CONSTR_ATTR_IMMEDIATE:
    3320           0 :                 if (!SUPPORTS_ATTRS(lastprimarycon))
    3321           0 :                     ereport(ERROR,
    3322             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3323             :                              errmsg("misplaced INITIALLY IMMEDIATE clause"),
    3324             :                              parser_errposition(cxt->pstate, con->location)));
    3325           0 :                 if (saw_initially)
    3326           0 :                     ereport(ERROR,
    3327             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3328             :                              errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
    3329             :                              parser_errposition(cxt->pstate, con->location)));
    3330           0 :                 saw_initially = true;
    3331           0 :                 lastprimarycon->initdeferred = false;
    3332           0 :                 break;
    3333             : 
    3334             :             default:
    3335             :                 /* Otherwise it's not an attribute */
    3336        9486 :                 lastprimarycon = con;
    3337             :                 /* reset flags for new primary node */
    3338        9486 :                 saw_deferrability = false;
    3339        9486 :                 saw_initially = false;
    3340        9486 :                 break;
    3341             :         }
    3342             :     }
    3343       45012 : }
    3344             : 
    3345             : /*
    3346             :  * Special handling of type definition for a column
    3347             :  */
    3348             : static void
    3349       44910 : transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
    3350             : {
    3351             :     /*
    3352             :      * All we really need to do here is verify that the type is valid,
    3353             :      * including any collation spec that might be present.
    3354             :      */
    3355       44910 :     Type        ctype = typenameType(cxt->pstate, column->typeName, NULL);
    3356             : 
    3357       44904 :     if (column->collClause)
    3358             :     {
    3359         120 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(ctype);
    3360             : 
    3361         240 :         LookupCollation(cxt->pstate,
    3362         120 :                         column->collClause->collname,
    3363         120 :                         column->collClause->location);
    3364             :         /* Complain if COLLATE is applied to an uncollatable type */
    3365         120 :         if (!OidIsValid(typtup->typcollation))
    3366           4 :             ereport(ERROR,
    3367             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3368             :                      errmsg("collations are not supported by type %s",
    3369             :                             format_type_be(typtup->oid)),
    3370             :                      parser_errposition(cxt->pstate,
    3371             :                                         column->collClause->location)));
    3372             :     }
    3373             : 
    3374       44900 :     ReleaseSysCache(ctype);
    3375       44900 : }
    3376             : 
    3377             : 
    3378             : /*
    3379             :  * transformCreateSchemaStmt -
    3380             :  *    analyzes the CREATE SCHEMA statement
    3381             :  *
    3382             :  * Split the schema element list into individual commands and place
    3383             :  * them in the result list in an order such that there are no forward
    3384             :  * references (e.g. GRANT to a table created later in the list). Note
    3385             :  * that the logic we use for determining forward references is
    3386             :  * presently quite incomplete.
    3387             :  *
    3388             :  * SQL also allows constraints to make forward references, so thumb through
    3389             :  * the table columns and move forward references to a posterior alter-table
    3390             :  * command.
    3391             :  *
    3392             :  * The result is a list of parse nodes that still need to be analyzed ---
    3393             :  * but we can't analyze the later commands until we've executed the earlier
    3394             :  * ones, because of possible inter-object references.
    3395             :  *
    3396             :  * Note: this breaks the rules a little bit by modifying schema-name fields
    3397             :  * within passed-in structs.  However, the transformation would be the same
    3398             :  * if done over, so it should be all right to scribble on the input to this
    3399             :  * extent.
    3400             :  */
    3401             : List *
    3402         550 : transformCreateSchemaStmt(CreateSchemaStmt *stmt)
    3403             : {
    3404             :     CreateSchemaStmtContext cxt;
    3405             :     List       *result;
    3406             :     ListCell   *elements;
    3407             : 
    3408         550 :     cxt.stmtType = "CREATE SCHEMA";
    3409         550 :     cxt.schemaname = stmt->schemaname;
    3410         550 :     cxt.authrole = (RoleSpec *) stmt->authrole;
    3411         550 :     cxt.sequences = NIL;
    3412         550 :     cxt.tables = NIL;
    3413         550 :     cxt.views = NIL;
    3414         550 :     cxt.indexes = NIL;
    3415         550 :     cxt.triggers = NIL;
    3416         550 :     cxt.grants = NIL;
    3417             : 
    3418             :     /*
    3419             :      * Run through each schema element in the schema element list. Separate
    3420             :      * statements by type, and do preliminary analysis.
    3421             :      */
    3422         598 :     foreach(elements, stmt->schemaElts)
    3423             :     {
    3424          48 :         Node       *element = lfirst(elements);
    3425             : 
    3426          48 :         switch (nodeTag(element))
    3427             :         {
    3428             :             case T_CreateSeqStmt:
    3429             :                 {
    3430           0 :                     CreateSeqStmt *elp = (CreateSeqStmt *) element;
    3431             : 
    3432           0 :                     setSchemaName(cxt.schemaname, &elp->sequence->schemaname);
    3433           0 :                     cxt.sequences = lappend(cxt.sequences, element);
    3434             :                 }
    3435           0 :                 break;
    3436             : 
    3437             :             case T_CreateStmt:
    3438             :                 {
    3439          30 :                     CreateStmt *elp = (CreateStmt *) element;
    3440             : 
    3441          30 :                     setSchemaName(cxt.schemaname, &elp->relation->schemaname);
    3442             : 
    3443             :                     /*
    3444             :                      * XXX todo: deal with constraints
    3445             :                      */
    3446          30 :                     cxt.tables = lappend(cxt.tables, element);
    3447             :                 }
    3448          30 :                 break;
    3449             : 
    3450             :             case T_ViewStmt:
    3451             :                 {
    3452          10 :                     ViewStmt   *elp = (ViewStmt *) element;
    3453             : 
    3454          10 :                     setSchemaName(cxt.schemaname, &elp->view->schemaname);
    3455             : 
    3456             :                     /*
    3457             :                      * XXX todo: deal with references between views
    3458             :                      */
    3459          10 :                     cxt.views = lappend(cxt.views, element);
    3460             :                 }
    3461          10 :                 break;
    3462             : 
    3463             :             case T_IndexStmt:
    3464             :                 {
    3465           8 :                     IndexStmt  *elp = (IndexStmt *) element;
    3466             : 
    3467           8 :                     setSchemaName(cxt.schemaname, &elp->relation->schemaname);
    3468           8 :                     cxt.indexes = lappend(cxt.indexes, element);
    3469             :                 }
    3470           8 :                 break;
    3471             : 
    3472             :             case T_CreateTrigStmt:
    3473             :                 {
    3474           0 :                     CreateTrigStmt *elp = (CreateTrigStmt *) element;
    3475             : 
    3476           0 :                     setSchemaName(cxt.schemaname, &elp->relation->schemaname);
    3477           0 :                     cxt.triggers = lappend(cxt.triggers, element);
    3478             :                 }
    3479           0 :                 break;
    3480             : 
    3481             :             case T_GrantStmt:
    3482           0 :                 cxt.grants = lappend(cxt.grants, element);
    3483           0 :                 break;
    3484             : 
    3485             :             default:
    3486           0 :                 elog(ERROR, "unrecognized node type: %d",
    3487             :                      (int) nodeTag(element));
    3488             :         }
    3489             :     }
    3490             : 
    3491         550 :     result = NIL;
    3492         550 :     result = list_concat(result, cxt.sequences);
    3493         550 :     result = list_concat(result, cxt.tables);
    3494         550 :     result = list_concat(result, cxt.views);
    3495         550 :     result = list_concat(result, cxt.indexes);
    3496         550 :     result = list_concat(result, cxt.triggers);
    3497         550 :     result = list_concat(result, cxt.grants);
    3498             : 
    3499         550 :     return result;
    3500             : }
    3501             : 
    3502             : /*
    3503             :  * setSchemaName
    3504             :  *      Set or check schema name in an element of a CREATE SCHEMA command
    3505             :  */
    3506             : static void
    3507          48 : setSchemaName(char *context_schema, char **stmt_schema_name)
    3508             : {
    3509          48 :     if (*stmt_schema_name == NULL)
    3510          48 :         *stmt_schema_name = context_schema;
    3511           0 :     else if (strcmp(context_schema, *stmt_schema_name) != 0)
    3512           0 :         ereport(ERROR,
    3513             :                 (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
    3514             :                  errmsg("CREATE specifies a schema (%s) "
    3515             :                         "different from the one being created (%s)",
    3516             :                         *stmt_schema_name, context_schema)));
    3517          48 : }
    3518             : 
    3519             : /*
    3520             :  * transformPartitionCmd
    3521             :  *      Analyze the ATTACH/DETACH PARTITION command
    3522             :  *
    3523             :  * In case of the ATTACH PARTITION command, cxt->partbound is set to the
    3524             :  * transformed value of cmd->bound.
    3525             :  */
    3526             : static void
    3527        1184 : transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
    3528             : {
    3529        1184 :     Relation    parentRel = cxt->rel;
    3530             : 
    3531        1184 :     switch (parentRel->rd_rel->relkind)
    3532             :     {
    3533             :         case RELKIND_PARTITIONED_TABLE:
    3534             :             /* transform the partition bound, if any */
    3535             :             Assert(RelationGetPartitionKey(parentRel) != NULL);
    3536        1036 :             if (cmd->bound != NULL)
    3537         920 :                 cxt->partbound = transformPartitionBound(cxt->pstate, parentRel,
    3538             :                                                          cmd->bound);
    3539        1024 :             break;
    3540             :         case RELKIND_PARTITIONED_INDEX:
    3541             :             /* nothing to check */
    3542             :             Assert(cmd->bound == NULL);
    3543         140 :             break;
    3544             :         case RELKIND_RELATION:
    3545             :             /* the table must be partitioned */
    3546           8 :             ereport(ERROR,
    3547             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3548             :                      errmsg("table \"%s\" is not partitioned",
    3549             :                             RelationGetRelationName(parentRel))));
    3550             :             break;
    3551             :         case RELKIND_INDEX:
    3552             :             /* the index must be partitioned */
    3553           0 :             ereport(ERROR,
    3554             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3555             :                      errmsg("index \"%s\" is not partitioned",
    3556             :                             RelationGetRelationName(parentRel))));
    3557             :             break;
    3558             :         default:
    3559             :             /* parser shouldn't let this case through */
    3560           0 :             elog(ERROR, "\"%s\" is not a partitioned table or index",
    3561             :                  RelationGetRelationName(parentRel));
    3562             :             break;
    3563             :     }
    3564        1164 : }
    3565             : 
    3566             : /*
    3567             :  * transformPartitionBound
    3568             :  *
    3569             :  * Transform a partition bound specification
    3570             :  */
    3571             : PartitionBoundSpec *
    3572        3430 : transformPartitionBound(ParseState *pstate, Relation parent,
    3573             :                         PartitionBoundSpec *spec)
    3574             : {
    3575             :     PartitionBoundSpec *result_spec;
    3576        3430 :     PartitionKey key = RelationGetPartitionKey(parent);
    3577        3430 :     char        strategy = get_partition_strategy(key);
    3578        3430 :     int         partnatts = get_partition_natts(key);
    3579        3430 :     List       *partexprs = get_partition_exprs(key);
    3580             : 
    3581             :     /* Avoid scribbling on input */
    3582        3430 :     result_spec = copyObject(spec);
    3583             : 
    3584        3430 :     if (spec->is_default)
    3585             :     {
    3586         218 :         if (strategy == PARTITION_STRATEGY_HASH)
    3587           4 :             ereport(ERROR,
    3588             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3589             :                      errmsg("a hash-partitioned table may not have a default partition")));
    3590             : 
    3591             :         /*
    3592             :          * In case of the default partition, parser had no way to identify the
    3593             :          * partition strategy. Assign the parent's strategy to the default
    3594             :          * partition bound spec.
    3595             :          */
    3596         214 :         result_spec->strategy = strategy;
    3597             : 
    3598         214 :         return result_spec;
    3599             :     }
    3600             : 
    3601        3212 :     if (strategy == PARTITION_STRATEGY_HASH)
    3602             :     {
    3603         226 :         if (spec->strategy != PARTITION_STRATEGY_HASH)
    3604           8 :             ereport(ERROR,
    3605             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3606             :                      errmsg("invalid bound specification for a hash partition"),
    3607             :                      parser_errposition(pstate, exprLocation((Node *) spec))));
    3608             : 
    3609         218 :         if (spec->modulus <= 0)
    3610           8 :             ereport(ERROR,
    3611             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3612             :                      errmsg("modulus for hash partition must be a positive integer")));
    3613             : 
    3614             :         Assert(spec->remainder >= 0);
    3615             : 
    3616         210 :         if (spec->remainder >= spec->modulus)
    3617           8 :             ereport(ERROR,
    3618             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3619             :                      errmsg("remainder for hash partition must be less than modulus")));
    3620             :     }
    3621        2986 :     else if (strategy == PARTITION_STRATEGY_LIST)
    3622             :     {
    3623             :         ListCell   *cell;
    3624             :         char       *colname;
    3625             :         Oid         coltype;
    3626             :         int32       coltypmod;
    3627             : 
    3628        1436 :         if (spec->strategy != PARTITION_STRATEGY_LIST)
    3629          12 :             ereport(ERROR,
    3630             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3631             :                      errmsg("invalid bound specification for a list partition"),
    3632             :                      parser_errposition(pstate, exprLocation((Node *) spec))));
    3633             : 
    3634             :         /* Get the only column's name in case we need to output an error */
    3635        1424 :         if (key->partattrs[0] != 0)
    3636        1378 :             colname = get_attname(RelationGetRelid(parent),
    3637        1378 :                                   key->partattrs[0], false);
    3638             :         else
    3639          92 :             colname = deparse_expression((Node *) linitial(partexprs),
    3640          46 :                                          deparse_context_for(RelationGetRelationName(parent),
    3641             :                                                              RelationGetRelid(parent)),
    3642             :                                          false, false);
    3643             :         /* Need its type data too */
    3644        1424 :         coltype = get_partition_col_typid(key, 0);
    3645        1424 :         coltypmod = get_partition_col_typmod(key, 0);
    3646             : 
    3647        1424 :         result_spec->listdatums = NIL;
    3648        3406 :         foreach(cell, spec->listdatums)
    3649             :         {
    3650        1990 :             A_Const    *con = castNode(A_Const, lfirst(cell));
    3651             :             Const      *value;
    3652             :             ListCell   *cell2;
    3653             :             bool        duplicate;
    3654             : 
    3655        1990 :             value = transformPartitionBoundValue(pstate, con,
    3656             :                                                  colname, coltype, coltypmod);
    3657             : 
    3658             :             /* Don't add to the result if the value is a duplicate */
    3659        1982 :             duplicate = false;
    3660        3006 :             foreach(cell2, result_spec->listdatums)
    3661             :             {
    3662        1024 :                 Const      *value2 = castNode(Const, lfirst(cell2));
    3663             : 
    3664        1024 :                 if (equal(value, value2))
    3665             :                 {
    3666           0 :                     duplicate = true;
    3667           0 :                     break;
    3668             :                 }
    3669             :             }
    3670        1982 :             if (duplicate)
    3671           0 :                 continue;
    3672             : 
    3673        1982 :             result_spec->listdatums = lappend(result_spec->listdatums,
    3674             :                                               value);
    3675             :         }
    3676             :     }
    3677        1550 :     else if (strategy == PARTITION_STRATEGY_RANGE)
    3678             :     {
    3679             :         ListCell   *cell1,
    3680             :                    *cell2;
    3681             :         int         i,
    3682             :                     j;
    3683             : 
    3684        1550 :         if (spec->strategy != PARTITION_STRATEGY_RANGE)
    3685          12 :             ereport(ERROR,
    3686             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3687             :                      errmsg("invalid bound specification for a range partition"),
    3688             :                      parser_errposition(pstate, exprLocation((Node *) spec))));
    3689             : 
    3690        1538 :         if (list_length(spec->lowerdatums) != partnatts)
    3691           4 :             ereport(ERROR,
    3692             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3693             :                      errmsg("FROM must specify exactly one value per partitioning column")));
    3694        1534 :         if (list_length(spec->upperdatums) != partnatts)
    3695           4 :             ereport(ERROR,
    3696             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3697             :                      errmsg("TO must specify exactly one value per partitioning column")));
    3698             : 
    3699             :         /*
    3700             :          * Once we see MINVALUE or MAXVALUE for one column, the remaining
    3701             :          * columns must be the same.
    3702             :          */
    3703        1530 :         validateInfiniteBounds(pstate, spec->lowerdatums);
    3704        1522 :         validateInfiniteBounds(pstate, spec->upperdatums);
    3705             : 
    3706             :         /* Transform all the constants */
    3707        1518 :         i = j = 0;
    3708        1518 :         result_spec->lowerdatums = result_spec->upperdatums = NIL;
    3709        3522 :         forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
    3710             :         {
    3711        2008 :             PartitionRangeDatum *ldatum = (PartitionRangeDatum *) lfirst(cell1);
    3712        2008 :             PartitionRangeDatum *rdatum = (PartitionRangeDatum *) lfirst(cell2);
    3713             :             char       *colname;
    3714             :             Oid         coltype;
    3715             :             int32       coltypmod;
    3716             :             A_Const    *con;
    3717             :             Const      *value;
    3718             : 
    3719             :             /* Get the column's name in case we need to output an error */
    3720        2008 :             if (key->partattrs[i] != 0)
    3721        1686 :                 colname = get_attname(RelationGetRelid(parent),
    3722        1686 :                                       key->partattrs[i], false);
    3723             :             else
    3724             :             {
    3725         644 :                 colname = deparse_expression((Node *) list_nth(partexprs, j),
    3726         322 :                                              deparse_context_for(RelationGetRelationName(parent),
    3727             :                                                                  RelationGetRelid(parent)),
    3728             :                                              false, false);
    3729         322 :                 ++j;
    3730             :             }
    3731             :             /* Need its type data too */
    3732        2008 :             coltype = get_partition_col_typid(key, i);
    3733        2008 :             coltypmod = get_partition_col_typmod(key, i);
    3734             : 
    3735        2008 :             if (ldatum->value)
    3736             :             {
    3737        1828 :                 con = castNode(A_Const, ldatum->value);
    3738        1828 :                 value = transformPartitionBoundValue(pstate, con,
    3739             :                                                      colname,
    3740             :                                                      coltype, coltypmod);
    3741        1828 :                 if (value->constisnull)
    3742           4 :                     ereport(ERROR,
    3743             :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3744             :                              errmsg("cannot specify NULL in range bound")));
    3745        1824 :                 ldatum = copyObject(ldatum);    /* don't scribble on input */
    3746        1824 :                 ldatum->value = (Node *) value;
    3747             :             }
    3748             : 
    3749        2004 :             if (rdatum->value)
    3750             :             {
    3751        1812 :                 con = castNode(A_Const, rdatum->value);
    3752        1812 :                 value = transformPartitionBoundValue(pstate, con,
    3753             :                                                      colname,
    3754             :                                                      coltype, coltypmod);
    3755        1812 :                 if (value->constisnull)
    3756           0 :                     ereport(ERROR,
    3757             :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    3758             :                              errmsg("cannot specify NULL in range bound")));
    3759        1812 :                 rdatum = copyObject(rdatum);    /* don't scribble on input */
    3760        1812 :                 rdatum->value = (Node *) value;
    3761             :             }
    3762             : 
    3763        2004 :             result_spec->lowerdatums = lappend(result_spec->lowerdatums,
    3764             :                                                ldatum);
    3765        2004 :             result_spec->upperdatums = lappend(result_spec->upperdatums,
    3766             :                                                rdatum);
    3767             : 
    3768        2004 :             ++i;
    3769             :         }
    3770             :     }
    3771             :     else
    3772           0 :         elog(ERROR, "unexpected partition strategy: %d", (int) strategy);
    3773             : 
    3774        3132 :     return result_spec;
    3775             : }
    3776             : 
    3777             : /*
    3778             :  * validateInfiniteBounds
    3779             :  *
    3780             :  * Check that a MAXVALUE or MINVALUE specification in a partition bound is
    3781             :  * followed only by more of the same.
    3782             :  */
    3783             : static void
    3784        3052 : validateInfiniteBounds(ParseState *pstate, List *blist)
    3785             : {
    3786             :     ListCell   *lc;
    3787        3052 :     PartitionRangeDatumKind kind = PARTITION_RANGE_DATUM_VALUE;
    3788             : 
    3789        7100 :     foreach(lc, blist)
    3790             :     {
    3791        4060 :         PartitionRangeDatum *prd = castNode(PartitionRangeDatum, lfirst(lc));
    3792             : 
    3793        4060 :         if (kind == prd->kind)
    3794        3768 :             continue;
    3795             : 
    3796         292 :         switch (kind)
    3797             :         {
    3798             :             case PARTITION_RANGE_DATUM_VALUE:
    3799         280 :                 kind = prd->kind;
    3800         280 :                 break;
    3801             : 
    3802             :             case PARTITION_RANGE_DATUM_MAXVALUE:
    3803           4 :                 ereport(ERROR,
    3804             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3805             :                          errmsg("every bound following MAXVALUE must also be MAXVALUE"),
    3806             :                          parser_errposition(pstate, exprLocation((Node *) prd))));
    3807             :                 break;
    3808             : 
    3809             :             case PARTITION_RANGE_DATUM_MINVALUE:
    3810           8 :                 ereport(ERROR,
    3811             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3812             :                          errmsg("every bound following MINVALUE must also be MINVALUE"),
    3813             :                          parser_errposition(pstate, exprLocation((Node *) prd))));
    3814             :                 break;
    3815             :         }
    3816             :     }
    3817        3040 : }
    3818             : 
    3819             : /*
    3820             :  * Transform one constant in a partition bound spec
    3821             :  */
    3822             : static Const *
    3823        5630 : transformPartitionBoundValue(ParseState *pstate, A_Const *con,
    3824             :                              const char *colName, Oid colType, int32 colTypmod)
    3825             : {
    3826             :     Node       *value;
    3827             : 
    3828             :     /* Make it into a Const */
    3829        5630 :     value = (Node *) make_const(pstate, &con->val, con->location);
    3830             : 
    3831             :     /* Coerce to correct type */
    3832        5630 :     value = coerce_to_target_type(pstate,
    3833             :                                   value, exprType(value),
    3834             :                                   colType,
    3835             :                                   colTypmod,
    3836             :                                   COERCION_ASSIGNMENT,
    3837             :                                   COERCE_IMPLICIT_CAST,
    3838             :                                   -1);
    3839             : 
    3840        5630 :     if (value == NULL)
    3841           4 :         ereport(ERROR,
    3842             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3843             :                  errmsg("specified value cannot be cast to type %s for column \"%s\"",
    3844             :                         format_type_be(colType), colName),
    3845             :                  parser_errposition(pstate, con->location)));
    3846             : 
    3847             :     /* Simplify the expression, in case we had a coercion */
    3848        5626 :     if (!IsA(value, Const))
    3849         212 :         value = (Node *) expression_planner((Expr *) value);
    3850             : 
    3851             :     /* Fail if we don't have a constant (i.e., non-immutable coercion) */
    3852        5626 :     if (!IsA(value, Const))
    3853           4 :         ereport(ERROR,
    3854             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3855             :                  errmsg("specified value cannot be cast to type %s for column \"%s\"",
    3856             :                         format_type_be(colType), colName),
    3857             :                  errdetail("The cast requires a non-immutable conversion."),
    3858             :                  errhint("Try putting the literal value in single quotes."),
    3859             :                  parser_errposition(pstate, con->location)));
    3860             : 
    3861        5622 :     return (Const *) value;
    3862             : }

Generated by: LCOV version 1.13