Fix problems with column name list of CREATE TABLE AS being applied to
authorTom Lane
Mon, 18 Sep 2006 16:04:04 +0000 (16:04 +0000)
committerTom Lane
Mon, 18 Sep 2006 16:04:04 +0000 (16:04 +0000)
the input query's target list too soon, causing it to affect processing
of ORDER BY in the input query.

src/backend/parser/analyze.c

index 4a8175e0cad3a00bb66edea6360a130fffa93b3a..582747a23f4bb7f996f5a08163e0bfc33d654b41 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.350 2006/09/18 00:52:14 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.351 2006/09/18 16:04:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2093,14 +2093,6 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
    /* transform targetlist */
    qry->targetList = transformTargetList(pstate, stmt->targetList);
 
-   /* handle any SELECT INTO/CREATE TABLE AS spec */
-   qry->into = stmt->into;
-   if (stmt->intoColNames)
-       applyColumnNames(qry->targetList, stmt->intoColNames);
-   qry->intoOptions = copyObject(stmt->intoOptions);
-   qry->intoOnCommit = stmt->intoOnCommit;
-   qry->intoTableSpaceName = stmt->intoTableSpaceName;
-
    /* mark column origins */
    markTargetListOrigins(pstate, qry->targetList);
 
@@ -2137,6 +2129,17 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
    qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
                                           "LIMIT");
 
+   /* handle any SELECT INTO/CREATE TABLE AS spec */
+   if (stmt->into)
+   {
+       qry->into = stmt->into;
+       if (stmt->intoColNames)
+           applyColumnNames(qry->targetList, stmt->intoColNames);
+       qry->intoOptions = copyObject(stmt->intoOptions);
+       qry->intoOnCommit = stmt->intoOnCommit;
+       qry->intoTableSpaceName = stmt->intoTableSpaceName;
+   }
+
    qry->rtable = pstate->p_rtable;
    qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
 
@@ -2271,6 +2274,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
    rtr->rtindex = list_length(pstate->p_rtable);
    Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
    pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
+   pstate->p_varnamespace = lappend(pstate->p_varnamespace, rte);
 
    /*
     * Generate a targetlist as though expanding "*"
@@ -2278,14 +2282,6 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
    Assert(pstate->p_next_resno == 1);
    qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0);
 
-   /* handle any CREATE TABLE AS spec */
-   qry->into = stmt->into;
-   if (stmt->intoColNames)
-       applyColumnNames(qry->targetList, stmt->intoColNames);
-   qry->intoOptions = copyObject(stmt->intoOptions);
-   qry->intoOnCommit = stmt->intoOnCommit;
-   qry->intoTableSpaceName = stmt->intoTableSpaceName;
-
    /*
     * The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE
     * to a VALUES, so cope.
@@ -2305,6 +2301,17 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES")));
 
+   /* handle any CREATE TABLE AS spec */
+   if (stmt->into)
+   {
+       qry->into = stmt->into;
+       if (stmt->intoColNames)
+           applyColumnNames(qry->targetList, stmt->intoColNames);
+       qry->intoOptions = copyObject(stmt->intoOptions);
+       qry->intoOnCommit = stmt->intoOnCommit;
+       qry->intoTableSpaceName = stmt->intoTableSpaceName;
+   }
+
    /*
     * There mustn't have been any table references in the expressions,
     * else strange things would happen, like Cartesian products of
@@ -2360,7 +2367,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
    int         leftmostRTI;
    Query      *leftmostQuery;
    SetOperationStmt *sostmt;
-   List       *intoColNames;
+   List       *intoColNames = NIL;
    List       *sortClause;
    Node       *limitOffset;
    Node       *limitCount;
@@ -2391,11 +2398,14 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
        leftmostSelect = leftmostSelect->larg;
    Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
           leftmostSelect->larg == NULL);
-   qry->into = leftmostSelect->into;
-   intoColNames = leftmostSelect->intoColNames;
-   qry->intoOptions = copyObject(leftmostSelect->intoOptions);
-   qry->intoOnCommit = leftmostSelect->intoOnCommit;
-   qry->intoTableSpaceName = leftmostSelect->intoTableSpaceName;
+   if (leftmostSelect->into)
+   {
+       qry->into = leftmostSelect->into;
+       intoColNames = leftmostSelect->intoColNames;
+       qry->intoOptions = copyObject(leftmostSelect->intoOptions);
+       qry->intoOnCommit = leftmostSelect->intoOnCommit;
+       qry->intoTableSpaceName = leftmostSelect->intoTableSpaceName;
+   }
 
    /* clear this to prevent complaints in transformSetOperationTree() */
    leftmostSelect->into = NULL;
@@ -2481,19 +2491,6 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
        left_tlist = lnext(left_tlist);
    }
 
-   /*
-    * Handle SELECT INTO/CREATE TABLE AS.
-    *
-    * Any column names from CREATE TABLE AS need to be attached to both the
-    * top level and the leftmost subquery.  We do not do this earlier because
-    * we do *not* want the targetnames list to be affected.
-    */
-   if (intoColNames)
-   {
-       applyColumnNames(qry->targetList, intoColNames);
-       applyColumnNames(leftmostQuery->targetList, intoColNames);
-   }
-
    /*
     * As a first step towards supporting sort clauses that are expressions
     * using the output columns, generate a varnamespace entry that makes the
@@ -2547,6 +2544,19 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
    qry->limitCount = transformLimitClause(pstate, limitCount,
                                           "LIMIT");
 
+   /*
+    * Handle SELECT INTO/CREATE TABLE AS.
+    *
+    * Any column names from CREATE TABLE AS need to be attached to both the
+    * top level and the leftmost subquery.  We do not do this earlier because
+    * we do *not* want sortClause processing to be affected.
+    */
+   if (intoColNames)
+   {
+       applyColumnNames(qry->targetList, intoColNames);
+       applyColumnNames(leftmostQuery->targetList, intoColNames);
+   }
+
    qry->rtable = pstate->p_rtable;
    qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
 
@@ -2788,19 +2798,32 @@ applyColumnNames(List *dst, List *src)
    ListCell   *dst_item;
    ListCell   *src_item;
 
-   if (list_length(src) > list_length(dst))
-       ereport(ERROR,
-               (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("CREATE TABLE AS specifies too many column names")));
+   src_item = list_head(src);
 
-   forboth(dst_item, dst, src_item, src)
+   foreach(dst_item, dst)
    {
        TargetEntry *d = (TargetEntry *) lfirst(dst_item);
-       ColumnDef  *s = (ColumnDef *) lfirst(src_item);
+       ColumnDef  *s;
+
+       /* junk targets don't count */
+       if (d->resjunk)
+           continue;
+
+       /* fewer ColumnDefs than target entries is OK */
+       if (src_item == NULL)
+           break;
+
+       s = (ColumnDef *) lfirst(src_item);
+       src_item = lnext(src_item);
 
-       Assert(!d->resjunk);
        d->resname = pstrdup(s->colname);
    }
+
+   /* more ColumnDefs than target entries is not OK */
+   if (src_item != NULL)
+       ereport(ERROR,
+               (errcode(ERRCODE_SYNTAX_ERROR),
+                errmsg("CREATE TABLE AS specifies too many column names")));
 }