From 2df2c3dca2cbfe98ab24db281ec4d1892e5d47bc Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 19 Feb 2005 19:33:42 +0000 Subject: [PATCH] Ensure that the resolved datatype of any unknown Param is propagated into the sub-SELECT targetlist when it appears in the context INSERT INTO foo SELECT $1 ... Per report from Abhijit Menon-Sen. --- src/backend/parser/analyze.c | 39 ++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 8ea47922b18..867c68d9a5b 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.290.2.2 2004/11/17 00:18:26 neilc Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.290.2.3 2005/02/19 19:33:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -498,6 +498,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, List **extras_before, List **extras_after) { Query *qry = makeNode(Query); + Query *selectQuery = NULL; + bool copy_up_hack = false; List *sub_rtable; List *sub_namespace; List *icolumns; @@ -552,7 +554,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, * be able to see. */ ParseState *sub_pstate = make_parsestate(pstate); - Query *selectQuery; RangeTblEntry *rte; RangeTblRef *rtr; @@ -599,7 +600,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable)); pstate->p_joinlist = lappend(pstate->p_joinlist, rtr); - /* + /*---------- * Generate a targetlist for the INSERT that selects all the * non-resjunk columns from the subquery. (We need this to be * separate from the subquery's tlist because we may add columns, @@ -609,8 +610,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, * are copied up as-is rather than being referenced as subquery * outputs. This is to ensure that when we try to coerce them to * the target column's datatype, the right things happen (see - * special cases in coerce_type). Otherwise, this fails: INSERT - * INTO foo SELECT 'bar', ... FROM baz + * special cases in coerce_type). Otherwise, this fails: + * INSERT INTO foo SELECT 'bar', ... FROM baz + *---------- */ qry->targetList = NIL; foreach(tl, selectQuery->targetList) @@ -622,9 +624,12 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, if (resnode->resjunk) continue; if (tle->expr && - (IsA(tle->expr, Const) ||IsA(tle->expr, Param)) && + (IsA(tle->expr, Const) || IsA(tle->expr, Param)) && exprType((Node *) tle->expr) == UNKNOWNOID) + { expr = tle->expr; + copy_up_hack = true; + } else expr = (Expr *) makeVar(rtr->rtindex, resnode->resno, @@ -698,6 +703,28 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("INSERT has more target columns than expressions"))); + /* + * If we copied up any unknown Params (see HACK above) then their + * resolved types need to be propagated into the Resdom nodes of + * the sub-INSERT's tlist. One hack begets another :-( + */ + if (copy_up_hack) + { + foreach(tl, selectQuery->targetList) + { + TargetEntry *tle = (TargetEntry *) lfirst(tl); + Resdom *resnode = tle->resdom; + + if (resnode->resjunk) + continue; + if (resnode->restype == UNKNOWNOID) + { + resnode->restype = exprType((Node *) tle->expr); + resnode->restypmod = exprTypmod((Node *) tle->expr); + } + } + } + /* done building the range table and jointree */ qry->rtable = pstate->p_rtable; qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);