Edgewall Software

Ticket #986: trac_mysql_r2628.patch

File trac_mysql_r2628.patch, 10.4 kB (added by trac@…, 3 years ago)

patch now reflects suggestion by mgood. Reverted database modification for SQLite and Postgres, only affects MySQL for AUTO_INCREMENT fields. Patch is against r2628.

  • trac/db_default.py

     
    437437) 
    438438 
    439439default_components = ('trac.About', 'trac.attachment', 
     440                      'trac.db.mysql_backend', 
    440441                      'trac.db.postgres_backend', 'trac.db.sqlite_backend', 
    441442                      'trac.mimeview.enscript', 'trac.mimeview.patch', 
    442443                      'trac.mimeview.php', 'trac.mimeview.rst', 
  • trac/ticket/api.py

     
    167167            return 
    168168        db = self.env.get_db_cnx() 
    169169        sql, args = query_to_sql(db, query, 'b.newvalue') 
    170         sql2, args2 = query_to_sql(db, query, 'summary||keywords||description||reporter||cc') 
     170        search_fields = ['summary', 'keywords', 'description', 'reporter', 'cc'] 
     171        sql_seq = [] 
     172        for f in search_fields: 
     173            subsql, subarg = query_to_sql(db, query, f) 
     174            sql_seq.append(subsql) 
     175            args += subarg 
     176        sql2 = ' OR '.join(sql_seq) 
    171177        cursor = db.cursor() 
    172         cursor.execute("SELECT DISTINCT a.summary,a.description,a.reporter, " 
    173                        "a.keywords,a.id,a.time FROM ticket a " 
    174                        "LEFT JOIN ticket_change b ON a.id = b.ticket " 
    175                        "WHERE (b.field='comment' AND %s ) OR %s" % (sql, sql2), 
    176                        args + args2) 
     178        sql3 = "SELECT DISTINCT a.summary,a.description,a.reporter, " + \ 
     179                       "a.keywords,a.id,a.time FROM ticket a " +  \ 
     180                       "LEFT JOIN ticket_change b ON a.id = b.ticket " + \ 
     181                       "WHERE (b.field='comment' AND %s ) OR %s" % (sql, sql2) 
     182        cursor.execute(sql3, args) 
    177183        for summary,desc,author,keywords,tid,date in cursor: 
    178184            yield (self.env.href.ticket(tid), 
    179185                   '#%d: %s' % (tid, util.escape(util.shorten_line(summary))), 
  • trac/db/mysql_backend.py

     
     1# -*- coding: iso8859-1 -*- 
     2# 
     3# Copyright (C) 2005 Edgewall Software 
     4# Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de> 
     5# Copyright (C) 2005 Jeff Weiss <trac@jeffweiss.org> 
     6# All rights reserved. 
     7# 
     8# This software is licensed as described in the file COPYING, which 
     9# you should have received as part of this distribution. The terms 
     10# are also available at http://trac.edgewall.com/license.html. 
     11# 
     12# This software consists of voluntary contributions made by many 
     13# individuals. For the exact contribution history, see the revision 
     14# history and logs, available at http://projects.edgewall.com/trac/. 
     15# 
     16# Derived from postgres_backend.py 
     17# Author: Christopher Lenz <cmlenz@gmx.de>  
     18# Author: Jeff Weiss <trac@jeffweiss.org> 
     19 
     20from trac.core import * 
     21from trac.db.api import IDatabaseConnector 
     22from trac.db.util import ConnectionWrapper 
     23 
     24import MySQLdb 
     25 
     26class MySQLConnector(Component): 
     27    """MySQL database support.  Still extremely experimental! 
     28Currently only supports database urls of the following formats: 
     29mysql://user:password@host/database 
     30mysql://user:password@host:port/database 
     31""" 
     32 
     33    implements(IDatabaseConnector) 
     34 
     35    def get_supported_schemes(self): 
     36        return [('mysql', 1)] 
     37 
     38    def get_connection(self, path, user=None, password=None, host=None, 
     39                       port=None, params={}): 
     40        return MySQLConnection(path, user, password, host, port, params) 
     41 
     42    def init_db(self, path, user=None, password=None, host=None, port=None, 
     43                params={}): 
     44        cnx = self.get_connection(path, user, password, host, port, params) 
     45        cursor = cnx.cursor() 
     46        from trac.db_default import schema 
     47        for table in schema: 
     48            for stmt in self.to_sql(table): 
     49                print "*****"*10 
     50                print stmt 
     51                cursor.execute(stmt) 
     52        cnx.commit() 
     53 
     54    def to_sql(self, table): 
     55        sql = ["CREATE TABLE %s (" % table.name] 
     56        coldefs = [] 
     57        textkeys = [] 
     58        textcols = [] 
     59        mytablekey = [] 
     60        num_key_text = 0 
     61        for column in table.columns: 
     62            ctype = column.type 
     63            if column.auto_increment: 
     64                ctype = "INT AUTO_INCREMENT" 
     65                # Overide the column type because otherwise it will screw 
     66                # up the rest of the code for indexes and constraints 
     67                column.type = 'int' 
     68            if column.name in table.key: 
     69                mytablekey.append(column.name) 
     70                if column.type == 'text': 
     71                    num_key_text += 1 
     72                    textkeys.append(column.name) 
     73            if column.type == 'text': 
     74                textcols.append(column.name) 
     75            coldefs.append("    `%s` %s" % (column.name, ctype)) 
     76        if len(table.key) >= 1: 
     77            if num_key_text == 0: 
     78                num_key_text = 1 
     79            size = 767 / num_key_text 
     80            keysize = "(%s)" % size 
     81            for key in textkeys: 
     82                if key in mytablekey: 
     83                    mytablekey.remove(key) 
     84                sizedkey = '`' + key + '`' + keysize 
     85                mytablekey.append(sizedkey) 
     86            coldefs.append("    CONSTRAINT %s_pk PRIMARY KEY (%s)" 
     87                           % (table.name, ','.join(mytablekey))) 
     88        sql.append(',\n'.join(coldefs) + '\n)') 
     89        yield '\n'.join(sql) 
     90# This does not work because what I need to do is not add something about 
     91# the index size for the text fields because MySQL apparrently can't index 
     92# on the entire length of the text field 
     93        for index in table.indices: 
     94            myidxcols = set([]) 
     95            processedidx = set([]) 
     96            for col in index.columns: 
     97                if col in textcols: 
     98                    myidxcols.add(col) 
     99            myidx = set(index.columns) - myidxcols 
     100            for col in myidx: 
     101               escaped_col = '`'+col+'`' 
     102               processedidx.add(escaped_col)  
     103            if len(myidxcols) > 0: 
     104                size = 767 / len(myidxcols) 
     105                idxsize  = "(%s)" % size 
     106                for col in myidxcols: 
     107                   sizedidx = '`'+col+'`'+idxsize 
     108                   processedidx.add(sizedidx)  
     109            yield "CREATE INDEX %s_%s_idx ON %s (%s)" % (table.name,  
     110                   '_'.join(index.columns), table.name, ','.join(processedidx)) 
     111 
     112 
     113class MySQLConnection(ConnectionWrapper): 
     114    """Connection wrapper for MySQL.""" 
     115 
     116    poolable = True 
     117 
     118    def __init__(self, path, usr=None, password=None, hst=None, prt=None, 
     119                 params={}): 
     120        if prt: 
     121            cnx = MySQLdb.connect(db=path[1:], user=usr, passwd=password, host=hst, port=prt) 
     122        else: 
     123            cnx = MySQLdb.connect(db=path[1:], user=usr, passwd=password, host=hst) 
     124 
     125        ConnectionWrapper.__init__(self, cnx) 
     126 
     127    def cast(self, column, type): 
     128        # Temporary hack needed for the union of selects in the search module 
     129        return 'CAST(%s AS %s)' % (column, type) 
     130 
     131    def like(self): 
     132        # Temporary hack needed for the case-insensitive string matching in the 
     133        # search module 
     134        return 'LIKE' 
     135 
     136    def get_last_id(self, cursor, table, column='id'): 
     137        sql = "SELECT MAX(`%s`) FROM %s" % (column, table) 
     138        cursor.execute(sql) 
     139        return cursor.fetchone()[0] 
  • trac/versioncontrol/web_ui/changeset.py

     
    384384            return 
    385385        authzperm = SubversionAuthorizer(self.env, req.authname) 
    386386        db = self.env.get_db_cnx() 
    387         sql, args = query_to_sql(db, query, 'message||author') 
     387        query_fields = ['message', 'author'] 
     388        sql_seq = [] 
     389        args = [] 
     390        for f in query_fields: 
     391            subsql, subarg = query_to_sql(db, query, f) 
     392            sql_seq.append(subsql)  
     393            args += subarg 
     394        sql = ' OR '.join(sql_seq) 
    388395        cursor = db.cursor() 
    389396        cursor.execute("SELECT rev,time,author,message " 
    390397                       "FROM revision WHERE " + sql, args) 
  • trac/versioncontrol/cache.py

     
    8585                    kind = kindmap[kind] 
    8686                    action = actionmap[action] 
    8787                    cursor.execute("INSERT INTO node_change (rev,path,kind," 
    88                                    "change,base_path,base_rev) " 
     88                                   "`change`,base_path,base_rev) " 
    8989                                   "VALUES (%s,%s,%s,%s,%s,%s)", 
    9090                                   (str(current_rev), path, kind, action, 
    9191                                   base_path, base_rev)) 
  • trac/web/session.py

     
    181181            # changed as to minimize the purging. 
    182182            mintime = now - PURGE_AGE 
    183183            self.env.log.debug('Purging old, expired, sessions.') 
    184             cursor.execute("DELETE FROM session WHERE authenticated=0 AND " 
    185                            "sid IN (SELECT sid FROM session WHERE " 
    186                            "var_name='last_visit' AND var_value < %s)", 
     184            # This is a temporary hack because MySQL doesn't support 
     185            # a delete statement with the subquery coming from the same 
     186            # table 
     187            cursor.execute("SELECT sid from session WHERE " 
     188                           "var_name='last_visit' AND var_value < %s", 
    187189                           (mintime,)) 
    188  
     190            sids = cursor.fetchall()  
     191            if len(sids) >= 1: 
     192                vals = [] 
     193                sids_args = [] 
     194                for t in sids: 
     195                    vals.append(t[0]) 
     196                    sids_args.append("sid = %s") 
     197                sql = "DELETE FROM session WHERE authenticated = 0 AND (%s)" % ' OR '.join(sids_args) 
     198                cursor.execute(sql, vals) 
    189199            db.commit()