slick / slick

Slick (Scala Language Integrated Connection Kit) is a modern database query and access library for Scala
https://scala-slick.org/
BSD 2-Clause "Simplified" License
2.65k stars 609 forks source link

Add support for two-value (i.e. null-respecting) equality operator in DBs that support it #2192

Open asazernik opened 3 years ago

asazernik commented 3 years ago

Many SQL implementations have an operator that is like =, but treats null as a normal value, i.e. equal to itself and not equal to other values. There is a SQL standard syntax for this (a IS DISTINCT FROM b) that AFAICT is only supported by postgres, but there are non-standard operators with the same semantics in MySQL/MariaDB (<=>) and SQLite (IS). It's also possible to emulate this logic in standard SQL, using CASE WHEN to collapse three-value logic into two-value, though I imagine indexes have trouble with that.

My preferred route to support this would be to add a default implementation using the CASE WHEN implementation, and allow individual drivers to overwrite it with native implementations. This is similar to how upsert support was added.

What I can contribute, and what I'd like help with:

hvesalai commented 3 years ago

Hi @asazernik, a PR would be very welcome.

asazernik commented 3 years ago

Re: CASE WHEN, notDistinctFrom would look something like this:

CASE foo = bar
WHEN true THEN true
ELSE false
END

Using notDistinctFrom because it makes the mechanism more clear - using the binary nature of WHEN and ELSE logic flow to convert ternary to binary logic. The generated code is ugly, and I doubt any query planner will know how to usefully optimize this when used as a filtering or join condition, but as a fallback shim it kind of works.

I have no idea how to craft this kind of relatively complex syntax tree around values passed to a Slick method, would appreciate any pointers to similar existing code or good places to hook in.