Edgewall Software

Ticket #8519: 8519-replace-like-r8958.patch

File 8519-replace-like-r8958.patch, 9.3 KB (added by rblank, 2 years ago)

Replace case-sensitive LIKE clauses with range clauses.

  • trac/db/mysql_backend.py

    diff --git a/trac/db/mysql_backend.py b/trac/db/mysql_backend.py
    a b  
    214214        return 'concat(%s)' % ', '.join(args) 
    215215 
    216216    def like(self): 
     217        """Return a case-insensitive LIKE clause.""" 
    217218        return "LIKE %s COLLATE utf8_general_ci ESCAPE '/'" 
    218219 
    219220    def like_escape(self, text): 
  • trac/db/postgres_backend.py

    diff --git a/trac/db/postgres_backend.py b/trac/db/postgres_backend.py
    a b  
    197197        return '||'.join(args) 
    198198 
    199199    def like(self): 
    200         # Temporary hack needed for the case-insensitive string matching in the 
    201         # search module 
     200        """Return a case-insensitive LIKE clause.""" 
    202201        return "ILIKE %s ESCAPE '/'" 
    203202 
    204203    def like_escape(self, text): 
  • trac/db/sqlite_backend.py

    diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py
    a b  
    253253        return '||'.join(args) 
    254254 
    255255    def like(self): 
     256        """Return a case-insensitive LIKE clause.""" 
    256257        if sqlite_version >= 30100: 
    257258            return "LIKE %s ESCAPE '/'" 
    258259        else: 
  • trac/ticket/model.py

    diff --git a/trac/ticket/model.py b/trac/ticket/model.py
    a b  
    382382        cursor.execute("SELECT time,author FROM ticket_change " 
    383383                       "WHERE ticket=%%s AND field='comment' " 
    384384                       "  AND (oldvalue=%%s OR oldvalue %s)" % db.like(), 
    385                        (self.id, scnum, '%.' + db.like_escape(scnum))) 
     385                       (self.id, scnum, '%' + db.like_escape('.' + scnum))) 
    386386        for ts, author in cursor: 
    387387            cursor.execute("SELECT field,author,oldvalue,newvalue " 
    388388                           "FROM ticket_change " 
     
    403403        when_ts = to_timestamp(when) 
    404404         
    405405        db, handle_ta = self._get_db_for_write(db) 
    406         like = db.like() 
    407406        cursor = db.cursor() 
    408407        cursor.execute("SELECT time,newvalue FROM ticket_change " 
    409408                       "WHERE ticket=%%s AND field='comment' " 
    410                        "  AND (oldvalue=%%s OR oldvalue %s)" % like, 
    411                        (self.id, scnum, '%.' + db.like_escape(scnum))) 
     409                       "  AND (oldvalue=%%s OR oldvalue %s)" % db.like(), 
     410                       (self.id, scnum, '%' + db.like_escape('.' + scnum))) 
    412411        for (ts, old_comment) in cursor: 
    413412            if comment == old_comment: 
    414413                return 
    415414            cursor.execute("SELECT COUNT(ticket) FROM ticket_change " 
    416                            "WHERE ticket=%%s AND time=%%s AND field %s" % like, 
    417                            (self.id, ts, db.like_escape('_comment') + '%')) 
     415                           "WHERE ticket=%s AND time=%s " 
     416                           "  AND field>='_comment0' and field<'_comment:'", 
     417                           (self.id, ts)) 
    418418            rev = cursor.fetchone()[0] 
    419419            cursor.execute("INSERT INTO ticket_change " 
    420420                           "(ticket,time,author,field,oldvalue,newvalue) " 
     
    431431    def get_comment_history(self, cnum, db=None): 
    432432        scnum = str(cnum) 
    433433        db = self._get_db(db) 
    434         like = db.like() 
    435434        history = [] 
    436435        cursor = db.cursor() 
    437436        cursor.execute("SELECT time,author,newvalue FROM ticket_change " 
    438437                       "WHERE ticket=%%s AND field='comment' " 
    439                        "  AND (oldvalue=%%s OR oldvalue %s)" % like, 
    440                        (self.id, scnum, '%.' + db.like_escape(scnum))) 
     438                       "  AND (oldvalue=%%s OR oldvalue %s)" % db.like(), 
     439                       (self.id, scnum, '%' + db.like_escape('.' + scnum))) 
    441440        for (ts0, author0, last_comment) in cursor: 
    442441            cursor.execute("SELECT field,author,oldvalue,newvalue " 
    443442                           "FROM ticket_change " 
    444                            "WHERE ticket=%%s AND time=%%s AND field %s" % like, 
    445                            (self.id, ts0, db.like_escape('_comment') + '%')) 
     443                           "WHERE ticket=%s AND time=%s " 
     444                           "  AND field>='_comment0' and field<'_comment:'", 
     445                           (self.id, ts0)) 
    446446            for field, author, comment, ts in cursor: 
    447447                rev = int(field[8:]) 
    448448                history.append((rev, datetime.fromtimestamp(int(ts0), utc), 
  • trac/ticket/tests/query.py

    diff --git a/trac/ticket/tests/query.py b/trac/ticket/tests/query.py
    a b  
    210210FROM ticket AS t 
    211211  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    212212WHERE ((COALESCE(t.owner,'') %(like)s)) 
    213 ORDER BY COALESCE(t.id,0)=0,t.id""" %  {'like': self.env.get_db_cnx().like()}) 
     213ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().like()}) 
    214214        self.assertEqual(['%someone%'], args) 
    215215        tickets = query.execute(self.req) 
    216216 
     
    222222FROM ticket AS t 
    223223  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    224224WHERE ((COALESCE(t.owner,'') NOT %(like)s)) 
    225 ORDER BY COALESCE(t.id,0)=0,t.id""" %  {'like': self.env.get_db_cnx().like()}) 
     225ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().like()}) 
    226226        self.assertEqual(['%someone%'], args) 
    227227        tickets = query.execute(self.req) 
    228228 
     
    234234FROM ticket AS t 
    235235  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    236236WHERE ((COALESCE(t.owner,'') %(like)s)) 
    237 ORDER BY COALESCE(t.id,0)=0,t.id""" %  {'like': self.env.get_db_cnx().like()}) 
     237ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().like()}) 
    238238        self.assertEqual(['someone%'], args) 
    239239        tickets = query.execute(self.req) 
    240240 
     
    246246FROM ticket AS t 
    247247  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    248248WHERE ((COALESCE(t.owner,'') %(like)s)) 
    249 ORDER BY COALESCE(t.id,0)=0,t.id""" %  {'like': self.env.get_db_cnx().like()}) 
     249ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().like()}) 
    250250        self.assertEqual(['%someone'], args) 
    251251        tickets = query.execute(self.req) 
    252252 
     
    423423FROM ticket AS t 
    424424  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    425425WHERE (((COALESCE(t.keywords,'') %(like)s AND COALESCE(t.keywords,'') NOT %(like)s AND COALESCE(t.keywords,'') %(like)s))) 
    426 ORDER BY COALESCE(t.id,0)=0,t.id"""  % {'like': self.env.get_db_cnx().like()}) 
     426ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().like()}) 
    427427        self.assertEqual(['%foo%', '%bar%', '%baz%'], args) 
    428428        tickets = query.execute(self.req) 
    429429 
  • trac/versioncontrol/cache.py

    diff --git a/trac/versioncontrol/cache.py b/trac/versioncontrol/cache.py
    a b  
    245245        rev_as_int = db.cast('rev', 'int') 
    246246        if first is None: 
    247247            cursor.execute("SELECT rev FROM node_change " 
    248                            "WHERE path = %%s " 
     248                           "WHERE %s <= %%s " 
     249                           "  AND path = %%s " 
    249250                           "  AND change_type IN ('A', 'C', 'M') " 
    250                            "  AND %s <= %%s " 
    251251                           "ORDER BY %s DESC " 
    252252                           "LIMIT 1" % ((rev_as_int,) * 2), 
    253253                           (path, last)) 
     
    255255            for row in cursor: 
    256256                first = int(row[0]) 
    257257        cursor.execute("SELECT DISTINCT rev FROM node_change " 
    258                        "WHERE (path = %%s OR path %s) " 
    259                        " AND %s >= %%s AND %s <= %%s" %  
    260                        (db.like(), rev_as_int, rev_as_int), 
    261                        (path, db.like_escape(path + '/') + '%', first, last)) 
     258                       "WHERE %s >= %%s AND %s <= %%s " 
     259                       "  AND (path = %%s OR (path >= %%s AND path < %%s))" % 
     260                       (rev_as_int, rev_as_int), 
     261                       (first, last, path, path + '/', path + '0')) 
    262262        return [int(row[0]) for row in cursor] 
    263263 
    264264    def has_node(self, path, rev=None): 
     
    293293 
    294294        if path: 
    295295            path = path.lstrip('/') 
    296             sql += " AND (" 
    297             # changes on path itself 
    298             sql += "path=%s " 
    299             args.append(path) 
    300             sql += " OR " 
    301             # changes on path children 
    302             sql += "path "+db.like() 
    303             args.append(db.like_escape(path+'/') + '%') 
    304             sql += " OR " 
     296            # changes on path itself or its children 
     297            sql += " AND (path = %s OR (path >= %s AND path < %s)" 
     298            args.extend((path, path + '/', path + '0')) 
    305299            # deletion of path ancestors 
    306300            components = path.lstrip('/').split('/') 
    307             for i in range(1, len(components)+1): 
     301            parents = ','.join(('%s',) * len(components)) 
     302            sql += " OR (path IN (" + parents + ") AND change_type = 'D'))" 
     303            for i in range(1, len(components) + 1): 
    308304                args.append('/'.join(components[:i])) 
    309             parent_insert = ','.join(('%s',) * len(components)) 
    310             sql += " (path in (" + parent_insert + ") and change_type='D')" 
    311             sql += ")" 
    312305 
    313306        sql += " ORDER BY " + db.cast('rev', 'int') + \ 
    314307                (direction == '<' and " DESC" or "") + " LIMIT 1"