OSDN Git Service

Update copyright for 2009.
[pg-rex/syncrep.git] / src / backend / parser / parse_utilcmd.c
index f17ad48..e011208 100644 (file)
  * a quick copyObject() call before manipulating the query tree.
  *
  *
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.2 2007/07/17 05:02:02 neilc Exp $
+ *     $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.20 2009/01/01 17:23:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,8 @@
 
 #include "access/genam.h"
 #include "access/heapam.h"
+#include "access/reloptions.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
@@ -38,7 +40,7 @@
 #include "commands/tablespace.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/clauses.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/analyze.h"
 #include "parser/gramparse.h"
 #include "parser/parse_clause.h"
@@ -98,13 +100,13 @@ static void transformTableConstraint(ParseState *pstate,
                                                 Constraint *constraint);
 static void transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
                                         InhRelation *inhrelation);
-static IndexStmt *generateClonedIndexStmt(CreateStmtContext *cxt, 
-                                                       Relation parent_index, AttrNumber *attmap);
+static IndexStmt *generateClonedIndexStmt(CreateStmtContext *cxt,
+                                               Relation parent_index, AttrNumber *attmap);
 static List *get_opclass(Oid opclass, Oid actual_datatype);
 static void transformIndexConstraints(ParseState *pstate,
                                                  CreateStmtContext *cxt);
 static IndexStmt *transformIndexConstraint(Constraint *constraint,
-                                                                                  CreateStmtContext *cxt);
+                                                CreateStmtContext *cxt);
 static void transformFKConstraints(ParseState *pstate,
                                           CreateStmtContext *cxt,
                                           bool skipValidation,
@@ -138,11 +140,25 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
        ListCell   *elements;
 
        /*
-        * We must not scribble on the passed-in CreateStmt, so copy it.  (This
-        * is overkill, but easy.)
+        * We must not scribble on the passed-in CreateStmt, so copy it.  (This is
+        * overkill, but easy.)
         */
        stmt = (CreateStmt *) copyObject(stmt);
 
+       /*
+        * If the target relation name isn't schema-qualified, make it so.  This
+        * prevents some corner cases in which added-on rewritten commands might
+        * think they should apply to other relations that have the same name and
+        * are earlier in the search path.      "istemp" is equivalent to a
+        * specification of pg_temp, so no need for anything extra in that case.
+        */
+       if (stmt->relation->schemaname == NULL && !stmt->relation->istemp)
+       {
+               Oid                     namespaceid = RangeVarGetCreationNamespace(stmt->relation);
+
+               stmt->relation->schemaname = get_namespace_name(namespaceid);
+       }
+
        /* Set up pstate */
        pstate = make_parsestate(NULL);
        pstate->p_sourcetext = queryString;
@@ -250,7 +266,8 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 
        /* Check for SERIAL pseudo-types */
        is_serial = false;
-       if (list_length(column->typename->names) == 1)
+       if (list_length(column->typename->names) == 1 &&
+               !column->typename->pct_type)
        {
                char       *typname = strVal(linitial(column->typename->names));
 
@@ -268,6 +285,16 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                        column->typename->names = NIL;
                        column->typename->typeid = INT8OID;
                }
+
+               /*
+                * We have to reject "serial[]" explicitly, because once we've
+                * set typeid, LookupTypeName won't notice arrayBounds.  We don't
+                * need any special coding for serial(typmod) though.
+                */
+               if (is_serial && column->typename->arrayBounds != NIL)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("array of serial is not implemented")));
        }
 
        /* Do necessary work on the column type declaration */
@@ -281,6 +308,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                char       *sname;
                char       *qstring;
                A_Const    *snamenode;
+               TypeCast   *castnode;
                FuncCall   *funccallnode;
                CreateSeqStmt *seqstmt;
                AlterSeqStmt *altseqstmt;
@@ -318,7 +346,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                 * TABLE.
                 */
                seqstmt = makeNode(CreateSeqStmt);
-               seqstmt->sequence = makeRangeVar(snamespace, sname);
+               seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
                seqstmt->options = NIL;
 
                cxt->blist = lappend(cxt->blist, seqstmt);
@@ -329,7 +357,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                 * done after this CREATE/ALTER TABLE.
                 */
                altseqstmt = makeNode(AlterSeqStmt);
