Commit 9650d6c7 authored by Tom Lane's avatar Tom Lane

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.
parent 2abe40aa
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.314 2004/12/31 22:00:26 pgsql Exp $ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.315 2005/02/19 19:33:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -506,6 +506,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, ...@@ -506,6 +506,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
List **extras_before, List **extras_after) List **extras_before, List **extras_after)
{ {
Query *qry = makeNode(Query); Query *qry = makeNode(Query);
Query *selectQuery = NULL;
bool copy_up_hack = false;
List *sub_rtable; List *sub_rtable;
List *sub_namespace; List *sub_namespace;
List *icolumns; List *icolumns;
...@@ -561,7 +563,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, ...@@ -561,7 +563,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
* be able to see. * be able to see.
*/ */
ParseState *sub_pstate = make_parsestate(pstate); ParseState *sub_pstate = make_parsestate(pstate);
Query *selectQuery;
RangeTblEntry *rte; RangeTblEntry *rte;
RangeTblRef *rtr; RangeTblRef *rtr;
...@@ -608,7 +609,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, ...@@ -608,7 +609,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable)); Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
pstate->p_joinlist = lappend(pstate->p_joinlist, rtr); pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
/* /*----------
* Generate a targetlist for the INSERT that selects all the * Generate a targetlist for the INSERT that selects all the
* non-resjunk columns from the subquery. (We need this to be * non-resjunk columns from the subquery. (We need this to be
* separate from the subquery's tlist because we may add columns, * separate from the subquery's tlist because we may add columns,
...@@ -618,8 +619,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, ...@@ -618,8 +619,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
* are copied up as-is rather than being referenced as subquery * are copied up as-is rather than being referenced as subquery
* outputs. This is to ensure that when we try to coerce them to * outputs. This is to ensure that when we try to coerce them to
* the target column's datatype, the right things happen (see * the target column's datatype, the right things happen (see
* special cases in coerce_type). Otherwise, this fails: INSERT * special cases in coerce_type). Otherwise, this fails:
* INTO foo SELECT 'bar', ... FROM baz * INSERT INTO foo SELECT 'bar', ... FROM baz
*----------
*/ */
qry->targetList = NIL; qry->targetList = NIL;
foreach(tl, selectQuery->targetList) foreach(tl, selectQuery->targetList)
...@@ -631,9 +633,12 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, ...@@ -631,9 +633,12 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
if (resnode->resjunk) if (resnode->resjunk)
continue; continue;
if (tle->expr && if (tle->expr &&
(IsA(tle->expr, Const) ||IsA(tle->expr, Param)) && (IsA(tle->expr, Const) || IsA(tle->expr, Param)) &&
exprType((Node *) tle->expr) == UNKNOWNOID) exprType((Node *) tle->expr) == UNKNOWNOID)
{
expr = tle->expr; expr = tle->expr;
copy_up_hack = true;
}
else else
expr = (Expr *) makeVar(rtr->rtindex, expr = (Expr *) makeVar(rtr->rtindex,
resnode->resno, resnode->resno,
...@@ -703,6 +708,28 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, ...@@ -703,6 +708,28 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("INSERT has more target columns than expressions"))); 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 */ /* done building the range table and jointree */
qry->rtable = pstate->p_rtable; qry->rtable = pstate->p_rtable;
qry->jointree = makeFromExpr(pstate->p_joinlist, NULL); qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment