Opened 3 months ago

Last modified 2 months ago

#35732 closed Bug

Postgresql Concat using || and Trigram similarity operator precedence bug — at Initial Version

Reported by: Gastón Avila Owned by:
Component: contrib.postgres Version: 5.1
Severity: Release blocker Keywords:
Cc: Gastón Avila Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

A change from 5.0.8 to 5.1 raised a test failure in one of our queries that combines Concat with TrigramSimilarity. @emicuencac tracked this down to a recently deployed simplification on how Concat is rendered to sql here #17471 which leads to the pipe operator not being wrapped in parenthesis which were implicit when using CONCAT(...).
Here is a more explicit example

    Model.objects
        .annotate(
            concat_result=Concat(F("field"), V("tew")),
            similarity=TrigramSimilarity("concat_result", search_term),
        )
        .filter(concat_result__trigram_similar=search_term)
        .values("field"),
        [{"field": "Matthew"}],

which works well with django 5.0.8 but fails in 5.1. It fails because the mentioned change renders CONCAT using the || operator without wrapping parenthesis and ends up sending something like this to the DB
which would render this before the change

WHERE CONCAT('something', 'other_word') % 'search_term'

but now renders

WHERE 'something' || 'other_word' % 'search_term'

which breaks the query because the similarity operator is evaluated first.

The error that looks like this

    def execute(
        self,
        query: Query,
        params: Params | None = None,
        *,
        prepare: bool | None = None,
        binary: bool | None = None,
    ) -> Self:
        """
        Execute a query or command to the database.
        """
        try:
            with self._conn.lock:
                self._conn.wait(
                    self._execute_gen(query, params, prepare=prepare, binary=binary)
                )
        except e._NO_TRACEBACK as ex:
>           raise ex.with_traceback(None)
E           django.db.utils.ProgrammingError: argument of WHERE must be type boolean, not type text
E           LINE 1: ...e" FROM "suggest_vins_makemodelsearchentry" WHERE COALESCE("...

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top