]> granicus.if.org Git - postgresql/commitdiff
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;
        }