-               altseqstmt->sequence = makeRangeVar(snamespace, sname);
+               altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
                attnamelist = list_make3(makeString(snamespace),
                                                                 makeString(cxt->relation->relname),
                                                                 makeString(column->colname));
@@ -352,12 +380,18 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                snamenode = makeNode(A_Const);
                snamenode->val.type = T_String;
                snamenode->val.val.str = qstring;
-               snamenode->typename = SystemTypeName("regclass");
+               snamenode->location = -1;
+               castnode = makeNode(TypeCast);
+               castnode->typename = SystemTypeName("regclass");
+               castnode->arg = (Node *) snamenode;
+               castnode->location = -1;
                funccallnode = makeNode(FuncCall);
                funccallnode->funcname = SystemFuncName("nextval");
-               funccallnode->args = list_make1(snamenode);
+               funccallnode->args = list_make1(castnode);
                funccallnode->agg_star = false;
                funccallnode->agg_distinct = false;
+               funccallnode->func_variadic = false;
+               funccallnode->over = NULL;
                funccallnode->location = -1;
 
                constraint = makeNode(Constraint);
@@ -426,7 +460,6 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                                                        (errcode(ERRCODE_SYNTAX_ERROR),
                                                         errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
                                                                  column->colname, cxt->relation->relname)));
-                               /* Note: DEFAULT NULL maps to constraint->raw_expr == NULL */
                                column->raw_default = constraint->raw_expr;
                                Assert(constraint->cooked_expr == NULL);
                                saw_default = true;
@@ -516,7 +549,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
        bool            including_indexes = false;
        ListCell   *elem;
 
-       relation = heap_openrv(inhRelation->relation, AccessShareLock);
+       relation = parserOpenTable(pstate, inhRelation->relation, AccessShareLock);
 
        if (relation->rd_rel->relkind != RELKIND_RELATION)
                ereport(ERROR,
@@ -567,8 +600,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
        }
 
        /*
-        * Insert the copied attributes into the cxt for the new table
-        * definition.
+        * Insert the copied attributes into the cxt for the new table definition.
         */
        for (parent_attno = 1; parent_attno <= tupleDesc->natts;
                 parent_attno++)
@@ -637,8 +669,8 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
        }
 
        /*
-        * Copy CHECK constraints if requested, being careful to adjust
-        * attribute numbers
+        * Copy CHECK constraints if requested, being careful to adjust attribute
+        * numbers
         */
        if (including_constraints && tupleDesc->constr)
        {
@@ -663,32 +695,32 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
                }
        }
 
+       /*
+        * Likewise, copy indexes if requested
+        */
        if (including_indexes && relation->rd_rel->relhasindex)
        {
-               AttrNumber *attmap;
+               AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns);
                List       *parent_indexes;
                ListCell   *l;
 
-               attmap = varattnos_map_schema(tupleDesc, cxt->columns);
                parent_indexes = RelationGetIndexList(relation);
 
                foreach(l, parent_indexes)
                {
-                       Oid              parent_index_oid = lfirst_oid(l);
-                       Relation         parent_index;
-                       IndexStmt       *index_stmt;
+                       Oid                     parent_index_oid = lfirst_oid(l);
+                       Relation        parent_index;
+                       IndexStmt  *index_stmt;
 
                        parent_index = index_open(parent_index_oid, AccessShareLock);
 
                        /* Build CREATE INDEX statement to recreate the parent_index */
-                       index_stmt = generateClonedIndexStmt(cxt, parent_index,
-                                                                                                attmap);
+                       index_stmt = generateClonedIndexStmt(cxt, parent_index, attmap);
 
-                       /* Add the new IndexStmt to the create context */
+                       /* Save it in the inh_indexes list for the time being */
                        cxt->inh_indexes = lappend(cxt->inh_indexes, index_stmt);
 
-                       /* Keep our lock on the index till xact commit */
-                       index_close(parent_index, NoLock);
+                       index_close(parent_index, AccessShareLock);
                }
        }
 
