fix(restheadspec,resolvespec): stop casting SqlNull-wrapped and citext columns to TEXT in filters

reflect.Type.Kind() on spectypes.SqlNull[T] wrappers (SqlInt16/32/64,
SqlFloat64, SqlBool, SqlString, and embedders like SqlTimeStamp) always
reports reflect.Struct, never the wrapped T. ValidateAndAdjustFilterForColumnType
treated those as "complex" columns and forced CAST(col AS TEXT) on eq/gt/lt
filters, e.g. CAST(atdetail.rid_parent AS TEXT) = '90446096', which can't
use the index on rid_parent.

Add spectypes.UnwrapKind to see through SqlNull wrappers to the underlying
Kind, and use it in GetColumnTypeFromModel so numeric/string SqlNull columns
are recognized correctly and compared natively.

Also stop unconditionally casting to TEXT for LIKE/ILIKE and add
reflection.IsCitextColumn: citext columns are already case-insensitive, so
casting them to TEXT flips to case-sensitive matching and defeats a citext
index.
This commit is contained in:
Hein
2026-09-15 11:18:13 +02:00
parent 1885ce016b
commit 6bd6a6f164
8 changed files with 253 additions and 21 deletions
+6
View File
@@ -1466,6 +1466,12 @@ func (h *Handler) ValidateAndAdjustFilterForColumnType(filter *common.FilterOpti
return ColumnCastInfo{NeedsCast: false, IsNumericType: false}
}
// Never cast citext columns to TEXT: CAST(col AS TEXT) swaps in case-sensitive
// comparison semantics and prevents PostgreSQL from using a citext index.
if reflection.IsCitextColumn(model, filter.Column) {
return ColumnCastInfo{NeedsCast: false, IsNumericType: false}
}
colType := reflection.GetColumnTypeFromModel(model, filter.Column)
if colType == reflect.Invalid {
// Column not found in model, no casting needed