Fix problems with column name list of CREATE TABLE AS being applied to

the input query's target list too soon, causing it to affect processing
of ORDER BY in the input query.
This commit is contained in:
Tom Lane 2006-09-18 16:04:04 +00:00
parent e8efd98312
commit 2ad94d382c
1 changed files with 69 additions and 46 deletions

View 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))
src_item = list_head(src);
foreach(dst_item, dst)
{
TargetEntry *d = (TargetEntry *) lfirst(dst_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);
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")));
forboth(dst_item, dst, src_item, src)
{
TargetEntry *d = (TargetEntry *) lfirst(dst_item);
ColumnDef *s = (ColumnDef *) lfirst(src_item);
Assert(!d->resjunk);
d->resname = pstrdup(s->colname);
}
}