@@ -701,54 +733,65 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
 }
 
 /*
- * Generate an IndexStmt entry using information from an already
- * existing index "source_idx".
- *
- * Note: Much of this functionality is cribbed from pg_get_indexdef.
+ * Generate an IndexStmt node using information from an already existing index
+ * "source_idx".  Attribute numbers should be adjusted according to attmap.
  */
 static IndexStmt *
 generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
                                                AttrNumber *attmap)
 {
-       HeapTuple                        ht_idx;
-       HeapTuple                        ht_idxrel;
-       HeapTuple                        ht_am;
-       Form_pg_index            idxrec;
-       Form_pg_class            idxrelrec;
-       Form_pg_am                       amrec;
-       List                            *indexprs = NIL;
-       ListCell                        *indexpr_item;
-       Oid                                      indrelid;
-       Oid                              source_relid;
-       int                                      keyno;
-       Oid                                      keycoltype;
-       Datum                            indclassDatum;
-       Datum                            indoptionDatum;
-       bool                             isnull;
-       oidvector                       *indclass;
-       int2vector                      *indoption;
-       IndexStmt                       *index;
-       Datum                            reloptions;
-
-       source_relid = RelationGetRelid(source_idx);
-
-       /* Fetch pg_index tuple for source index */
-       ht_idx = SearchSysCache(INDEXRELID,
-                                                       ObjectIdGetDatum(source_relid),
-                                                       0, 0, 0);
-       if (!HeapTupleIsValid(ht_idx))
-               elog(ERROR, "cache lookup failed for index %u", source_relid);
-       idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
+       Oid                     source_relid = RelationGetRelid(source_idx);
+       HeapTuple       ht_idxrel;
+       HeapTuple       ht_idx;
+       Form_pg_class idxrelrec;
+       Form_pg_index idxrec;
+       Form_pg_am      amrec;
+       oidvector  *indclass;
+       IndexStmt  *index;
+       List       *indexprs;
+       ListCell   *indexpr_item;
+       Oid                     indrelid;
+       int                     keyno;
+       Oid                     keycoltype;
+       Datum           datum;
+       bool            isnull;
+
+       /*
+        * Fetch pg_class tuple of source index.  We can't use the copy in the
+        * relcache entry because it doesn't include optional fields.
+        */
+       ht_idxrel = SearchSysCache(RELOID,
+                                                          ObjectIdGetDatum(source_relid),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(ht_idxrel))
+               elog(ERROR, "cache lookup failed for relation %u", source_relid);
+       idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
 
-       Assert(source_relid == idxrec->indexrelid);
+       /* Fetch pg_index tuple for source index from relcache entry */
+       ht_idx = source_idx->rd_indextuple;
+       idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
        indrelid = idxrec->indrelid;
 
+       /* Fetch pg_am tuple for source index from relcache entry */
+       amrec = source_idx->rd_am;
+
+       /* Must get indclass the hard way, since it's not stored in relcache */
+       datum = SysCacheGetAttr(INDEXRELID, ht_idx,
+                                                       Anum_pg_index_indclass, &isnull);
+       Assert(!isnull);
+       indclass = (oidvector *) DatumGetPointer(datum);
+
+       /* Begin building the IndexStmt */
        index = makeNode(IndexStmt);
+       index->relation = cxt->relation;
+       index->accessMethod = pstrdup(NameStr(amrec->amname));
+       if (OidIsValid(idxrelrec->reltablespace))
+               index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
+       else
+               index->tableSpace = NULL;
        index->unique = idxrec->indisunique;
-       index->concurrent = false;
        index->primary = idxrec->indisprimary;
-       index->relation = cxt->relation;
-       index->isconstraint = false;
+       index->concurrent = false;
 
        /*
         * We don't try to preserve the name of the source index; instead, just
@@ -756,65 +799,40 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
         */
        index->idxname = NULL;
 
-       /* Must get indclass and indoption the hard way */
-       indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-                                                                       Anum_pg_index_indclass, &isnull);
-       Assert(!isnull);
-       indclass = (oidvector *) DatumGetPointer(indclassDatum);
-       indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-                                                                        Anum_pg_index_indoption, &isnull);
-       Assert(!isnull);
-       indoption = (int2vector *) DatumGetPointer(indoptionDatum);
-
-       /* Fetch pg_class tuple of source index */
-       ht_idxrel = SearchSysCache(RELOID,
-                                                          ObjectIdGetDatum(source_relid),
-                                                          0, 0, 0);
-       if (!HeapTupleIsValid(ht_idxrel))
-               elog(ERROR, "cache lookup failed for relation %u", source_relid);
-
        /*
-        * Store the reloptions for later use by this new index
+        * If the index is marked PRIMARY, it's certainly from a constraint;
+        * else, if it's not marked UNIQUE, it certainly isn't; else, we have
+        * to search pg_depend to see if there's an associated unique constraint.
         */
