0

I am in an existing Postgres 14 database that has the following Operators and Functions in place that augment an '=' or 'LIKE' query to leverage 'lower()' (thus allowing the query to take advantage of Indexes). This is allowing us to do case-insensitive queries without having to directly include 'lower()' in the query.

-- ------------ CREATE FUNCTIONS -----------

CREATE OR REPLACE FUNCTION ci_caseinsmatch(varchar, varchar) RETURNS boolean
AS $$
SELECT LOWER($1)::text = LOWER($2)::text;
$$
    LANGUAGE sql
    IMMUTABLE STRICT;

CREATE FUNCTION ci_like(varchar, varchar) RETURNS boolean
AS $$
SELECT LOWER($1)::text LIKE LOWER($2)::text;
$$
    LANGUAGE sql;       
        
-- ------------ CREATE OPERATORS -----------

CREATE OPERATOR = (
    PROCEDURE = ci_caseinsmatch,
    LEFTARG = varchar,
    RIGHTARG = varchar,
    COMMUTATOR = =,
    NEGATOR = <>
    );

CREATE OPERATOR ~~(
    PROCEDURE = ci_like,
    LEFTARG = varchar,
    RIGHTARG = varchar,
    RESTRICT = likesel,
    JOIN = likejoinsel);

(That code courtesy of postgresonline)

With the proper indexes in place, this gets us the ability to do fast case-insensitive searches like

select * from packages where a_varchar_column='Bd1261d5-6e47-481f-a7e2-6f54c88dd8eb';

or

select * from packages where a_varchar_column LIKE 'Bd1261d5-6e47-481f-a7e2-6f54c88dd8eb';

any time we're comparing VARCHAR's, without worrying about the casing of characters, or having to interject lower() in to the queries manually.

Now I want to extend that capability to IN queries, like this

select * from packages where a_varchar_column IN ('b8fec092-fdea-4c1f-bf30-7f4124da660e', 'ae7a78f3-d419-4361-95c9-9254f1c76da2')

But IN (which translates to =AND) is not an Operator. So I can't CREATE OPERATOR IN nor CREATE OPERATOR =AND.

So the underlying question is, can I interject a function any time an '=AND' construct is called, and how do I set up that trigger ?

In this case it happens to be desired when we have a varchar on the left that we want forced to lower(), but that's already handled by the Function.

I know for certain that if my app were using lower() like this

select * from packages where lower(a_varchar_column) IN ('b8fec092-fdea-4c1f-bf30-7f4124da660e', 'ae7a78f3-d419-4361-95c9-9254f1c76da2')

that the query is fast and takes advantage of our Indexes. But I'm trying to have the database do that on the applications behalf.

hp3ba
  • 1
  • 2
  • Why aren't you using a case-insensitive type rather than varchar? – Richard Huxton Oct 27 '22 at 08:13
  • There are no case-insensitive types in PG, but there exists case-insensitive queries in multiple legacy apps that share this same database (that was migrated from case-insensitive MSSQL). The CITEXT extension did not work as well as the above work-around (for us). We're just iterating our way out of Legacy while KTLO. – hp3ba Oct 27 '22 at 20:51

0 Answers0