Skip to main content
1 of 3

When an index is created from a function on a column, we get the function name instead of the column name in pg_attribute in Postgres. How to fix it?

I have come up with the following query to get the table name, index_type, operator_classes, and uniqueness of indexes based on the answers mostly from @Erwin Brandstetter:

SELECT i.indrelid::regclass::text AS table
     , c.relname AS index_name
     , a.amname AS index_type
     , opc.operator_classes
     , i.indisunique AS is_unique
     , array_agg(att.attname) as column_names
FROM   pg_catalog.pg_namespace n
JOIN   pg_catalog.pg_class     c ON c.relnamespace = n.oid
JOIN   pg_catalog.pg_attribute att ON att.attrelid = c.oid
JOIN   pg_catalog.pg_index     i ON i.indexrelid = c.oid
JOIN   pg_catalog.pg_am        a ON a.oid = c.relam
CROSS  JOIN LATERAL (
   SELECT ARRAY (SELECT opc.opcname
                 FROM   unnest(i.indclass::oid[]) WITH ORDINALITY o(oid, ord)
                 JOIN   pg_opclass opc ON opc.oid = o.oid
                 ORDER  BY o.ord)
   ) opc(operator_classes)
WHERE  n.nspname !~ '^pg_'
AND    c.relkind = ANY (ARRAY['r', 't', 'i'])
group by
   i.indrelid, c.relname, a.amname, opc.operator_classes, i.indisunique
ORDER  BY 1, 2, 3, 4;

This works great, except it returns the wrong column names when the index is created by transforming data from another column. For example, with the following index:

CREATE INDEX _ixtr_luxury_inventory_images ON public.luxury_inventory USING gin (f_textarr2text(images) gin_trgm_ops)

returns:

table            | luxury_inventory
index_name       | _ixtr_luxury_inventory_images
index_type       | gin
operator_classes | ['gin_trgm_ops']
is_unique        | False
column_names     | ['f_textarr2text']

We get f_textarr2text as the column name instead of images.

How can we get the correct column_names? I'm on Postgres 16.2 if that matters.