-       reloptions = SysCacheGetAttr(RELOID, ht_idxrel,
-                                                                Anum_pg_class_reloptions, &isnull);
-       if (!isnull)
-               index->src_options = flatten_reloptions(source_relid);
-
-       idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
-
-       /* Fetch pg_am tuple for the index's access method */
-       ht_am = SearchSysCache(AMOID,
-                                                  ObjectIdGetDatum(idxrelrec->relam),
-                                                  0, 0, 0);
-       if (!HeapTupleIsValid(ht_am))
-               elog(ERROR, "cache lookup failed for access method %u",
-                        idxrelrec->relam);
-       amrec = (Form_pg_am) GETSTRUCT(ht_am);
-       index->accessMethod = pstrdup(NameStr(amrec->amname));
+       if (index->primary)
+               index->isconstraint = true;
+       else if (!index->unique)
+               index->isconstraint = false;
+       else
+               index->isconstraint = OidIsValid(get_index_constraint(source_relid));
 
        /* Get the index expressions, if any */
-       if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
+       datum = SysCacheGetAttr(INDEXRELID, ht_idx,
+                                                       Anum_pg_index_indexprs, &isnull);
+       if (!isnull)
        {
-               Datum           exprsDatum;
-               bool            isnull;
                char       *exprsString;
 
-               exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-                                                                        Anum_pg_index_indexprs, &isnull);
-               exprsString = DatumGetCString(DirectFunctionCall1(textout,
-                                                                                                                 exprsDatum));
-               Assert(!isnull);
+               exprsString = TextDatumGetCString(datum);
                indexprs = (List *) stringToNode(exprsString);
        }
+       else
+               indexprs = NIL;
 
-       indexpr_item = list_head(indexprs);
+       /* Build the list of IndexElem */
+       index->indexParams = NIL;
 
+       indexpr_item = list_head(indexprs);
        for (keyno = 0; keyno < idxrec->indnatts; keyno++)
        {
-               IndexElem       *iparam;
+               IndexElem  *iparam;
                AttrNumber      attnum = idxrec->indkey.values[keyno];
-               int16           opt = indoption->values[keyno];
+               int16           opt = source_idx->rd_indoption[keyno];
 
                iparam = makeNode(IndexElem);
 
@@ -837,11 +855,14 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
                        if (indexpr_item == NULL)
                                elog(ERROR, "too few entries in indexprs list");
                        indexkey = (Node *) lfirst(indexpr_item);
+                       indexpr_item = lnext(indexpr_item);
+
+                       /* OK to modify indexkey since we are working on a private copy */
                        change_varattnos_of_a_node(indexkey, attmap);
+
                        iparam->name = NULL;
                        iparam->expr = indexkey;
 
-                       indexpr_item = lnext(indexpr_item);
                        keycoltype = exprType(indexkey);
                }
 
@@ -854,40 +875,50 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
                /* Adjust options if necessary */
                if (amrec->amcanorder)
                {
-                       /* If it supports sort ordering, report DESC and NULLS opts */
+                       /*
+                        * If it supports sort ordering, copy DESC and NULLS opts.
+                        * Don't set non-default settings unnecessarily, though,
+                        * so as to improve the chance of recognizing equivalence
+                        * to constraint indexes.
+                        */
                        if (opt & INDOPTION_DESC)
+                       {
                                iparam->ordering = SORTBY_DESC;
-                       if (opt & INDOPTION_NULLS_FIRST)
-                               iparam->nulls_ordering = SORTBY_NULLS_FIRST;
+                               if ((opt & INDOPTION_NULLS_FIRST) == 0)
+                                       iparam->nulls_ordering = SORTBY_NULLS_LAST;
+                       }
+                       else
+                       {
+                               if (opt & INDOPTION_NULLS_FIRST)
+                                       iparam->nulls_ordering = SORTBY_NULLS_FIRST;
+                       }
                }
 
                index->indexParams = lappend(index->indexParams, iparam);
        }
 
