lpsmith / postgresql-simple

Mid-level client library for accessing PostgreSQL from Haskell
Other
206 stars 71 forks source link

Invalid ranges should not be silently converted to 'empty' #220

Open cimmanon opened 7 years ago

cimmanon commented 7 years ago

If you query PostgreSQL directly, valid ranges are accepted and invalid ranges throw an error.

test=> select '[1,5]' :: int4range;
 int4range
-----------
 [1,6)
(1 row)

test=> select '[5,1]' :: int4range;
ERROR:  range lower bound must be less than or equal to range upper bound
LINE 1: select '[5,1]' :: int4range;
               ^

When postgresql-simple encounters an invalid range, it silently converts it to an empty range. This behavior is counterintuitive and wrong. Either throw an exception when converting it ToRow or pass the invalid range to Postgres so it can throw an error.

lpsmith commented 6 years ago

As a classically trained mathematician, I find the behavior currently implemented perfectly intuitive, and postgresql's behavior much too pedantic. It's easy to see that [4,3] @> x <=> 4 <= x <= 3 <=> 4 <= x && x <= 3 is an empty range. And from the point of view of software engineering, I feel that if a construct has a unique logically consistent interpretation, that the construct should be accepted and not prohibited arbitrarily.

cimmanon commented 6 years ago

You might have a point if this was a stand alone library, but it's not. The sole purpose here is to talk to PostgreSQL. If PostgreSQL throws an error when I supply [5,1), any library that talks to PostgreSQL should behave the same way. If I tried to insert [5,1), how do you know I didn't intend to write something like [1,5) or [5,11)? The only time an empty range should be passed on to PostgreSQL is if an empty range is supplied.

If I were talking to PostgreSQL directly, it would have protected me against an invalid range and given me the opportunity to fix it. By silently changing the content to mean something else entirely in order to make it "fit", you're effectively removed constraints provided by the database that are intended to protect the user from their own fat fingers.