Ensure that the resolved datatype of any unknown Param is propagated
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 19 Feb 2005 19:33:42 +0000 (19:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 19 Feb 2005 19:33:42 +0000 (19:33 +0000)
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

index 8ea47922b18b7c3e3ac7e24c3d0f8c004854fbbb..867c68d9a5b765e71cf1ba530ed21e1d0e22181a 100644 (file)
@@ -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);