-       /* Use the same tablespace as the source index */
-       index->tableSpace = get_tablespace_name(source_idx->rd_node.spcNode);
+       /* Copy reloptions if any */
+       datum = SysCacheGetAttr(RELOID, ht_idxrel,
+                                                       Anum_pg_class_reloptions, &isnull);
+       if (!isnull)
+               index->options = untransformRelOptions(datum);
 
        /* If it's a partial index, decompile and append the predicate */
-       if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
+       datum = SysCacheGetAttr(INDEXRELID, ht_idx,
+                                                       Anum_pg_index_indpred, &isnull);
+       if (!isnull)
        {
-               Datum           pred_datum;
-               bool            isnull;
                char       *pred_str;
 
                /* Convert text string to node tree */
-               pred_datum = SysCacheGetAttr(INDEXRELID, ht_idx,
-                                                                        Anum_pg_index_indpred, &isnull);
-               Assert(!isnull);
-               pred_str = DatumGetCString(DirectFunctionCall1(textout,
-                                                                                                          pred_datum));
+               pred_str = TextDatumGetCString(datum);
                index->whereClause = (Node *) stringToNode(pred_str);
+               /* Adjust attribute numbers */
                change_varattnos_of_a_node(index->whereClause, attmap);
        }
 
        /* Clean up */
-       ReleaseSysCache(ht_idx);
        ReleaseSysCache(ht_idxrel);
-       ReleaseSysCache(ht_am);
 
        return index;
 }
@@ -901,9 +932,9 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
 static List *
 get_opclass(Oid opclass, Oid actual_datatype)
 {
-       HeapTuple                        ht_opc;
-       Form_pg_opclass          opc_rec;
-       List                            *result = NIL;
+       HeapTuple       ht_opc;
+       Form_pg_opclass opc_rec;
+       List       *result = NIL;
 
        ht_opc = SearchSysCache(CLAOID,
                                                        ObjectIdGetDatum(opclass),
@@ -912,11 +943,11 @@ get_opclass(Oid opclass, Oid actual_datatype)
                elog(ERROR, "cache lookup failed for opclass %u", opclass);
        opc_rec = (Form_pg_opclass) GETSTRUCT(ht_opc);
 
-       if (!OidIsValid(actual_datatype) ||
-               GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
+       if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
        {
-               char *nsp_name = get_namespace_name(opc_rec->opcnamespace);
-               char *opc_name = NameStr(opc_rec->opcname);
+               /* For simplicity, we always schema-qualify the name */
+               char       *nsp_name = get_namespace_name(opc_rec->opcnamespace);
+               char       *opc_name = pstrdup(NameStr(opc_rec->opcname));
 
                result = list_make2(makeString(nsp_name), makeString(opc_name));
        }
@@ -928,8 +959,8 @@ get_opclass(Oid opclass, Oid actual_datatype)
 
 /*
  * transformIndexConstraints
- *             Handle UNIQUE and PRIMARY KEY constraints, which create
- *             indexes. We also merge index definitions arising from
+ *             Handle UNIQUE and PRIMARY KEY constraints, which create indexes.
+ *             We also merge in any index definitions arising from
  *             LIKE ... INCLUDING INDEXES.
  */
 static void
@@ -948,7 +979,30 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
        {
                Constraint *constraint = (Constraint *) lfirst(lc);
 
+               Assert(IsA(constraint, Constraint));
+               Assert(constraint->contype == CONSTR_PRIMARY ||
+                          constraint->contype == CONSTR_UNIQUE);
+
                index = transformIndexConstraint(constraint, cxt);
+
+               indexlist = lappend(indexlist, index);
+       }
+
+       /* Add in any indexes defined by LIKE ... INCLUDING INDEXES */
+       foreach(lc, cxt->inh_indexes)
+       {
+               index = (IndexStmt *) lfirst(lc);
+
+               if (index->primary)
+               {
+                       if (cxt->pkey != NULL)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+                                                errmsg("multiple primary keys for table \"%s\" are not allowed",
+                                                               cxt->relation->relname)));
+                       cxt->pkey = index;
+               }
+
                indexlist = lappend(indexlist, index);
        }
 
@@ -983,8 +1037,11 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
                {
                        IndexStmt  *priorindex = lfirst(k);
 
-                       if (equal(index->indexParams, priorindex->indexParams))
+                       if (equal(index->indexParams, priorindex->indexParams) &&
+                               equal(index->whereClause, priorindex->whereClause) &&
+                               strcmp(index->accessMethod, priorindex->accessMethod) == 0)
                        {
+                               priorindex->unique |= index->unique;
                                /*
                                 * If the prior index is as yet unnamed, and this one is
                                 * named, then transfer the name to the prior index. This
@@ -1001,48 +1058,31 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
                if (keep)
                        cxt->alist = lappend(cxt->alist, index);
        }
-
-       /* Copy indexes defined by LIKE ... INCLUDING INDEXES */
-       foreach(lc, cxt->inh_indexes)
-       {
-               index = (IndexStmt *) lfirst(lc);
-
-               if (index->primary)
-               {
-                       if (cxt->pkey)
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-                                                errmsg("multiple primary keys for table \"%s\" are not allowed",
-                                                               cxt->relation->relname)));
-
-                       cxt->pkey = index;
-               }
-
-               cxt->alist = lappend(cxt->alist, index);
-       }
 }
 
