Edgewall Software

Ticket #986: trac_mysql_r2644.patch

File trac_mysql_r2644.patch, 27.4 kB (added by trac@…, 3 years ago)

patch contains suggestions of cmlenz, against r2644.

  • trac/db_default.py

     
    1818from trac.db import Table, Column, Index 
    1919 
    2020# Database version identifier. Used for automatic upgrades. 
    21 db_version = 16 
     21db_version = 17 
    2222 
    2323def __mkreports(reports): 
    2424    """Utility function used to create report data in same syntax as the 
     
    8383        Column('author'), 
    8484        Column('message'), 
    8585        Index(['time'])], 
    86     Table('node_change', key=('rev', 'path', 'change'))[ 
     86    Table('node_change', key=('rev', 'path', 'change_type'))[ 
    8787        Column('rev'), 
    8888        Column('path'), 
    89         Column('kind', size=1), 
    90         Column('change', size=1), 
     89        Column('node_type', size=1), 
     90        Column('change_type', size=1), 
    9191        Column('base_path'), 
    9292        Column('base_rev'), 
    9393        Index(['rev'])], 
     
    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/tests/api.py

     
    3939                                       'host': 'localhost', 'port': 9431, 
    4040                                       'path': '/trac'}), 
    4141                         _parse_db_str('postgres://john:letmein@localhost:9431/trac')) 
     42    def test_mysql_simple(self): 
     43        self.assertEqual(('mysql', {'host': 'localhost', 'path': '/trac'}), 
     44                         _parse_db_str('mysql://localhost/trac')) 
    4245 
    43  
     46    def test_mysql_with_creds(self): 
     47        self.assertEqual(('mysql', {'user': 'john', 'password': 'letmein', 
     48                                       'host': 'localhost', 'port': 3306, 
     49                                       'path': '/trac'}), 
     50                         _parse_db_str('mysql://john:letmein@localhost:3306/trac')) 
    4451def suite(): 
    4552    return unittest.makeSuite(ParseConnectionStringTestCase,'test') 
    4653 
  • 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                self.env.log.debug(stmt) 
     50                cursor.execute(stmt) 
     51        cnx.commit() 
     52 
     53    def to_sql(self, table): 
     54        sql = ["CREATE TABLE %s (" % table.name] 
     55        coldefs = [] 
     56        textkeys = [] 
     57        textcols = [] 
     58        mytablekey = [] 
     59        num_key_text = 0 
     60        for column in table.columns: 
     61            ctype = column.type 
     62            if column.auto_increment: 
     63                ctype = "INT AUTO_INCREMENT" 
     64                # Overide the column type because otherwise it will screw 
     65                # up the rest of the code for indexes and constraints 
     66                column.type = 'int' 
     67            if column.name in table.key: 
     68                mytablekey.append(column.name) 
     69                if column.type == 'text': 
     70                    num_key_text += 1 
     71                    textkeys.append(column.name) 
     72            if column.type == 'text': 
     73                textcols.append(column.name) 
     74            coldefs.append("    `%s` %s" % (column.name, ctype)) 
     75        if len(table.key) >= 1: 
     76            if num_key_text == 0: 
     77                num_key_text = 1 
     78            size = 767 / num_key_text 
     79            keysize = "(%s)" % size 
     80            for key in textkeys: 
     81                if key in mytablekey: 
     82                    mytablekey.remove(key) 
     83                sizedkey =  '`'+key+'`' + keysize 
     84                mytablekey.append(sizedkey) 
     85            coldefs.append("    CONSTRAINT %s_pk PRIMARY KEY (%s)" 
     86                           % (table.name, ','.join(mytablekey))) 
     87        sql.append(',\n'.join(coldefs) + '\n)') 
     88        yield '\n'.join(sql) 
     89# This does not work because what I need to do is not add something about 
     90# the index size for the text fields because MySQL apparrently can't index 
     91# on the entire length of the text field 
     92        for index in table.indices: 
     93            myidxcols = set([]) 
     94            processedidx = set([]) 
     95            for col in index.columns: 
     96                if col in textcols: 
     97                    myidxcols.add(col) 
     98            myidx = set(index.columns) - myidxcols 
     99            for col in myidx: 
     100               escaped_col = '`'+col+'`' 
     101               processedidx.add(escaped_col)  
     102            if len(myidxcols) > 0: 
     103                size = 767 / len(myidxcols) 
     104                idxsize  = "(%s)" % size 
     105                for col in myidxcols: 
     106                   sizedidx = '`'+col+'`'+idxsize 
     107                   processedidx.add(sizedidx)  
     108            yield "CREATE INDEX %s_%s_idx ON %s (%s)" % (table.name,  
     109                   '_'.join(index.columns), table.name, ','.join(processedidx)) 
     110 
     111 
     112class MySQLConnection(ConnectionWrapper): 
     113    """Connection wrapper for MySQL.""" 
     114 
     115    poolable = True 
     116 
     117    def __init__(self, path, usr=None, password=None, hst=None, prt=None, 
     118                 params={}): 
     119        if prt: 
     120            cnx = MySQLdb.connect(db=path[1:], user=usr, passwd=password, host=hst, port=prt) 
     121        else: 
     122            cnx = MySQLdb.connect(db=path[1:], user=usr, passwd=password, host=hst) 
     123 
     124        ConnectionWrapper.__init__(self, cnx) 
     125 
     126    def cast(self, column, type): 
     127        # Temporary hack needed for the union of selects in the search module 
     128        return 'CAST(%s AS %s)' % (column, type) 
     129 
     130    def like(self): 
     131        # Temporary hack needed for the case-insensitive string matching in the 
     132        # search module 
     133        return 'LIKE' 
     134 
     135    def get_last_id(self, cursor, table, column='id'): 
     136        sql = "SELECT MAX(%s) FROM %s" % (column, table) 
     137        cursor.execute(sql) 
     138        return cursor.fetchone()[0] 
  • trac/versioncontrol/api.py

     
    132132    DIRECTORY = "dir" 
    133133    FILE = "file" 
    134134 
    135     def __init__(self, path, rev, kind): 
    136         assert kind in (Node.DIRECTORY, Node.FILE), "Unknown node kind %s" % kind 
     135    def __init__(self, path, rev, node_type): 
     136        assert node_type in (Node.DIRECTORY, Node.FILE), "Unknown node node_type %s" % node_type 
    137137        self.path = str(path) 
    138138        self.rev = rev 
    139         self.kind = kind 
     139        self.node_type = node_type 
    140140 
    141141    def get_content(self): 
    142142        """ 
     
    187187        raise NotImplementedError 
    188188    last_modified = property(lambda x: x.get_last_modified()) 
    189189 
    190     isdir = property(lambda x: x.kind == Node.DIRECTORY) 
    191     isfile = property(lambda x: x.kind == Node.FILE) 
     190    isdir = property(lambda x: x.node_type == Node.DIRECTORY) 
     191    isfile = property(lambda x: x.node_type == Node.FILE) 
    192192 
    193193 
    194194class Changeset(object): 
     
    210210 
    211211    def get_changes(self): 
    212212        """ 
    213         Generator that produces a (path, kind, change, base_rev, base_path) 
     213        Generator that produces a (path, node_type, change_type, base_rev, base_path) 
    214214        tuple for every change in the changeset, where change can be one of 
    215215        Changeset.ADD, Changeset.COPY, Changeset.DELETE, Changeset.EDIT or 
    216         Changeset.MOVE, and kind is one of Node.FILE or Node.DIRECTORY. 
     216        Changeset.MOVE, and node_type is one of Node.FILE or Node.DIRECTORY. 
    217217        """ 
    218218        raise NotImplementedError 
    219219 
  • trac/versioncontrol/tests/svn_fs.py

     
    117117        node = self.repos.get_node('/trunk') 
    118118        self.assertEqual('trunk', node.name) 
    119119        self.assertEqual('/trunk', node.path) 
    120         self.assertEqual(Node.DIRECTORY, node.kind) 
     120        self.assertEqual(Node.DIRECTORY, node.node_type) 
    121121        self.assertEqual(14, node.rev) 
    122122        self.assertEqual(1133340423L, node.last_modified) 
    123123        node = self.repos.get_node('/trunk/README.txt') 
    124124        self.assertEqual('README.txt', node.name) 
    125125        self.assertEqual('/trunk/README.txt', node.path) 
    126         self.assertEqual(Node.FILE, node.kind) 
     126        self.assertEqual(Node.FILE, node.node_type) 
    127127        self.assertEqual(3, node.rev) 
    128128        self.assertEqual(1112361898, node.last_modified) 
    129129 
     
    131131        node = self.repos.get_node('/trunk', 1) 
    132132        self.assertEqual('trunk', node.name) 
    133133        self.assertEqual('/trunk', node.path) 
    134         self.assertEqual(Node.DIRECTORY, node.kind) 
     134        self.assertEqual(Node.DIRECTORY, node.node_type) 
    135135        self.assertEqual(1, node.rev) 
    136136        self.assertEqual(1112349652, node.last_modified) 
    137137        node = self.repos.get_node('/trunk/README.txt', 2) 
    138138        self.assertEqual('README.txt', node.name) 
    139139        self.assertEqual('/trunk/README.txt', node.path) 
    140         self.assertEqual(Node.FILE, node.kind) 
     140        self.assertEqual(Node.FILE, node.node_type) 
    141141        self.assertEqual(2, node.rev) 
    142142        self.assertEqual(1112361138, node.last_modified) 
    143143 
     
    370370        node = self.repos.get_node('/dir1') 
    371371        self.assertEqual('dir1', node.name) 
    372372        self.assertEqual('/dir1', node.path) 
    373         self.assertEqual(Node.DIRECTORY, node.kind) 
     373        self.assertEqual(Node.DIRECTORY, node.node_type) 
    374374        self.assertEqual(5, node.rev) 
    375375        self.assertEqual(1112372739, node.last_modified) 
    376376        node = self.repos.get_node('/README.txt') 
    377377        self.assertEqual('README.txt', node.name) 
    378378        self.assertEqual('/README.txt', node.path) 
    379         self.assertEqual(Node.FILE, node.kind) 
     379        self.assertEqual(Node.FILE, node.node_type) 
    380380        self.assertEqual(3, node.rev) 
    381381        self.assertEqual(1112361898, node.last_modified) 
    382382 
     
    384384        node = self.repos.get_node('/dir1', 4) 
    385385        self.assertEqual('dir1', node.name) 
    386386        self.assertEqual('/dir1', node.path) 
    387         self.assertEqual(Node.DIRECTORY, node.kind) 
     387        self.assertEqual(Node.DIRECTORY, node.node_type) 
    388388        self.assertEqual(4, node.rev) 
    389389        self.assertEqual(1112370155, node.last_modified) 
    390390        node = self.repos.get_node('/README.txt', 2) 
    391391        self.assertEqual('README.txt', node.name) 
    392392        self.assertEqual('/README.txt', node.path) 
    393         self.assertEqual(Node.FILE, node.kind) 
     393        self.assertEqual(Node.FILE, node.node_type) 
    394394        self.assertEqual(2, node.rev) 
    395395        self.assertEqual(1112361138, node.last_modified) 
    396396 
  • trac/versioncontrol/tests/cache.py

     
    6666        self.assertEquals(('0', 41000, '', ''), cursor.fetchone()) 
    6767        self.assertEquals(('1', 42000, 'joe', 'Import'), cursor.fetchone()) 
    6868        self.assertEquals(None, cursor.fetchone()) 
    69         cursor.execute("SELECT rev,path,kind,change,base_path,base_rev " 
     69        cursor.execute("SELECT rev,path,node_type,change_type,base_path,base_rev " 
    7070                       "FROM node_change") 
    7171        self.assertEquals(('1', 'trunk', 'D', 'A', None, None), 
    7272                          cursor.fetchone()) 
     
    8080                       "VALUES (0,41000,'','')") 
    8181        cursor.execute("INSERT INTO revision (rev,time,author,message) " 
    8282                       "VALUES (1,42000,'joe','Import')") 
    83         cursor.executemany("INSERT INTO node_change (rev,path,kind,change," 
     83        cursor.executemany("INSERT INTO node_change (rev,path,node_type,change_type," 
    8484                           "base_path,base_rev) VALUES ('1',%s,%s,%s,%s,%s)", 
    8585                           [('trunk', 'D', 'A', None, None), 
    8686                            ('trunk/README', 'F', 'A', None, None)]) 
     
    9999        cursor.execute("SELECT time,author,message FROM revision WHERE rev='2'") 
    100100        self.assertEquals((42042, 'joe', 'Update'), cursor.fetchone()) 
    101101        self.assertEquals(None, cursor.fetchone()) 
    102         cursor.execute("SELECT path,kind,change,base_path,base_rev " 
     102        cursor.execute("SELECT path,node_type,change_type,base_path,base_rev " 
    103103                       "FROM node_change WHERE rev='2'") 
    104104        self.assertEquals(('trunk/README', 'F', 'E', 'trunk/README', '1'), 
    105105                          cursor.fetchone()) 
     
    111111                       "VALUES (0,41000,'','')") 
    112112        cursor.execute("INSERT INTO revision (rev,time,author,message) " 
    113113                       "VALUES (1,42000,'joe','Import')") 
    114         cursor.executemany("INSERT INTO node_change (rev,path,kind,change," 
     114        cursor.executemany("INSERT INTO node_change (rev,path,node_type,change_type," 
    115115                           "base_path,base_rev) VALUES ('1',%s,%s,%s,%s,%s)", 
    116116                           [('trunk', 'D', 'A', None, None), 
    117117                            ('trunk/README', 'F', 'A', None, None)]) 
  • trac/versioncontrol/web_ui/changeset.py

     
    181181 
    182182        edits = [] 
    183183        idx = 0 
    184         for path, kind, change, base_path, base_rev in chgset.get_changes(): 
    185             info = {'change': change} 
     184        for path, node_type, change_type, base_path, base_rev in chgset.get_changes(): 
     185            info = {'change': change_type} 
    186186            if base_path: 
    187187                info['path.old'] = base_path 
    188188                info['rev.old'] = base_rev 
     
    193193                info['rev.new'] = chgset.rev 
    194194                info['browser_href.new'] = self.env.href.browser(path, 
    195195                                                                 rev=chgset.rev) 
    196             if change in (Changeset.COPY, Changeset.EDIT, Changeset.MOVE): 
    197                 edits.append((idx, path, kind, base_path, base_rev)) 
     196            if change_type in (Changeset.COPY, Changeset.EDIT, Changeset.MOVE): 
     197                edits.append((idx, path, node_type, base_path, base_rev)) 
    198198            req.hdf['changeset.changes.%d' % idx] = info 
    199199            idx += 1 
    200200 
     
    202202                             in self.config.get('browser', 'hide_properties', 
    203203                                                'svk:merge').split(',')] 
    204204 
    205         for idx, path, kind, base_path, base_rev in edits: 
     205        for idx, path, node_type, base_path, base_rev in edits: 
    206206            old_node = repos.get_node(base_path or path, base_rev) 
    207207            new_node = repos.get_node(path, chgset.rev) 
    208208 
     
    224224                        del changed_props[k] 
    225225                req.hdf['changeset.changes.%d.props' % idx] = changed_props 
    226226 
    227             if kind == Node.DIRECTORY: 
     227            if node_type == Node.DIRECTORY: 
    228228                continue 
    229229 
    230230            # Content changes 
     
    272272                        'filename=Changeset%s.diff' % req.args.get('rev')) 
    273273        req.end_headers() 
    274274 
    275         for path, kind, change, base_path, base_rev in chgset.get_changes(): 
    276             if change == Changeset.ADD: 
     275        for path, node_type, change_type, base_path, base_rev in chgset.get_changes(): 
     276            if change_type == Changeset.ADD: 
    277277                old_node = None 
    278278            else: 
    279279                old_node = repos.get_node(base_path or path, base_rev) 
    280             if change == Changeset.DELETE: 
     280            if change_type == Changeset.DELETE: 
    281281                new_node = None 
    282282            else: 
    283283                new_node = repos.get_node(path, chgset.rev) 
     
    285285            # TODO: Property changes 
    286286 
    287287            # Content changes 
    288             if kind == 'dir': 
     288            if node_type == 'dir': 
    289289                continue 
    290290 
    291291            default_charset = self.config.get('trac', 'default_charset') 
     
    345345 
    346346        buf = StringIO() 
    347347        zipfile = ZipFile(buf, 'w', ZIP_DEFLATED) 
    348         for path, kind, change, base_path, base_rev in chgset.get_changes(): 
    349             if kind == Node.FILE and change != Changeset.DELETE: 
     348        for path, node_type, change_type, base_path, base_rev in chgset.get_changes(): 
     349            if node_type == Node.FILE and change_type != Changeset.DELETE: 
    350350                node = repos.get_node(path, chgset.rev) 
    351351                zipinfo = ZipInfo() 
    352352                zipinfo.filename = node.path 
     
    390390            return 
    391391        authzperm = SubversionAuthorizer(self.env, req.authname) 
    392392        db = self.env.get_db_cnx() 
    393         sql, args = query_to_sql(db, query, 'message||author') 
     393        query_fields = ['message', 'author'] 
     394        sql_seq = [] 
     395        args = [] 
     396        for f in query_fields: 
     397            subsql, subarg = query_to_sql(db, query, f) 
     398            sql_seq.append(subsql)  
     399            args += subarg 
     400        sql = ' OR '.join(sql_seq) 
    394401        cursor = db.cursor() 
    395402        cursor.execute("SELECT rev,time,author,message " 
    396403                       "FROM revision WHERE " + sql, args) 
  • trac/versioncontrol/cache.py

     
    1818from trac.versioncontrol import Changeset, Node, Repository, Authorizer 
    1919 
    2020 
    21 _kindmap = {'D': Node.DIRECTORY, 'F': Node.FILE} 
    22 _actionmap = {'A': Changeset.ADD, 'C': Changeset.COPY, 
     21_node_typemap = {'D': Node.DIRECTORY, 'F': Node.FILE} 
     22_change_typemap = {'A': Changeset.ADD, 'C': Changeset.COPY, 
    2323              'D': Changeset.DELETE, 'E': Changeset.EDIT, 
    2424              'M': Changeset.MOVE} 
    2525 
     
    6464            authz = self.repos.authz 
    6565            self.repos.authz = Authorizer() # remove permission checking 
    6666 
    67             kindmap = dict(zip(_kindmap.values(), _kindmap.keys())) 
    68             actionmap = dict(zip(_actionmap.values(), _actionmap.keys())) 
     67            node_typemap = dict(zip(_node_typemap.values(), _node_typemap.keys())) 
     68            change_typemap = dict(zip(_change_typemap.values(), _change_typemap.keys())) 
    6969            self.log.info("Syncing with repository (%s to %s)" 
    7070                          % (youngest_stored, self.repos.youngest_rev)) 
    7171            if youngest_stored: 
     
    7878                               "VALUES (%s,%s,%s,%s)", (str(current_rev), 
    7979                               changeset.date, changeset.author, 
    8080                               changeset.message)) 
    81                 for path,kind,action,base_path,base_rev in changeset.get_changes(): 
     81                for path,node_type,change_type,base_path,base_rev in changeset.get_changes(): 
    8282                    self.log.debug("Caching node change in [%s]: %s" 
    83                                    % (current_rev, (path, kind, action, 
     83                                   % (current_rev, (path, node_type, change_type, 
    8484                                      base_path, base_rev))) 
    85                     kind = kindmap[kind] 
    86                     action = actionmap[action] 
    87                     cursor.execute("INSERT INTO node_change (rev,path,kind," 
    88                                    "change,base_path,base_rev) " 
     85                    node_type = node_typemap[node_type] 
     86                    change_type = change_typemap[change_type] 
     87                    cursor.execute("INSERT INTO node_change (rev,path,node_type," 
     88                                   "change_type,base_path,base_rev) " 
    8989                                   "VALUES (%s,%s,%s,%s,%s,%s)", 
    90                                    (str(current_rev), path, kind, action, 
     90                                   (str(current_rev), path, node_type, change_type, 
    9191                                   base_path, base_rev)) 
    9292                current_rev = self.repos.next_rev(current_rev) 
    9393            self.db.commit() 
     
    141141 
    142142    def get_changes(self): 
    143143        cursor = self.db.cursor() 
    144         cursor.execute("SELECT path,kind,change,base_path,base_rev " 
     144        cursor.execute("SELECT path,node_type,change_type,base_path,base_rev " 
    145145                       "FROM node_change WHERE rev=%s " 
    146146                       "ORDER BY path", (self.rev,)) 
    147         for path, kind, change, base_path, base_rev in cursor: 
     147        for path, node_type, change_type, base_path, base_rev in cursor: 
    148148            if not self.authz.has_permission(path): 
    149149                # FIXME: what about the base_path? 
    150150                continue 
    151             kind = _kindmap[kind] 
    152             change = _actionmap[change] 
    153             yield path, kind, change, base_path, base_rev 
     151            node_type = _node_typemap[node_type] 
     152            change_type = _change_typemap[change_type] 
     153            yield path, node_type, change_type, base_path, base_rev 
  • trac/upgrades/db17.py

     
     1from trac.db import Table, Column, Index, DatabaseManager 
     2 
     3def do_upgrade(env, ver, cursor): 
     4    cursor.execute("CREATE TEMP TABLE node_change_old AS SELECT * FROM node_change") 
     5    cursor.execute("DROP TABLE node_change") 
     6 
     7    db = env.get_db_cnx() 
     8    node_change_table = Table('node_change', key=('rev', 'path', 'change_type'))[ 
     9        Column('rev'), 
     10        Column('path'), 
     11        Column('node_type', size=1), 
     12        Column('change_type', size=1), 
     13        Column('base_path'), 
     14        Column('base_rev'), 
     15        Index(['rev'])] 
     16    db_backend, _ = DatabaseManager(env)._get_connector() 
     17    for stmt in db_backend.to_sql(node_change_table): 
     18        cursor.execute(stmt) 
     19 
     20    cursor.execute("INSERT INTO node_change (rev,path,node_type,change_type,base_path,base_rev) " 
     21                   "SELECT rev,path,kind,change,base_path,base_rev " 
     22                   "FROM node_change_old") 
  • 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 sids and 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() 
  • templates/changeset.cs

     
    7070 </div> 
    7171</form><?cs /if ?> 
    7272 
    73 <?cs def:node_change(item,cl,kind) ?><?cs  
     73<?cs def:node_change(item,cl,node_type) ?><?cs  
    7474  set:ndiffs = len(item.diff) ?><?cs 
    7575  set:nprops = len(item.props) ?> 
    7676  <div class="<?cs var:cl ?>"></div><?cs  
     
    8181   <a title="Show entry in browser" href="<?cs 
    8282     var:item.browser_href.new ?>"><?cs var:item.path.new ?></a><?cs 
    8383  /if ?> 
    84   <span class="comment">(<?cs var:kind ?>)</span><?cs 
     84  <span class="comment">(<?cs var:node_type ?>)</span><?cs 
    8585  if:item.path.old && item.change == 'copy' || item.change == 'move' ?> 
    86    <small><em>(<?cs var:kind ?> from <a href="<?cs 
     86   <small><em>(<?cs var:node_type ?> from <a href="<?cs 
    8787    var:item.browser_href.old ?>" title="Show original file (rev. <?cs 
    8888    var:item.rev.old ?>)"><?cs var:item.path.old ?></a>)</em></small><?cs 
    8989  /if ?><?cs