Fix oversight in original coding of inline_function(): since
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 6 Mar 2007 22:45:16 +0000 (22:45 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 6 Mar 2007 22:45:16 +0000 (22:45 +0000)
check_sql_fn_retval allows binary-compatibility cases, the expression
extracted from an inline-able SQL function might have a type that is only
binary-compatible with the declared function result type.  To avoid possibly
changing the semantics of the expression, we should insert a RelabelType node
in such cases.  This has only been shown to have bad consequences in recent
8.1 and up releases, but I suspect there may be failure cases in the older
branches too, so patch it all the way back.  Per bug #3116 from Greg Mullane.

Along the way, fix an omission in eval_const_expressions_mutator: it failed
to copy the relabelformat field when processing a RelabelType.  No known
observable failures from this, but it definitely isn't intended behavior.

src/backend/optimizer/util/clauses.c

index 852b0f533e75d4251e128bb5aae0a3eb3e05b631..0f8231c4f913ffae04e211b34e9426b5a643a796 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.236 2007/02/22 22:00:24 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.237 2007/03/06 22:45:16 tgl Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -1976,6 +1976,7 @@ eval_const_expressions_mutator(Node *node,
            newrelabel->arg = (Expr *) arg;
            newrelabel->resulttype = relabel->resulttype;
            newrelabel->resulttypmod = relabel->resulttypmod;
+           newrelabel->relabelformat = relabel->relabelformat;
            return (Node *) newrelabel;
        }
    }
@@ -2929,7 +2930,8 @@ inline_function(Oid funcid, Oid result_type, List *args,
     * no rewriting was needed; that's probably not important, but let's be
     * careful.
     */
-   (void) check_sql_fn_retval(funcid, result_type, querytree_list, NULL);
+   if (check_sql_fn_retval(funcid, result_type, querytree_list, NULL))
+       goto fail;              /* reject whole-tuple-result cases */
 
    /*
     * Additional validity checks on the expression.  It mustn't return a set,
@@ -3014,6 +3016,21 @@ inline_function(Oid funcid, Oid result_type, List *args,
 
    MemoryContextDelete(mycxt);
 
+   /*
+    * Since check_sql_fn_retval allows binary-compatibility cases, the
+    * expression we now have might return some type that's only binary
+    * compatible with the original expression result type.  To avoid
+    * confusing matters, insert a RelabelType in such cases.
+    */
+   if (exprType(newexpr) != funcform->prorettype)
+   {
+       Assert(IsBinaryCoercible(exprType(newexpr), funcform->prorettype));
+       newexpr = (Node *) makeRelabelType((Expr *) newexpr,
+                                          funcform->prorettype,
+                                          -1,
+                                          COERCE_IMPLICIT_CAST);
+   }
+
    /*
     * Recursively try to simplify the modified expression.  Here we must add
     * the current function to the context list of active functions.