From 2ad94d382c2fa1e1917a46f86c44f95faf110bb2 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 18 Sep 2006 16:04:04 +0000 Subject: 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. --- src/backend/parser/analyze.c | 109 ++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 43 deletions(-) (limited to 'src/backend/parser/analyze.c') diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 4a8175e0cad..582747a23f4 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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"))); } -- cgit v1.2.3