+/*
+ * transformIndexConstraint
+ *             Transform one UNIQUE or PRIMARY KEY constraint for
+ *             transformIndexConstraints.
+ */
 static IndexStmt *
 transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 {
-       IndexStmt       *index;
-       ListCell        *keys;
-       IndexElem       *iparam;
-
-       Assert(constraint->contype == CONSTR_PRIMARY ||
-                  constraint->contype == CONSTR_UNIQUE);
+       IndexStmt  *index;
+       ListCell   *keys;
+       IndexElem  *iparam;
 
        index = makeNode(IndexStmt);
+
        index->unique = true;
        index->primary = (constraint->contype == CONSTR_PRIMARY);
-
        if (index->primary)
        {
                if (cxt->pkey != NULL)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-                                        errmsg("multiple primary keys for table \"%s\" are not allowed",
-                                                       cxt->relation->relname)));
+                        errmsg("multiple primary keys for table \"%s\" are not allowed",
+                                       cxt->relation->relname)));
                cxt->pkey = index;
 
                /*
@@ -1055,7 +1095,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
        if (constraint->name != NULL)
                index->idxname = pstrdup(constraint->name);
        else
-               index->idxname = NULL;          /* DefineIndex will choose name */
+               index->idxname = NULL;  /* DefineIndex will choose name */
 
        index->relation = cxt->relation;
        index->accessMethod = DEFAULT_INDEX_TYPE;
@@ -1066,10 +1106,10 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
        index->concurrent = false;
 
        /*
-        * Make sure referenced keys exist.  If we are making a PRIMARY KEY
-        * index, also make sure they are NOT NULL, if possible. (Although we
-        * could leave it to DefineIndex to mark the columns NOT NULL, it's
-        * more efficient to get it right the first time.)
+        * Make sure referenced keys exist.  If we are making a PRIMARY KEY index,
+        * also make sure they are NOT NULL, if possible. (Although we could leave
+        * it to DefineIndex to mark the columns NOT NULL, it's more efficient to
+        * get it right the first time.)
         */
        foreach(keys, constraint->keys)
        {
@@ -1097,9 +1137,9 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
                else if (SystemAttributeByName(key, cxt->hasoids) != NULL)
                {
                        /*
-                        * column will be a system column in the new table, so accept
-                        * it.  System columns can't ever be null, so no need to worry
-                        * about PRIMARY/NOT NULL constraint.
+                        * column will be a system column in the new table, so accept it.
+                        * System columns can't ever be null, so no need to worry about
+                        * PRIMARY/NOT NULL constraint.
                         */
                        found = true;
                }
@@ -1119,8 +1159,8 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
                                if (rel->rd_rel->relkind != RELKIND_RELATION)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                                                        errmsg("inherited relation \"%s\" is not a table",
-                                                                       inh->relname)));
+                                                  errmsg("inherited relation \"%s\" is not a table",
+                                                                 inh->relname)));
                                for (count = 0; count < rel->rd_att->natts; count++)
                                {
                                        Form_pg_attribute inhattr = rel->rd_att->attrs[count];
@@ -1133,10 +1173,10 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
                                                found = true;
 
                                                /*
-                                                * We currently have no easy way to force an
-                                                * inherited column to be NOT NULL at creation, if
-                                                * its parent wasn't so already. We leave it to
-                                                * DefineIndex to fix things up in this case.
+                                                * We currently have no easy way to force an inherited
+                                                * column to be NOT NULL at creation, if its parent
+                                                * wasn't so already. We leave it to DefineIndex to
+                                                * fix things up in this case.
                                                 */
                                                break;
                                        }
