OSDN Git Service

CREATE TABLE foo (x,y,z) AS SELECT ... can't apply target column names
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 5 Nov 2001 05:00:14 +0000 (05:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 5 Nov 2001 05:00:14 +0000 (05:00 +0000)
to the target list in gram.y; it must wait till after expansion of the
target list in analyze.c.  Per bug report 4-Nov:
lx=# CREATE TABLE abc (a char, b char, c char);
CREATE
lx=# CREATE TABLE xyz (x, y, z) AS SELECT * FROM abc;
ERROR:  CREATE TABLE/AS SELECT has mismatched column count

src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/include/nodes/parsenodes.h

index 6200543..6977a60 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.159 2001/10/25 05:49:30 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.160 2001/11/05 05:00:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1835,6 +1835,7 @@ _copySelectStmt(SelectStmt *from)
        if (from->into)
                newnode->into = pstrdup(from->into);
        newnode->istemp = from->istemp;
+       Node_Copy(from, newnode, intoColNames);
        Node_Copy(from, newnode, targetList);
        Node_Copy(from, newnode, fromClause);
        Node_Copy(from, newnode, whereClause);
index 0a48a19..538a773 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.107 2001/10/25 05:49:30 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.108 2001/11/05 05:00:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -681,6 +681,8 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
                return false;
        if (a->istemp != b->istemp)
                return false;
+       if (!equal(a->intoColNames, b->intoColNames))
+               return false;
        if (!equal(a->targetList, b->targetList))
                return false;
        if (!equal(a->fromClause, b->fromClause))
index 0d83307..40e9700 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.209 2001/11/04 03:08:11 momjian Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.210 2001/11/05 05:00:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,6 +88,7 @@ static void transformFKConstraints(ParseState *pstate,
                                           CreateStmtContext *cxt);
 static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
 
+static void applyColumnNames(List *dst, List *src);
 static void transformTypeRefsList(ParseState *pstate, List *l);
 static void transformTypeRef(ParseState *pstate, TypeName *tn);
 static List *getSetColTypes(ParseState *pstate, Node *node);
@@ -1942,9 +1943,13 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
        /* process the FROM clause */
        transformFromClause(pstate, stmt->fromClause);
 
-       /* transform targetlist and WHERE */
+       /* transform targetlist */
        qry->targetList = transformTargetList(pstate, stmt->targetList);
 
+       if (stmt->intoColNames)
+               applyColumnNames(qry->targetList, stmt->intoColNames);
+
+       /* transform WHERE */
        qual = transformWhereClause(pstate, stmt->whereClause);
 
        /*
@@ -2003,6 +2008,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
        SetOperationStmt *sostmt;
        char       *into;
        bool            istemp;
+       List       *intoColNames;
        char       *portalname;
        bool            binary;
        List       *sortClause;
@@ -2031,12 +2037,14 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
                   leftmostSelect->larg == NULL);
        into = leftmostSelect->into;
        istemp = leftmostSelect->istemp;
+       intoColNames = leftmostSelect->intoColNames;
        portalname = stmt->portalname;
        binary = stmt->binary;
 
        /* clear them to prevent complaints in transformSetOperationTree() */
        leftmostSelect->into = NULL;
        leftmostSelect->istemp = false;
+       leftmostSelect->intoColNames = NIL;
        stmt->portalname = NULL;
        stmt->binary = false;
 
@@ -2149,6 +2157,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
                qry->isBinary = FALSE;
        }
 
+       if (intoColNames)
+               applyColumnNames(qry->targetList, intoColNames);
+
        /*
         * As a first step towards supporting sort clauses that are
         * expressions using the output columns, generate a namespace entry
@@ -2377,6 +2388,27 @@ getSetColTypes(ParseState *pstate, Node *node)
        }
 }
 
+/* Attach column names from a ColumnDef list to a TargetEntry list */
+static void
+applyColumnNames(List *dst, List *src)
+{
+       if (length(src) > length(dst))
+               elog(ERROR,"CREATE TABLE AS specifies too many column names");
+
+       while (src != NIL && dst != NIL)
+       {
+               TargetEntry *d = (TargetEntry *) lfirst(dst);
+               ColumnDef *s = (ColumnDef *) lfirst(src);
+
+               Assert(d->resdom && !d->resdom->resjunk);
+
+               d->resdom->resname = pstrdup(s->colname);
+
+               dst = lnext(dst);
+               src = lnext(src);
+       }
+}
+
 
 /*
  * transformUpdateStmt -
index c97c9da..63465c9 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.271 2001/10/31 04:49:43 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.272 2001/11/05 05:00:14 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -86,7 +86,6 @@ static Node *makeTypeCast(Node *arg, TypeName *typename);
 static Node *makeStringConst(char *str, TypeName *typename);
 static Node *makeFloatConst(char *str);
 static Node *makeRowExpr(char *opr, List *largs, List *rargs);
-static void mapTargetColumns(List *source, List *target);
 static SelectStmt *findLeftmostSelect(SelectStmt *node);
 static void insertSelectOptions(SelectStmt *stmt,
                                                                List *sortClause, List *forUpdate,
@@ -1611,11 +1610,10 @@ CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
                                         */
                                        SelectStmt *n = findLeftmostSelect((SelectStmt *) $7);
                                        if (n->into != NULL)
-                                               elog(ERROR,"CREATE TABLE / AS SELECT may not specify INTO");
+                                               elog(ERROR,"CREATE TABLE AS may not specify INTO");
                                        n->istemp = $2;
                                        n->into = $4;
-                                       if ($5 != NIL)
-                                               mapTargetColumns($5, n->targetList);
+                                       n->intoColNames = $5;
                                        $$ = $7;
                                }
                ;
@@ -3552,6 +3550,7 @@ simple_select: SELECT opt_distinct target_list
                                        n->targetList = $3;
                                        n->istemp = (bool) ((Value *) lfirst($4))->val.ival;
                                        n->into = (char *) lnext($4);
+                                       n->intoColNames = NIL;
                                        n->fromClause = $5;
                                        n->whereClause = $6;
                                        n->groupClause = $7;
@@ -6106,28 +6105,6 @@ makeRowExpr(char *opr, List *largs, List *rargs)
        return expr;
 }
 
-static void
-mapTargetColumns(List *src, List *dst)
-{
-       ColumnDef *s;
-       ResTarget *d;
-
-       if (length(src) != length(dst))
-               elog(ERROR,"CREATE TABLE / AS SELECT has mismatched column count");
-
-       while ((src != NIL) && (dst != NIL))
-       {
-               s = (ColumnDef *)lfirst(src);
-               d = (ResTarget *)lfirst(dst);
-
-               d->name = s->colname;
-
-               src = lnext(src);
-               dst = lnext(dst);
-       }
-} /* mapTargetColumns() */
-
-
 /* findLeftmostSelect()
  *             Find the leftmost component SelectStmt in a set-operation parsetree.
  */
index 1abd7ba..892177c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.149 2001/10/28 06:26:07 momjian Exp $
+ * $Id: parsenodes.h,v 1.150 2001/11/05 05:00:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -881,6 +881,7 @@ typedef struct SelectStmt
                                                                 * DISTINCT) */
        char       *into;                       /* name of table (for select into table) */
        bool            istemp;                 /* into is a temp table? */
+       List       *intoColNames;       /* column names for into table */
        List       *targetList;         /* the target list (of ResTarget) */
        List       *fromClause;         /* the FROM clause */
        Node       *whereClause;        /* WHERE qualification */