Avoid an Assert failure in deconstruct_array() by making get_attstatsslot()
authorTom Lane <[email protected]>
Fri, 9 Jul 2010 22:58:17 +0000 (22:58 +0000)
committerTom Lane <[email protected]>
Fri, 9 Jul 2010 22:58:17 +0000 (22:58 +0000)
use the actual element type of the array it's disassembling, rather than
trusting the type OID passed in by its caller.  This is needed because
sometimes the planner passes in a type OID that's only binary-compatible
with the target column's type, rather than being an exact match.  Per an
example from Bernd Helmle.

Possibly we should refactor get_attstatsslot/free_attstatsslot to not expect
the caller to supply type ID data at all, but for now I'll just do the
minimum-change fix.

Back-patch to 7.4.  Bernd's test case only crashes back to 8.0, but since
these subroutines are the same in 7.4, I suspect there may be variant
cases that would crash 7.4 as well.

src/backend/utils/cache/lsyscache.c

index e81f89c662ca1b908e5b7c35bf80c84648bce704..26102e96e4034f0df47e7e70e70c180c0aa97f8c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.119.4.1 2007/10/13 15:56:08 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.119.4.2 2010/07/09 22:58:17 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
@@ -1888,6 +1888,10 @@ get_attavgwidth(Oid relid, AttrNumber attnum)
  * If the attribute type is pass-by-reference, the values referenced by
  * the values array are themselves palloc'd.  The palloc'd stuff can be
  * freed by calling free_attstatsslot.
+ *
+ * Note: at present, atttype/atttypmod aren't actually used here at all.
+ * But the caller must have the correct (or at least binary-compatible)
+ * type ID to pass to free_attstatsslot later.
  */
 bool
 get_attstatsslot(HeapTuple statstuple,
@@ -1902,6 +1906,7 @@ get_attstatsslot(HeapTuple statstuple,
        Datum           val;
        bool            isnull;
        ArrayType  *statarray;
+       Oid                     arrayelemtype;
        int                     narrayelem;
        HeapTuple       typeTuple;
        Form_pg_type typeForm;
@@ -1924,17 +1929,24 @@ get_attstatsslot(HeapTuple statstuple,
                        elog(ERROR, "stavalues is null");
                statarray = DatumGetArrayTypeP(val);
 
-               /* Need to get info about the array element type */
+               /*
+                * Need to get info about the array element type.  We look at the
+                * actual element type embedded in the array, which might be only
+                * binary-compatible with the passed-in atttype.  The info we
+                * extract here should be the same either way, but deconstruct_array
+                * is picky about having an exact type OID match.
+                */
+               arrayelemtype = ARR_ELEMTYPE(statarray);
                typeTuple = SearchSysCache(TYPEOID,
-                                                                  ObjectIdGetDatum(atttype),
+                                                                  ObjectIdGetDatum(arrayelemtype),
                                                                   0, 0, 0);
                if (!HeapTupleIsValid(typeTuple))
-                       elog(ERROR, "cache lookup failed for type %u", atttype);
+                       elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
                typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
 
                /* Deconstruct array into Datum elements */
                deconstruct_array(statarray,
-                                                 atttype,
+                                                 arrayelemtype,
                                                  typeForm->typlen,
                                                  typeForm->typbyval,
                                                  typeForm->typalign,