Skip to content

Commit 9650d6c

Browse files
committed
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.
1 parent 2abe40a commit 9650d6c

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

src/backend/parser/analyze.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.314 2004/12/31 22:00:26 pgsql Exp $
9+
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.315 2005/02/19 19:33:08 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -506,6 +506,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
506506
List **extras_before, List **extras_after)
507507
{
508508
Query *qry = makeNode(Query);
509+
Query *selectQuery = NULL;
510+
bool copy_up_hack = false;
509511
List *sub_rtable;
510512
List *sub_namespace;
511513
List *icolumns;
@@ -561,7 +563,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
561563
* be able to see.
562564
*/
563565
ParseState *sub_pstate = make_parsestate(pstate);
564-
Query *selectQuery;
565566
RangeTblEntry *rte;
566567
RangeTblRef *rtr;
567568

@@ -608,7 +609,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
608609
Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
609610
pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
610611

611-
/*
612+
/*----------
612613
* Generate a targetlist for the INSERT that selects all the
613614
* non-resjunk columns from the subquery. (We need this to be
614615
* separate from the subquery's tlist because we may add columns,
@@ -618,8 +619,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
618619
* are copied up as-is rather than being referenced as subquery
619620
* outputs. This is to ensure that when we try to coerce them to
620621
* the target column's datatype, the right things happen (see
621-
* special cases in coerce_type). Otherwise, this fails: INSERT
622-
* INTO foo SELECT 'bar', ... FROM baz
622+
* special cases in coerce_type). Otherwise, this fails:
623+
* INSERT INTO foo SELECT 'bar', ... FROM baz
624+
*----------
623625
*/
624626
qry->targetList = NIL;
625627
foreach(tl, selectQuery->targetList)
@@ -631,9 +633,12 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
631633
if (resnode->resjunk)
632634
continue;
633635
if (tle->expr &&
634-
(IsA(tle->expr, Const) ||IsA(tle->expr, Param)) &&
636+
(IsA(tle->expr, Const) || IsA(tle->expr, Param)) &&
635637
exprType((Node *) tle->expr) == UNKNOWNOID)
638+
{
636639
expr = tle->expr;
640+
copy_up_hack = true;
641+
}
637642
else
638643
expr = (Expr *) makeVar(rtr->rtindex,
639644
resnode->resno,
@@ -703,6 +708,28 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
703708
(errcode(ERRCODE_SYNTAX_ERROR),
704709
errmsg("INSERT has more target columns than expressions")));
705710

711+
/*
712+
* If we copied up any unknown Params (see HACK above) then their
713+
* resolved types need to be propagated into the Resdom nodes of
714+
* the sub-INSERT's tlist. One hack begets another :-(
715+
*/
716+
if (copy_up_hack)
717+
{
718+
foreach(tl, selectQuery->targetList)
719+
{
720+
TargetEntry *tle = (TargetEntry *) lfirst(tl);
721+
Resdom *resnode = tle->resdom;
722+
723+
if (resnode->resjunk)
724+
continue;
725+
if (resnode->restype == UNKNOWNOID)
726+
{
727+
resnode->restype = exprType((Node *) tle->expr);
728+
resnode->restypmod = exprTypmod((Node *) tle->expr);
729+
}
730+
}
731+
}
732+
706733
/* done building the range table and jointree */
707734
qry->rtable = pstate->p_rtable;
708735
qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);

0 commit comments

Comments
 (0)