Symptom
A query selecting a column whose type is an array of a domain fails at run time with
UnexpectedColumnTypeStatementError 33 1001 211356
^ ^ the domain's array OID in this database
bytea[]
Nothing catches it at compile time. It surfaces the first time that query runs.
Why
hasql validates each result column's OID against the decoder. For a scalar domain column PostgreSQL reports the domain's base type in the row description, so Hasql.Decoders.bytea decodes a bytea-backed domain column fine — which is what sqlc-hs emits, and it is correct. For an array of a domain it reports the domain's own array OID instead, and the plain bytea/text decoder's array OID no longer matches.
The array OID is assigned per database, so it cannot be a constant.
What the fix looks like
Hasql.{Encoders,Decoders}.custom takes a type name and Nothing for the static OIDs, and hasql then resolves both the scalar and array OID from pg_type by name at run time. So for an array-of-domain column the codec wants to be
Hasql.Decoders.custom Nothing "opcua_attribute_value" Nothing [] (\_lookup bytes -> ...)
rather than Hasql.Decoders.bytea. Encoders.custom takes one argument more than the decoder — a render function used only in error messages.
sqlc-hs already has everything it needs to decide this: column ^. #isArray says it is an array, and columnDataType (column ^. #type') is the domain name. hasqlColumnCodec is where the choice would go.
Workaround today
Per-column hasql_encoder / hasql_decoder overrides naming a hand-written codec, one pair per column, plus nullable: true and nullable: false variants of each (see the other issue about nullable defaulting). In an application with four such columns that is eight override entries and two hand-written codec pairs to express something the plugin could derive.
Finding the affected columns in a schema:
SELECT c.relname, a.attname
FROM pg_class c
JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 AND NOT a.attisdropped
JOIN pg_type t ON t.oid = a.atttypid
JOIN pg_type el ON el.oid = t.typelem
WHERE c.relkind = 'r' AND t.typcategory = 'A' AND el.typtype = 'd';
Symptom
A query selecting a column whose type is an array of a domain fails at run time with
Nothing catches it at compile time. It surfaces the first time that query runs.
Why
hasql validates each result column's OID against the decoder. For a scalar domain column PostgreSQL reports the domain's base type in the row description, so
Hasql.Decoders.byteadecodes abytea-backed domain column fine — which is what sqlc-hs emits, and it is correct. For an array of a domain it reports the domain's own array OID instead, and the plainbytea/textdecoder's array OID no longer matches.The array OID is assigned per database, so it cannot be a constant.
What the fix looks like
Hasql.{Encoders,Decoders}.customtakes a type name andNothingfor the static OIDs, and hasql then resolves both the scalar and array OID frompg_typeby name at run time. So for an array-of-domain column the codec wants to berather than
Hasql.Decoders.bytea.Encoders.customtakes one argument more than the decoder — a render function used only in error messages.sqlc-hs already has everything it needs to decide this:
column ^. #isArraysays it is an array, andcolumnDataType (column ^. #type')is the domain name.hasqlColumnCodecis where the choice would go.Workaround today
Per-column
hasql_encoder/hasql_decoderoverrides naming a hand-written codec, one pair per column, plusnullable: trueandnullable: falsevariants of each (see the other issue aboutnullabledefaulting). In an application with four such columns that is eight override entries and two hand-written codec pairs to express something the plugin could derive.Finding the affected columns in a schema: