Change plpgsql's cast cache to consider source typmod as significant.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 5 Mar 2015 01:23:13 +0000 (20:23 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 5 Mar 2015 01:23:13 +0000 (20:23 -0500)
I had thought that there was no need to maintain separate cache entries
for different source typmods, but further experimentation shows that there
is an advantage to doing so in some cases.  In particular, if a domain has
a typmod (say, "CREATE DOMAIN d AS numeric(20,0)"), failing to notice the
source typmod leads to applying a length-coercion step even when the
source has the correct typmod.

src/pl/plpgsql/src/pl_exec.c

index 315d28b8fae8e6cac9efb7b9af94fb82e3b19b89..f24f55a2ff43bcffd83e7639809e80f162650d89 100644 (file)
@@ -57,6 +57,7 @@ typedef struct
        /* NB: we assume this struct contains no padding bytes */
        Oid                     srctype;                /* source type for cast */
        Oid                     dsttype;                /* destination type for cast */
+       int32           srctypmod;              /* source typmod for cast */
        int32           dsttypmod;              /* destination typmod for cast */
 } plpgsql_CastHashKey;
 
@@ -231,7 +232,7 @@ static Datum exec_cast_value(PLpgSQL_execstate *estate,
                                Oid valtype, int32 valtypmod,
                                Oid reqtype, int32 reqtypmod);
 static ExprState *get_cast_expression(PLpgSQL_execstate *estate,
-                                       Oid srctype, Oid dsttype, int32 dsttypmod);
+                                Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod);
 static void exec_init_tuple_store(PLpgSQL_execstate *estate);
 static void exec_set_found(PLpgSQL_execstate *estate, bool state);
 static void plpgsql_create_econtext(PLpgSQL_execstate *estate);
@@ -5733,7 +5734,9 @@ exec_cast_value(PLpgSQL_execstate *estate,
        {
                ExprState  *cast_expr;
 
-               cast_expr = get_cast_expression(estate, valtype, reqtype, reqtypmod);
+               cast_expr = get_cast_expression(estate,
+                                                                               valtype, valtypmod,
+                                                                               reqtype, reqtypmod);
                if (cast_expr)
                {
                        ExprContext *econtext = estate->eval_econtext;
@@ -5769,7 +5772,7 @@ exec_cast_value(PLpgSQL_execstate *estate,
  */
 static ExprState *
 get_cast_expression(PLpgSQL_execstate *estate,
-                                       Oid srctype, Oid dsttype, int32 dsttypmod)
+                                 Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
 {
        HTAB       *cast_hash = estate->func->cast_hash;
        plpgsql_CastHashKey cast_key;
@@ -5799,6 +5802,7 @@ get_cast_expression(PLpgSQL_execstate *estate,
        /* Look for existing entry */
        cast_key.srctype = srctype;
        cast_key.dsttype = dsttype;
+       cast_key.srctypmod = srctypmod;
        cast_key.dsttypmod = dsttypmod;
        cast_entry = (plpgsql_CastHashEntry *) hash_search(cast_hash,
                                                                                                           (void *) &cast_key,
@@ -5815,7 +5819,7 @@ get_cast_expression(PLpgSQL_execstate *estate,
         */
        placeholder = makeNode(CaseTestExpr);
        placeholder->typeId = srctype;
-       placeholder->typeMod = -1;
+       placeholder->typeMod = srctypmod;
        placeholder->collation = get_typcollation(srctype);
        if (OidIsValid(estate->func->fn_input_collation) &&
                OidIsValid(placeholder->collation))