Do not access indclass through Form_pg_index
authorPeter Eisentraut <peter_e@gmx.net>
Fri, 27 Jan 2012 18:08:34 +0000 (20:08 +0200)
committerPeter Eisentraut <peter_e@gmx.net>
Fri, 27 Jan 2012 18:08:34 +0000 (20:08 +0200)
Normally, accessing variable-length members of catalog structures past
the first one doesn't work at all.  Here, it happened to work because
indnatts was checked to be 1, and so the defined FormData_pg_index
layout, using int2vector[1] and oidvector[1] for variable-length
arrays, happened to match the actual memory layout.  But it's a very
fragile assumption, and it's not in a performance-critical path, so
code it properly using heap_getattr() instead.

bug analysis by Tom Lane

src/backend/utils/cache/relcache.c

index d0138fc7e845e64e71986f6def98e795c7f11f74..a59950e45a06d49a1dc3c0b113247ec7aaca3a80 100644 (file)
@@ -3351,15 +3351,30 @@ RelationGetIndexList(Relation relation)
    while (HeapTupleIsValid(htup = systable_getnext(indscan)))
    {
        Form_pg_index index = (Form_pg_index) GETSTRUCT(htup);
+       Datum       indclassDatum;
+       oidvector  *indclass;
+       bool        isnull;
 
        /* Add index's OID to result list in the proper order */
        result = insert_ordered_oid(result, index->indexrelid);
 
+       /*
+        * indclass cannot be referenced directly through the C struct, because
+        * it comes after the variable-width indkey field.  Must extract the
+        * datum the hard way...
+        */
+       indclassDatum = heap_getattr(htup,
+                                    Anum_pg_index_indclass,
+                                    GetPgIndexDescriptor(),
+                                    &isnull);
+       Assert(!isnull);
+       indclass = (oidvector *) DatumGetPointer(indclassDatum);
+
        /* Check to see if it is a unique, non-partial btree index on OID */
        if (index->indnatts == 1 &&
            index->indisunique && index->indimmediate &&
            index->indkey.values[0] == ObjectIdAttributeNumber &&
-           index->indclass.values[0] == OID_BTREE_OPS_OID &&
+           indclass->values[0] == OID_BTREE_OPS_OID &&
            heap_attisnull(htup, Anum_pg_index_indpred))
            oidIndex = index->indexrelid;
    }