问题
There has been some curious update in the way enum
types work between PostgreSQL 9.0 and 9.1. The pg_catalog.pg_enum
table has a new column enumsortorder
in PostgreSQL 9.1. This order seems to override the previous enum ordering based on OIDs.
PostgreSQL 9.0 Documentation
The OIDs for a particular enum type are guaranteed to be ordered in the way the type should sort, but there is no guarantee about the ordering of OIDs of unrelated enum types.
PostgreSQL 9.1 Documentation
The OIDs for pg_enum rows follow a special rule: even-numbered OIDs are guaranteed to be ordered in the same way as the sort ordering of their enum type. That is, if two even OIDs belong to the same enum type, the smaller OID must have the smaller enumsortorder value. Odd-numbered OID values need bear no relationship to the sort order. This rule allows the enum comparison routines to avoid catalog lookups in many common cases. The routines that create and alter enum types attempt to assign even OIDs to enum values whenever possible.
When an enum type is created, its members are assigned sort-order positions 1..n. But members added later might be given negative or fractional values of enumsortorder. The only requirement on these values is that they be correctly ordered and unique within each enum type.
My question
For the jOOQ code generator, I'm reading the pg_catalog.pg_enum
table, ordering enum literals by OID, the way it was specified in PostgreSQL 9.0. With the udpated specification, it seems that I should order the literals by enumsortorder
, which seems to behave differently as it respects enum literal insertions "in the middle".
What's the most reliable, cross-version compatible way to read these enum literals from the pg_catalog
?
回答1:
I think you'll need to check the PostgreSQL version and change behaviour appropriately, or use SQL that doesn't touch the catalog to determine the ordering.
An idea for the latter, given dummy enum:
CREATE TYPE test_enum AS ENUM ('z','x','y');
ALTER TYPE test_enum ADD VALUE 'a' BEFORE 'x';
is to ORDER BY
the cast of the enum label to values of the enum type using the row_number
window function available in 8.4 and newer:
SELECT enumlabel, row_number() OVER (ORDER BY enumlabel::test_enum) AS sort_key
FROM pg_catalog.pg_enum
WHERE enumtypid = 'test_enum'::regtype;
This gets you the labels ordered by a sort key. In older Pg versions Pg will just sort by the oid
of the enum values, in newer versions it'll use the enumsortorder, but you don't have to care either way, you've just told PostgreSQL "sort these into the correct order please".
Or if you just need them in the order the server expects, write:
SELECT enumlabel
FROM pg_catalog.pg_enum
WHERE enumtypid = 'test_enum'::regtype
ORDER BY enumlabel::test_enum
来源:https://stackoverflow.com/questions/18398590/the-difference-in-ordering-of-enum-type-literals-between-postgresql-9-0-and-9-1