@@ -1149,9 +1189,9 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 
                /*
                 * In the ALTER TABLE case, don't complain about index keys not
-                * created in the command; they may well exist already.
-                * DefineIndex will complain about them if not, and will also take
-                * care of marking them NOT NULL.
+                * created in the command; they may well exist already. DefineIndex
+                * will complain about them if not, and will also take care of marking
+                * them NOT NULL.
                 */
                if (!found && !cxt->isalter)
                        ereport(ERROR,
@@ -1173,8 +1213,8 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
                                else
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_DUPLICATE_COLUMN),
-                                                        errmsg("column \"%s\" appears twice in unique constraint",
-                                                                       key)));
+                                       errmsg("column \"%s\" appears twice in unique constraint",
+                                                  key)));
                        }
                }
 
@@ -1256,7 +1296,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt,
  * transformIndexStmt - parse analysis for CREATE INDEX
  *
  * Note: this is a no-op for an index not using either index expressions or
- * a predicate expression.  There are several code paths that create indexes
+ * a predicate expression.     There are several code paths that create indexes
  * without bothering to call this, because they know they don't have any
  * such expressions to deal with.
  */
@@ -1269,28 +1309,28 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
        ListCell   *l;
 
        /*
-        * We must not scribble on the passed-in IndexStmt, so copy it.  (This
-        * is overkill, but easy.)
+        * We must not scribble on the passed-in IndexStmt, so copy it.  (This is
+        * overkill, but easy.)
         */
        stmt = (IndexStmt *) copyObject(stmt);
 
        /*
-        * Open the parent table with appropriate locking.  We must do this
+        * Open the parent table with appropriate locking.      We must do this
         * because addRangeTableEntry() would acquire only AccessShareLock,
-        * leaving DefineIndex() needing to do a lock upgrade with consequent
-        * risk of deadlock.  Make sure this stays in sync with the type of
-        * lock DefineIndex() wants.
+        * leaving DefineIndex() needing to do a lock upgrade with consequent risk
+        * of deadlock.  Make sure this stays in sync with the type of lock
+        * DefineIndex() wants.
         */
        rel = heap_openrv(stmt->relation,
-                               (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));
+                                 (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));
 
        /* Set up pstate */
        pstate = make_parsestate(NULL);
        pstate->p_sourcetext = queryString;
 
        /*
-        * Put the parent table into the rtable so that the expressions can
-        * refer to its fields without qualification.
+        * Put the parent table into the rtable so that the expressions can refer
+        * to its fields without qualification.
         */
        rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true);
 
@@ -1419,7 +1459,7 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
 
        /* take care of the where clause */
        *whereClause = transformWhereClause(pstate,
-                                                                               (Node *) copyObject(stmt->whereClause),
+                                                                         (Node *) copyObject(stmt->whereClause),
                                                                                "WHERE");
 
        if (list_length(pstate->p_rtable) != 2)         /* naughty, naughty... */
@@ -1432,6 +1472,10 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
                ereport(ERROR,
                                (errcode(ERRCODE_GROUPING_ERROR),
                   errmsg("cannot use aggregate function in rule WHERE condition")));
+       if (pstate->p_hasWindowFuncs)
+               ereport(ERROR,
+                               (errcode(ERRCODE_WINDOWING_ERROR),
+                                errmsg("cannot use window function in rule WHERE condition")));
 
        /*
         * 'instead nothing' rules with a qualification need a query rangetable so
@@ -1445,7 +1489,7 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
 
                nothing_qry->commandType = CMD_NOTHING;
                nothing_qry->rtable = pstate->p_rtable;
-               nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
+               nothing_qry->jointree = makeFromExpr(NIL, NULL);                /* no join wanted */
 
                *actions = list_make1(nothing_qry);
        }
