]> granicus.if.org Git - postgresql/commitdiff
Ensure that the resolved datatype of any unknown Param is propagated
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 19 Feb 2005 19:33:08 +0000 (19:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 19 Feb 2005 19:33:08 +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 c2c0ef4408dcd2e0d5f04e8acdd9785608474cd9..cc27b0b7bad1d9a4441af4505ee94701645a2acf 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * 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,
                                        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;
@@ -561,7 +563,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
                 * be able to see.
                 */
                ParseState *sub_pstate = make_parsestate(pstate);
-               Query      *selectQuery;
                RangeTblEntry *rte;
                RangeTblRef *rtr;
 
@@ -608,7 +609,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,
@@ -618,8 +619,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)
@@ -631,9 +633,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,
@@ -703,6 +708,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);