@@ -1467,8 +1511,8 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
                                                has_new;
 
                        /*
-                        * Since outer ParseState isn't parent of inner, have to pass
-                        * down the query text by hand.
+                        * Since outer ParseState isn't parent of inner, have to pass down
+                        * the query text by hand.
                         */
                        sub_pstate->p_sourcetext = queryString;
 
@@ -1637,17 +1681,17 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
        AlterTableCmd *newcmd;
 
        /*
-        * We must not scribble on the passed-in AlterTableStmt, so copy it.
-        * (This is overkill, but easy.)
+        * We must not scribble on the passed-in AlterTableStmt, so copy it. (This
+        * is overkill, but easy.)
         */
        stmt = (AlterTableStmt *) copyObject(stmt);
 
        /*
-        * Acquire exclusive lock on the target relation, which will be held
-        * until end of transaction.  This ensures any decisions we make here
-        * based on the state of the relation will still be good at execution.
-        * We must get exclusive lock now because execution will; taking a lower
-        * grade lock now and trying to upgrade later risks deadlock.
+        * Acquire exclusive lock on the target relation, which will be held until
+        * end of transaction.  This ensures any decisions we make here based on
+        * the state of the relation will still be good at execution. We must get
+        * exclusive lock now because execution will; taking a lower grade lock
+        * now and trying to upgrade later risks deadlock.
         */
        rel = relation_openrv(stmt->relation, AccessExclusiveLock);
 
@@ -1682,44 +1726,27 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
                switch (cmd->subtype)
                {
                        case AT_AddColumn:
+                       case AT_AddColumnToView:
                                {
                                        ColumnDef  *def = (ColumnDef *) cmd->def;
 
-                                       Assert(IsA(cmd->def, ColumnDef));
-                                       transformColumnDefinition(pstate, &cxt,
-                                                                                         (ColumnDef *) cmd->def);
+                                       Assert(IsA(def, ColumnDef));
+                                       transformColumnDefinition(pstate, &cxt, def);
 
                                        /*
                                         * If the column has a non-null default, we can't skip
                                         * validation of foreign keys.
                                         */
-                                       if (((ColumnDef *) cmd->def)->raw_default != NULL)
+                                       if (def->raw_default != NULL)
                                                skipValidation = false;
 
-                                       newcmds = lappend(newcmds, cmd);
-
-                                       /*
-                                        * Convert an ADD COLUMN ... NOT NULL constraint to a
-                                        * separate command
-                                        */
-                                       if (def->is_not_null)
-                                       {
-                                               /* Remove NOT NULL from AddColumn */
-                                               def->is_not_null = false;
-
-                                               /* Add as a separate AlterTableCmd */
-                                               newcmd = makeNode(AlterTableCmd);
-                                               newcmd->subtype = AT_SetNotNull;
-                                               newcmd->name = pstrdup(def->colname);
-                                               newcmds = lappend(newcmds, newcmd);
-                                       }
-
                                        /*
                                         * All constraints are processed in other ways. Remove the
                                         * original list
                                         */
                                        def->constraints = NIL;
 
+                                       newcmds = lappend(newcmds, cmd);
                                        break;
                                }
                        case AT_AddConstraint:
@@ -1727,7 +1754,6 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
                                /*
                                 * The original AddConstraint cmd node doesn't go to newcmds
                                 */
-
                                if (IsA(cmd->def, Constraint))
                                        transformTableConstraint(pstate, &cxt,
                                                                                         (Constraint *) cmd->def);
@@ -1759,7 +1785,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
 
        /*
         * transformIndexConstraints wants cxt.alist to contain only index
-        * statements, so transfer anything we already have into save_alist.
+        * statements, so transfer anything we already have into save_alist
         * immediately.
         */
        save_alist = cxt.alist;
@@ -1942,7 +1968,7 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
        /*
         * All we really need to do here is verify that the type is valid.
         */
-       Type            ctype = typenameType(pstate, column->typename);
+       Type            ctype = typenameType(pstate, column->typename, NULL);
 
        ReleaseSysCache(ctype);
 }