PostgresqlPatch: pgsql_patch_02.diff

File pgsql_patch_02.diff, 53.1 kB (added by brad, 7 years ago)

now with 'trac-admin' initenv working

  • scripts/trac-admin

    old new  
    9292            return 0 
    9393        return 1 
    9494         
    95     def env_create(self): 
     95    def env_create(self, db_str): 
    9696        try: 
    97             self.__env = trac.Environment.Environment (self.envname, create=1
     97            self.__env = trac.Environment.Environment (self.envname, 1, db_str
    9898            return self.__env 
    9999        except Exception, e: 
    100100            print 'Failed to create environment.', e 
     
    481481        dt = trac.siteconfig.__default_templates_dir__ 
    482482        prompt = 'Templates directory [%s]> ' % dt 
    483483        returnvals.append(raw_input(prompt) or dt) 
     484        print 
     485        print " Please enter the database in which you wish to store Trac data." 
     486        print " Default is 'sqlite', but others are supported:" 
     487        print " 'sqlite' - SQLite       http://www.sqlite.org" 
     488        print " 'pgsql'  - PostgreSQL   http://www.postgresql.org" 
     489        print 
     490        ddb = "sqlite" 
     491        prompt =  'database system [%s]> ' % ddb 
     492        dbms = raw_input(prompt) or ddb 
     493        returnvals.append(dbms) 
     494         
     495        # PostgreSQL - additional questions 
     496        if dbms == "pgsql": 
     497            print 
     498            print " Please enter the host of your PostgreSQL database." 
     499            print " Default is 'localhost'" 
     500            print 
     501            host = "localhost" 
     502            prompt = "PostgreSQL host [%s]> " % host 
     503            returnvals.append(raw_input(prompt) or host) 
     504             
     505            print 
     506            print " Please enter the port of your PostgreSQL database." 
     507            print " Default is '5432'" 
     508            print 
     509            port = "5432" 
     510            prompt = "PostgreSQL port [%s]> " % port 
     511            returnvals.append(raw_input(prompt) or port) 
     512             
     513            print 
     514            print " Please enter the name of your PostgreSQL database." 
     515            print " Default is 'trac'" 
     516            print " Note: This database should not exist, as trac-admin will" \ 
     517                  " attempt to create it." 
     518            print 
     519            name = "trac" 
     520            prompt = "PostgreSQL host [%s]> " % name 
     521            returnvals.append(raw_input(prompt) or name) 
     522             
     523            print 
     524            print " Please enter the user of your PostgreSQL database." 
     525            print " Default is 'trac'" 
     526            print 
     527            user = "trac" 
     528            prompt = "PostgreSQL host [%s]> " % user 
     529            returnvals.append(raw_input(prompt) or user) 
     530             
     531            print 
     532            print " Please enter the password of your PostgreSQL database." 
     533            print " Default is 'trac'" 
     534            print 
     535            password = "trac" 
     536            prompt = "PostgreSQL host [%s]> " % password 
     537            returnvals.append(raw_input(prompt) or password) 
     538             
    484539        return returnvals 
    485540          
    486541    def do_initenv(self, line): 
     
    491546        project_name = None 
    492547        repository_dir = None 
    493548        templates_dir = None 
     549        db_str = None 
    494550        if len(arg) == 1: 
    495551            returnvals = self.get_initenv_args() 
    496552            project_name = returnvals[0] 
    497553            repository_dir = returnvals[1] 
    498554            templates_dir = returnvals[2] 
    499         elif len(arg)!= 3: 
     555            db_str = returnvals[3] 
     556        elif len(arg) < 4: 
    500557            print 'Wrong number of arguments to initenv %d' % len(arg) 
    501558            return 
    502559        else: 
    503560            project_name = arg[0] 
    504561            repository_dir = arg[1] 
    505562            templates_dir = arg[2] 
     563            db_str = arg[3] 
     564         
     565        # postgres-specific stuff 
     566        if db_str.lower() == "pgsql": 
     567            if len(arg) == 1: 
     568                host = returnvals[4] 
     569                port = returnvals[5] 
     570                database = returnvals[6] 
     571                user = returnvals[7] 
     572                password = returnvals[8] 
     573            elif len(arg) != 9: 
     574                print 'Wrong number of arguments to initenv %d' % len(arg) 
     575                print 'For PostgreSQL (after pgsql): <host> <port> <database>' \ 
     576                      ' <user> <password>' 
     577                return 
     578            else: 
     579                host = arg[4] 
     580                port = arg[5] 
     581                database = arg[6] 
     582                user = arg[7] 
     583                password = arg[8] 
     584            db_str = "pgsql:\"\",host='%s:%s',database='%s',user='%s'," \ 
     585                     "password='%s'" \ 
     586                     % (host, port, database, user, password) 
     587            createdb_str = "createdb --host=%s --port=%s --owner=%s " \ 
     588                           "--username=%s %s\n" \ 
     589                           % (host, port, user, user, database) 
     590            print createdb_str 
     591            try: 
     592                # TODO: this is not cross-platform. 
     593                # for Windows, look at win32pipe.popen() 
     594                os.popen(createdb_str) 
     595            except Exception, e: 
     596                print "Error creating PostgreSQL database: %s" % e 
     597                print "command: %s" % createdb_str 
     598         
    506599        from svn import util, repos, core 
    507600        core.apr_initialize() 
    508601        pool = core.svn_pool_create(None) 
     
    521614            return 
    522615        try: 
    523616            print 'Creating and Initializing Project' 
    524             self.env_create(
     617            self.env_create(db_str
    525618            cnx = self.__env.get_db_cnx() 
    526619            print ' Inserting default data' 
    527620            self.__env.insert_default_data() 
     
    685778        data = data.replace("'", "''") # Escape ' for safe SQL 
    686779        f.close() 
    687780         
    688         sql = ("INSERT INTO wiki('version','name','time','author','ipnr','text') " 
    689                " SELECT 1+ifnull(max(version),0),'%(title)s','%(time)s','%(author)s'," 
    690                "   '%(ipnr)s','%(text)s' FROM wiki WHERE name='%(title)s'"  
     781        sql = ("INSERT INTO wiki(version,name,time,author,ipnr,text) " 
     782               " SELECT 1+COALESCE(max(version),0),'%(title)s','%(time)s'," 
     783               "'%(author)s','%(ipnr)s','%(text)s' " 
     784               "FROM wiki WHERE name='%(title)s'"  
    691785               % {'title':title, 
    692786                  'time':int(time.time()), 
    693787                  'author':'trac', 
  • trac/core.py

    old new  
    11# -*- coding: iso8859-1 -*- 
    22# 
    33# Copyright (C) 2003, 2004 Edgewall Software 
    4 # Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com> 
     4# Copyright (C) 2003, 2004 Jonas Borgstr?m <jonas@edgewall.com> 
    55# 
    66# Trac is free software; you can redistribute it and/or 
    77# modify it under the terms of the GNU General Public License as 
     
    1717# along with this program; if not, write to the Free Software 
    1818# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
    1919# 
    20 # Author: Jonas Borgström <jonas@edgewall.com> 
     20# Author: Jonas Borgstr?m <jonas@edgewall.com> 
    2121 
    2222import os 
    2323import re 
  • trac/db_default.py

    old new  
    127127         name            text PRIMARY KEY, 
    128128         owner           text 
    129129); 
     130 
    130131CREATE TABLE milestone ( 
    131          id              integer PRIMARY KEY, 
    132132         name            text, 
    133          time            integer, 
    134          descr           text, 
     133         due             integer, -- Due date/time 
     134         completed       integer, -- Completed date/time 
     135         description     text, 
    135136         UNIQUE(name) 
    136137); 
    137138CREATE TABLE version ( 
     
    175176CREATE INDEX session_idx        ON session(sid,var_name); 
    176177""" 
    177178 
     179schema_pgsql = """ 
     180CREATE TABLE revision ( 
     181        rev             integer, 
     182        time            integer, 
     183        author          text, 
     184        message         text, 
     185        CONSTRAINT revision_pkey PRIMARY KEY (rev) 
     186) WITHOUT OIDS; 
     187 
     188CREATE TABLE node_change ( 
     189        rev             integer, 
     190        name            text, 
     191        change          char(1), 
     192        CONSTRAINT node_change_pkey PRIMARY KEY (rev, name, change) 
     193) WITHOUT OIDS; 
     194 
     195CREATE TABLE auth_cookie ( 
     196        cookie          text, 
     197        name            text, 
     198        ipnr            text, 
     199        time            integer, 
     200        CONSTRAINT auth_cookie_pkey PRIMARY KEY(cookie, name, ipnr) 
     201) WITHOUT OIDS; 
     202 
     203CREATE TABLE enum ( 
     204        type            text, 
     205        name            text, 
     206        value           text, 
     207        CONSTRAINT enum_pkey PRIMARY KEY(name,type) 
     208) WITHOUT OIDS; 
     209 
     210CREATE TABLE system ( 
     211        name            text, 
     212        value           text, 
     213        CONSTRAINT system_pkey PRIMARY KEY(name) 
     214) WITHOUT OIDS; 
     215 
     216CREATE TABLE lock ( 
     217        name            text, 
     218        owner           text, 
     219        ipnr            text, 
     220        time            integer, 
     221        CONSTRAINT lock_pkey PRIMARY KEY(name) 
     222) WITHOUT OIDS; 
     223 
     224CREATE TABLE ticket ( 
     225        id              integer, 
     226        time            integer,        -- the time it was created 
     227        changetime      integer, 
     228        component       text, 
     229        severity        text, 
     230        priority        text, 
     231        owner           text,           -- who is this ticket assigned to 
     232        reporter        text, 
     233        cc              text,           -- email addresses to notify 
     234        url             text,           -- url related to this ticket 
     235        version         text,           --  
     236        milestone       text,           --  
     237        status          text, 
     238        resolution      text, 
     239        summary         text,           -- one-line summary 
     240        description     text,           -- problem description (long) 
     241        keywords        text, 
     242        CONSTRAINT ticket_pkey PRIMARY KEY(id) 
     243) WITHOUT OIDS; 
     244 
     245CREATE TABLE ticket_change ( 
     246        ticket          integer, 
     247        time            integer, 
     248        author          text, 
     249        field           text, 
     250        oldvalue        text, 
     251        newvalue        text, 
     252        CONSTRAINT ticket_change_pkey PRIMARY KEY(ticket, time, field) 
     253) WITHOUT OIDS; 
     254 
     255CREATE TABLE ticket_custom ( 
     256       ticket               integer, 
     257       name             text, 
     258       value            text, 
     259       CONSTRAINT ticket_custom_pkey PRIMARY KEY(ticket,name) 
     260) WITHOUT OIDS; 
     261 
     262CREATE TABLE report ( 
     263        id              integer, 
     264        author          text, 
     265        title           text, 
     266        sql             text, 
     267        description     text, 
     268        CONSTRAINT report_pkey PRIMARY KEY(id) 
     269) WITHOUT OIDS; 
     270 
     271CREATE TABLE permission ( 
     272        username        text,           --  
     273        action          text,           -- allowable activity 
     274        CONSTRAINT permission_pkey PRIMARY KEY(username,action) 
     275) WITHOUT OIDS; 
     276 
     277CREATE TABLE component ( 
     278         name            text, 
     279         owner           text, 
     280         CONSTRAINT component_pkey PRIMARY KEY(name) 
     281) WITHOUT OIDS; 
     282 
     283CREATE TABLE milestone ( 
     284         name            text, 
     285         due             integer, -- Due date/time 
     286         completed       integer, -- Completed date/time 
     287         description     text, 
     288         CONSTRAINT milestone_pkey PRIMARY KEY(name) 
     289) WITHOUT OIDS; 
     290 
     291CREATE TABLE version ( 
     292         name            text, 
     293         time            integer, 
     294         CONSTRAINT version_pkey PRIMARY KEY(name) 
     295) WITHOUT OIDS; 
     296 
     297CREATE TABLE wiki ( 
     298         name            text, 
     299         version         integer, 
     300         time            integer, 
     301         author          text, 
     302         ipnr            text, 
     303         text            text, 
     304         comment         text, 
     305         readonly        integer, 
     306         CONSTRAINT wiki_pkey PRIMARY KEY(name,version) 
     307) WITHOUT OIDS; 
     308 
     309CREATE TABLE attachment ( 
     310         type            text, 
     311         id              text, 
     312         filename        text, 
     313         size            integer, 
     314         time            integer, 
     315         description     text, 
     316         author          text, 
     317         ipnr            text, 
     318         CONSTRAINT attachment_pkey PRIMARY KEY(type,id,filename) 
     319) WITHOUT OIDS; 
     320 
     321CREATE TABLE session ( 
     322         sid             text, 
     323         username        text, 
     324         var_name        text, 
     325         var_value       text, 
     326         CONSTRAINT session_pkey PRIMARY KEY(sid,var_name) 
     327) WITHOUT OIDS; 
     328 
     329""" 
     330 
    178331## 
    179332## Default Reports 
    180333## 
     
    351504               (('component1', 'somebody'), 
    352505                ('component2', 'somebody'))), 
    353506           ('milestone', 
    354              ('name', 'time'), 
    355                (('', 0),  
    356                 ('milestone1', 0), 
    357                 ('milestone2', 0), 
    358                 ('milestone3', 0), 
    359                 ('milestone4', 0))), 
     507             ('name','due','completed'), 
     508               (('milestone1',0,0), 
     509                ('milestone2',0,0), 
     510                ('milestone3',0,0), 
     511                ('milestone4',0,0))), 
    360512           ('version', 
    361513             ('name', 'time'), 
    362514               (('', 0), 
     
    414566 (('trac', 'htdocs_location', '/trac/'), 
    415567  ('trac', 'repository_dir', '/var/svn/myrep'), 
    416568  ('trac', 'templates_dir', '/usr/lib/trac/templates'), 
    417   ('trac', 'database', 'sqlite:db/trac.db'), 
     569  ('trac', 'database', 'sqlite:"db/trac.db",timeout=10000'), 
    418570  ('trac', 'default_charset', 'iso-8859-15'), 
    419571  ('logging', 'log_type', 'none'), 
    420572  ('logging', 'log_file', 'trac.log'), 
  • trac/Milestone.py

    old new  
    157157        cursor = self.db.cursor() 
    158158        self.log.debug("Creating new milestone '%s'" % name) 
    159159        cursor.execute("INSERT INTO milestone (id, name, due, description) " 
    160                        "VALUES (NULL, %s, %d, %s)", name, date, description) 
     160                       "VALUES (NULL, %s, %s, %s)", name, date, description) 
    161161        self.db.commit() 
    162162        self.req.redirect(self.env.href.milestone(name)) 
    163163 
     
    208208        groups = [] 
    209209        if by in ['status', 'resolution', 'severity', 'priority']: 
    210210            cursor.execute("SELECT name FROM enum WHERE type = %s " 
    211                            "AND IFNULL(name,'') != '' ORDER BY value", by) 
     211                           "AND COALESCE(name,'') != '' ORDER BY value", by) 
    212212        elif by in ['component', 'milestone', 'version']: 
    213213            cursor.execute("SELECT name FROM %s " 
    214                            "WHERE IFNULL(name,'') != '' ORDER BY name" % by) 
     214                           "WHERE COALESCE(name,'') != '' ORDER BY name" % by) 
    215215        elif by == 'owner': 
    216216            cursor.execute("SELECT DISTINCT owner AS name FROM ticket " 
    217217                           "ORDER BY owner") 
  • trac/Query.py

    old new  
    11# -*- coding: iso8859-1 -*- 
    22# 
    33# Copyright (C) 2003, 2004 Edgewall Software 
    4 # Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com> 
     4# Copyright (C) 2003, 2004 Jonas Borgstr?m <jonas@edgewall.com> 
    55# 
    66# Trac is free software; you can redistribute it and/or 
    77# modify it under the terms of the GNU General Public License as 
     
    1717# along with this program; if not, write to the Free Software 
    1818# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
    1919# 
    20 # Author: Jonas Borgström <jonas@edgewall.com> 
     20# Author: Jonas Borgstr?m <jonas@edgewall.com> 
    2121 
    2222from __future__ import nested_scopes 
    2323from time import gmtime, localtime, strftime 
     
    154154        sql.append("\nFROM ticket") 
    155155        for k in [k for k in cols if k in custom_fields]: 
    156156           sql.append("\n  LEFT OUTER JOIN ticket_custom AS %s ON " \ 
    157                       "(id=%s.ticket AND %s.name='%s')" % (k, k, k, k)) 
     157                      "(id=%s.ticket AND %s.name='%s') tc" % (k, k, k, k)) 
    158158 
    159159        for col in [c for c in ['status', 'resolution', 'priority', 'severity'] 
    160160                    if c == self.order or c == self.group]: 
    161161            sql.append("\n  LEFT OUTER JOIN (SELECT name AS %s_name, " \ 
    162162                                            "value AS %s_value " \ 
    163                                             "FROM enum WHERE type='%s')" \ 
     163                                            "FROM enum WHERE type='%s') e" \ 
    164164                       " ON %s_name=%s" % (col, col, col, col, col)) 
    165165        for col in [c for c in ['milestone', 'version'] 
    166166                    if c == self.order or c == self.group]: 
    167167            sql.append("\n  LEFT OUTER JOIN (SELECT name AS %s_name, " \ 
    168                                             "time AS %s_time FROM %s)" \ 
     168                                            "time AS %s_time FROM %s) other" \ 
    169169                       " ON %s_name=%s" % (col, col, col, col, col)) 
    170170 
    171171        def get_constraint_sql(name, value, mode, neg): 
    172172            value = sql_escape(value[len(mode and '!' or '' + mode):]) 
    173173            if mode == '~' and value: 
    174                 return "IFNULL(%s,'') %sLIKE '%%%s%%'" % ( 
     174                return "COALESCE(%s,'') %sLIKE '%%%s%%'" % ( 
    175175                       name, neg and 'NOT ' or '', value) 
    176176            elif mode == '^' and value: 
    177                 return "IFNULL(%s,'') %sLIKE '%s%%'" % ( 
     177                return "COALESCE(%s,'') %sLIKE '%s%%'" % ( 
    178178                       name, neg and 'NOT ' or '', value) 
    179179            elif mode == '$' and value: 
    180                 return "IFNULL(%s,'') %sLIKE '%%%s'" % ( 
     180                return "COALESCE(%s,'') %sLIKE '%%%s'" % ( 
    181181                       name, neg and 'NOT ' or '', value) 
    182182            elif mode == '': 
    183                 return "IFNULL(%s,'')%s='%s'" % (name, neg and '!' or '', value) 
     183                return "COALESCE(%s,'')%s='%s'" % (name, neg and '!' or '', value) 
    184184 
    185185        clauses = [] 
    186186        for k, v in self.constraints.items(): 
     
    194194            # Special case for exact matches on multiple values 
    195195            if not mode and len(v) > 1: 
    196196                inlist = ",".join(["'" + sql_escape(val[neg and 1 or 0:]) + "'" for val in v]) 
    197                 clauses.append("IFNULL(%s,'') %sIN (%s)" % (k, neg and "NOT " or "", inlist)) 
     197                clauses.append("COALESCE(%s,'') %sIN (%s)" % (k, neg and "NOT " or "", inlist)) 
    198198            elif len(v) > 1: 
    199199                constraint_sql = [get_constraint_sql(k, val, mode, neg) for val in v] 
    200200                if neg: 
     
    214214            order_cols.insert(0, (self.group, self.groupdesc)) 
    215215        for col, desc in order_cols: 
    216216            if desc: 
    217                 sql.append("IFNULL(%s,'')='' DESC," % col) 
     217                sql.append("COALESCE(%s,'')='' DESC," % col) 
    218218            else: 
    219                 sql.append("IFNULL(%s,'')=''," % col) 
     219                sql.append("COALESCE(%s,'')=''," % col) 
    220220            if col in ['status', 'resolution', 'priority', 'severity']: 
    221221                if desc: 
    222222                    sql.append("%s_value DESC" % col) 
     
    224224                    sql.append("%s_value" % col) 
    225225            elif col in ['milestone', 'version']: 
    226226                if desc: 
    227                     sql.append("IFNULL(%s_time,0)=0 DESC,%s_time DESC,%s DESC" 
     227                    sql.append("COALESCE(%s_time,0)=0 DESC,%s_time DESC,%s DESC" 
    228228                               % (col, col, col)) 
    229229                else: 
    230                     sql.append("IFNULL(%s_time,0)=0,%s_time,%s" 
     230                    sql.append("COALESCE(%s_time,0)=0,%s_time,%s" 
    231231                               % (col, col, col)) 
    232232            else: 
    233233                if desc: 
  • trac/Report.py

    old new  
    11# -*- coding: iso8859-1 -*- 
    22# 
    33# Copyright (C) 2003, 2004 Edgewall Software 
    4 # Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com> 
     4# Copyright (C) 2003, 2004 Jonas Borgstr?m <jonas@edgewall.com> 
    55# 
    66# Trac is free software; you can redistribute it and/or 
    77# modify it under the terms of the GNU General Public License as 
     
    1717# along with this program; if not, write to the Free Software 
    1818# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
    1919# 
    20 # Author: Jonas Borgström <jonas@edgewall.com> 
     20# Author: Jonas Borgstr?m <jonas@edgewall.com> 
    2121 
    2222import os 
    2323import re 
     
    9595            sql = 'SELECT id AS report, title FROM report ORDER BY report' 
    9696            description = 'This is a list of reports available.' 
    9797        else: 
    98             cursor.execute('SELECT title, sql, description from report ' 
    99                            ' WHERE id=%s', id) 
     98            sql = "SELECT title, sql, description from report " \ 
     99                  "WHERE id=%s" % id 
     100            cursor.execute(sql) 
    100101            row = cursor.fetchone() 
    101102            if not row: 
    102103                raise util.TracError('Report %d does not exist.' % id, 
     
    133134        sql = self.sql_sub_vars(sql, args) 
    134135        if not sql: 
    135136            raise util.TracError('Report %s has no SQL query.' % id) 
     137        self.env.log.debug("sql: %s" % sql) 
    136138        cursor.execute(sql) 
    137139 
    138140        if sql.find('__group__') == -1: 
     
    140142 
    141143        # FIXME: fetchall should probably not be used. 
    142144        info = cursor.fetchall() 
    143         cols = cursor.rs.col_defs 
     145        cols = cursor.description 
     146         
    144147        # Escape the values so that they are safe to have as html parameters 
    145148        #info = map(lambda row: map(lambda x: escape(x), row), info) 
    146149 
  • trac/sync.py

    old new  
    11# -*- coding: iso8859-1 -*- 
    22# 
    33# Copyright (C) 2003, 2004 Edgewall Software 
    4 # Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com> 
     4# Copyright (C) 2003, 2004 Jonas Borgstr?m <jonas@edgewall.com> 
    55# 
    66# Trac is free software; you can redistribute it and/or 
    77# modify it under the terms of the GNU General Public License as 
     
    1717# along with this program; if not, write to the Free Software 
    1818# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
    1919# 
    20 # Author: Jonas Borgström <jonas@edgewall.com> 
     20# Author: Jonas Borgstr?m <jonas@edgewall.com> 
    2121 
    2222from svn import fs, util, delta, repos, core 
     23from util import sql_escape 
    2324 
    2425import posixpath 
    2526 
     
    3536              (util.SVN_VER_MAJOR, util.SVN_VER_MINOR, util.SVN_VER_MICRO) 
    3637 
    3738    cursor = db.cursor() 
    38     cursor.execute('SELECT ifnull(max(rev), 0) FROM revision') 
    39     youngest_stored =  int(cursor.fetchone()[0]) 
     39    cursor.execute('SELECT max(rev) FROM revision') 
     40    row = cursor.fetchone() 
     41    youngest_stored = 0 
     42    if row and row[0] != None: 
     43        youngest_stored =  int(row[0]) 
     44     
    4045    max_rev = fs.youngest_rev(fs_ptr, pool) 
    4146    num = max_rev - youngest_stored 
    4247    offset = youngest_stored + 1 
     
    5257 
    5358        date = util.svn_time_from_cstring(date, subpool) / 1000000 
    5459         
    55         cursor.execute ('INSERT INTO revision (rev, time, author, message) ' 
    56                         'VALUES (%s, %s, %s, %s)', rev + offset, date, 
    57                         author, message) 
     60        sql = "INSERT INTO revision (rev, time, author, message) " \ 
     61              "VALUES (%s, %s, '%s', '%s')" \ 
     62              % ( rev + offset, date, sql_escape(author), sql_escape(message) ) 
     63        cursor.execute (sql) 
    5864        insert_change (subpool, fs_ptr, rev + offset, cursor) 
    5965        core.svn_pool_clear(subpool) 
    6066 
  • trac/Session.py

    old new  
    2121 
    2222import sys 
    2323import time 
    24 from util import hex_entropy, add_dict_to_hdf, TracError 
     24from util import hex_entropy, add_dict_to_hdf, TracError, sql_escape 
    2525 
    2626class Session: 
    2727    """Basic session handling and per-session storage.""" 
     
    104104        self.sid = sid 
    105105        curs = self.db.cursor() 
    106106        curs.execute("SELECT username,var_name,var_value FROM session" 
    107                     " WHERE sid=%s", self.sid) 
     107                    " WHERE sid='%s'" % self.sid) 
    108108        rows = curs.fetchall() 
    109109        if (not rows                              # No session data yet 
    110110            or rows[0][0] == 'anonymous'          # Anon session 
     
    136136        if currval == None: 
    137137            if key == 'last_visit': # Limit the frequency of purging 
    138138                self.purge_expired()  
    139             curs.execute('INSERT INTO session(sid,username,var_name,var_value)' 
    140                          ' VALUES(%s,%s,%s,%s)', 
    141                          self.sid, self.req.authname, key, val) 
     139            sql = "INSERT INTO session(sid,username,var_name,var_value) " \ 
     140                  "VALUES('%s','%s','%s','%s')" \ 
     141                  % ( 
     142                     sql_escape(self.sid), sql_escape(self.req.authname), 
     143                     sql_escape(key), sql_escape(val) 
     144                    ) 
     145            curs.execute(sql) 
    142146        else: 
    143             curs.execute('UPDATE session SET username=%s,var_value=%s' 
    144                          ' WHERE sid=%s AND var_name=%s', 
    145                          self.req.authname, val, self.sid, key) 
     147            sql = "UPDATE session SET username='%s',var_value='%s' " \ 
     148                  "WHERE sid='%s' AND var_name='%s'" \ 
     149                  % (sql_escape(self.req.authname), 
     150                     sql_escape(str(val)), 
     151                     sql_escape(self.sid), 
     152                     sql_escape(key)  
     153                    ) 
     154            curs.execute(sql) 
    146155        self.db.commit() 
    147156        self.vars[key] = val 
    148157 
  • trac/Roadmap.py

    old new  
    4444        if show == 'all': 
    4545            icalhref += '&show=all' 
    4646            query = "SELECT name,due,completed,description FROM milestone " \ 
    47                     "WHERE IFNULL(name,'')!='' " \ 
    48                     "ORDER BY IFNULL(due,0)=0,due,name" 
     47                    "WHERE COALESCE(name,'')!='' " \ 
     48                    "ORDER BY COALESCE(due,0)=0,due,name" 
    4949        else: 
    5050            self.req.hdf.setValue('roadmap.showall', '1') 
    5151            query = "SELECT name,due,completed,description FROM milestone " \ 
    52                     "WHERE IFNULL(name,'')!='' " \ 
    53                     "AND IFNULL(completed,0)=0 " \ 
    54                     "ORDER BY IFNULL(due,0)=0,due,name" 
     52                    "WHERE COALESCE(name,'')!='' " \ 
     53                    "AND COALESCE(completed,0)=0 " \ 
     54                    "ORDER BY COALESCE(due,0)=0,due,name" 
    5555 
    5656        if self.req.authname and self.req.authname != 'anonymous': 
    5757            icalhref += '&user=' + self.req.authname 
  • trac/auth.py

    old new  
    11# -*- coding: iso8859-1 -*- 
    22# 
    33# Copyright (C) 2003, 2004 Edgewall Software 
    4 # Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com> 
     4# Copyright (C) 2003, 2004 Jonas Borgstr?m <jonas@edgewall.com> 
    55# 
    66# Trac is free software; you can redistribute it and/or 
    77# modify it under the terms of the GNU General Public License as 
     
    1717# along with this program; if not, write to the Free Software 
    1818# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
    1919# 
    20 # Author: Jonas Borgström <jonas@edgewall.com> 
     20# Author: Jonas Borgstr?m <jonas@edgewall.com> 
    2121 
    2222import time 
    2323import util 
     
    3030        if req.incookie.has_key('trac_auth'): 
    3131            cursor = db.cursor () 
    3232            cookie = req.incookie['trac_auth'].value 
    33             cursor.execute ("SELECT name FROM auth_cookie " 
    34                             "WHERE cookie=%s AND ipnr=%s" 
    35                             ,cookie, req.remote_addr) 
     33            sql = "SELECT name FROM auth_cookie " \ 
     34                  "WHERE cookie='%s' AND ipnr='%s'" \ 
     35                  % ( cookie, req.remote_addr ) 
     36            cursor.execute(sql) 
    3637            if cursor.rowcount >= 1: 
    3738                self.authname = cursor.fetchone()[0] 
    3839 
    3940    def login(self, req): 
    4041        cursor = self.db.cursor () 
    4142        cookie = util.hex_entropy() 
    42         cursor.execute ("INSERT INTO auth_cookie (cookie, name, ipnr, time)" + 
    43                         "VALUES (%s, %s, %s, %d)", 
    44                         cookie, req.remote_user, req.remote_addr, 
    45                         int(time.time())); 
     43        sql = "INSERT INTO auth_cookie (cookie, name, ipnr, time)" \ 
     44              "VALUES ('%s', '%s', '%s', %d)" \ 
     45              % ( cookie, req.remote_user, req.remote_addr, int(time.time()) ) 
     46        cursor.execute(sql); 
     47         
     48#        cursor.execute ("INSERT INTO auth_cookie (cookie, name, ipnr, time)" + 
     49#                        "VALUES (%s, %s, %s, %d)", 
     50#                        cookie, req.remote_user, req.remote_addr, 
     51#                        int(time.time())); 
    4652        self.db.commit () 
    4753        self.authname = req.remote_user 
    4854        req.outcookie['trac_auth'] = cookie 
  • trac/Wiki.py

    old new  
    11# -*- coding: iso8859-1 -*- 
    22# 
    33# Copyright (C) 2003, 2004 Edgewall Software 
    4 # Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com> 
     4# Copyright (C) 2003, 2004 Jonas Borgstr?m <jonas@edgewall.com> 
    55# 
    66# Trac is free software; you can redistribute it and/or 
    77# modify it under the terms of the GNU General Public License as 
     
    1717# along with this program; if not, write to the Free Software 
    1818# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
    1919# 
    20 # Author: Jonas Borgström <jonas@edgewall.com> 
     20# Author: Jonas Borgstr?m <jonas@edgewall.com> 
    2121 
    2222import os 
    2323import time 
     
    2727 
    2828import perm 
    2929from Module import Module 
    30 from util import escape, TracError, get_reporter_id 
     30from util import escape, TracError, get_reporter_id, sql_escape 
    3131from Session import Session 
    3232from WikiFormatter import * 
    3333 
     
    5656        self.name = name 
    5757        self.perm = perm 
    5858        cursor = self.db.cursor () 
     59        sql = "SELECT version, text, readonly FROM wiki " 
    5960        if version: 
    60             cursor.execute ('SELECT version, text, readonly FROM wiki ' 
    61                             'WHERE name=%s AND version=%s', 
    62                             name, version) 
     61            sql += "WHERE name='%s' AND version=%s" % (name, version) 
    6362        else: 
    64             cursor.execute ('SELECT version, text, readonly FROM wiki ' 
    65                             'WHERE name=%s ORDER BY version DESC LIMIT 1', name
     63            sql += "WHERE name='%s' ORDER BY version DESC LIMIT 1" % name 
     64        cursor.execute(sql
    6665        row = cursor.fetchone() 
    6766        if row: 
    6867            self.new = 0 
     
    102101            self.db.commit () 
    103102            self.old_readonly = self.readonly 
    104103        elif self.modified: 
    105             cursor.execute ('INSERT INTO WIKI ' 
    106                             '(name, version, time, author, ipnr, text, comment, readonly) ' 
    107                             'VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', 
    108                             self.name, self.version, int(time.time()), 
    109                             author, remote_addr, self.text, comment, self.readonly) 
     104            sql = "INSERT INTO WIKI " \ 
     105                  "(name, version, time, author, ipnr, text, comment, readonly) " \ 
     106                  "VALUES ('%s', %s, %s, '%s', '%s', '%s', '%s', %s)" \ 
     107                  % ( 
     108                     sql_escape(self.name), self.version, int(time.time()), 
     109                     sql_escape(author), sql_escape(remote_addr),  
     110                     sql_escape(self.text), sql_escape(comment), self.readonly 
     111                    ) 
     112            cursor.execute (sql) 
    110113            self.db.commit () 
    111114            self.old_readonly = self.readonly 
    112115            self.modified = 0 
     
    124127        This information is used to present a changelog/history for a given page 
    125128        """ 
    126129        cursor = self.db.cursor () 
    127         cursor.execute ('SELECT version, time, author, comment, ipnr FROM wiki ' 
    128                         'WHERE name=%s ORDER BY version DESC', pagename) 
     130        sql = "SELECT version, time, author, comment, ipnr FROM wiki " \ 
     131              "WHERE name='%s' ORDER BY version DESC" % pagename 
     132        cursor.execute (sql) 
    129133        i = 0 
    130134        while 1: 
    131135            row = cursor.fetchone() 
     
    155159           self.req.redirect(self.env.href.wiki(pagename, version, 1)) 
    156160 
    157161        cursor = self.db.cursor() 
    158         cursor.execute ('SELECT text,author,comment,time FROM wiki ' 
    159                         'WHERE name=%s AND (version=%s or version=%s)' 
    160                         'ORDER BY version ASC', pagename, version - 1, version) 
     162        sql = "SELECT text,author,comment,time FROM wiki " \ 
     163              "WHERE name='%s' AND (version=%s or version=%s) " \ 
     164              "ORDER BY version ASC" % (pagename, version - 1, version) 
     165        cursor.execute (sql) 
    161166        res = cursor.fetchall() 
    162167        if not res: 
    163168            raise TracError('Version %d of page "%s" not found.' 
    164169                            % (version, pagename), 
    165170                            'Page Not Found') 
    166  
     171         
    167172        if len(res) == 1: 
    168173            old = '' 
    169174        else: 
  • trac/Environment.py

    old new  
    11# -*- coding: iso8859-1 -*- 
    22# 
    33# Copyright (C) 2003, 2004 Edgewall Software 
    4 # Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com> 
     4# Copyright (C) 2003, 2004 Jonas Borgstr?m <jonas@edgewall.com> 
    55# 
    66# Trac is free software; you can redistribute it and/or 
    77# modify it under the terms of the GNU General Public License as 
     
    1717# along with this program; if not, write to the Free Software 
    1818# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
    1919# 
    20 # Author: Jonas Borgström <jonas@edgewall.com> 
     20# Author: Jonas Borgstr?m <jonas@edgewall.com> 
    2121# 
    2222# Todo: Move backup and upgrade from db.py 
    2323# 
     
    5050     * Project specific templates and wiki macros. 
    5151     * wiki and ticket attachments. 
    5252    """ 
    53     def __init__(self, path, create=0): 
     53    def __init__(self, path, create=0, db_str=None): 
    5454        self.path = path 
    5555        if create: 
    56             self.create(
     56            self.create(db_str
    5757        self.verify() 
    5858        self.load_config() 
    5959        try: # Use binary I/O on Windows 
     
    7171        assert fd.read(26) == 'Trac Environment Version 1' 
    7272        fd.close() 
    7373 
    74     def get_db_cnx(self): 
    75         db_str = self.get_config('trac', 'database', 'sqlite:db/trac.db') 
    76         assert db_str[:7] == 'sqlite:' 
    77         db_name = os.path.join(self.path, db_str[7:]) 
    78         if not os.access(db_name, os.F_OK): 
    79             raise EnvironmentError, 'Database "%s" not found.' % db_name 
     74    def get_db_cnx(self, check_exists=1): 
     75        db_str = self.get_config('trac',  
     76                                 'database',  
     77                                 'sqlite:"db/trac.db",timeout=10000') 
     78                                  
     79        pos = db_str.find(':') 
     80        if pos == -1: 
     81            raise EnvironmentError, 'Connection param must be of form ' \ 
     82                  '(db_module_name):(db_connect_params), the value "%s ' \ 
     83                  'does not match' % db_str 
    8084         
    81         directory = os.path.dirname(db_name) 
    82         if not os.access(db_name, os.R_OK + os.W_OK) or \ 
    83                not os.access(directory, os.R_OK + os.W_OK): 
    84             raise EnvironmentError, \ 
    85                   'The web server user requires read _and_ write permission\n' \ 
    86                   'to the database %s and the directory this file is located in.' % db_name 
    87         return sqlite.connect(os.path.join(self.path, db_str[7:]), 
    88                               timeout=10000) 
     85        module_name = db_str[:pos] 
     86        connect_params = db_str[pos+1:].split(',') 
     87         
     88        # following is very crude code for parsing the arguments in the 
     89        # db_connect_params string 
     90        kargs = {} 
     91        arg_list = [] 
     92        for x in connect_params: 
     93            pos1 = x.find('=') 
     94            pos2 = x.find('"') 
     95            pos3 = x.find("'") 
     96            if pos1 > -1: 
     97                if pos2 > -1 and pos2 < pos1: 
     98                    arg_list.append(eval(x)) 
     99                elif pos3 > -1 and pos3 < pos1: 
     100                    arg_list.append(eval(x)) 
     101                else: 
     102                    name = x[:pos1].strip() 
     103                    value = eval(x[pos1+1:].strip()) 
     104                    kargs[name] = value 
     105            else: 
     106                # self.log.debug("Environment - get_db_cnx - x: %s" % x) 
     107                arg_list.append(eval(x)) 
     108        args = tuple(arg_list) 
     109         
     110        import_str = 'import %s' % module_name 
    89111 
    90     def create(self): 
     112        # since Trac has a slightly closer relationship with sqlite than 
     113        # other db's, there's a special case setup here so that when the 
     114        # path to the sqlite db is specified, its relative to TRAC_ENV 
     115        if module_name == 'sqlite': 
     116            db_name = os.path.join(self.path, args[0]) 
     117            args = list(args) 
     118            args[0] = '%s' % db_name 
     119            args = tuple(args) 
     120            if check_exists == 1 and not os.access(db_name, os.F_OK): 
     121                raise EnvironmentError, 'Database "%s" not found.' % db_name 
     122         
     123            directory = os.path.dirname(db_name) 
     124            if (check_exists == 1 and not os.access(db_name, os.R_OK + os.W_OK)) \ 
     125                or not os.access(directory, os.R_OK + os.W_OK): 
     126                raise EnvironmentError, \ 
     127                      'The web server user requires read _and_ write permission\n' \ 
     128                      'to the database %s and the directory this file is located in.' % db_name 
     129         
     130        # handle weird import for PostgreSQL module 
     131        if module_name.lower() == 'pgsql': 
     132            import_str = "from pyPgSQL import PgSQL" 
     133            module_name = "PgSQL" 
     134             
     135        exec import_str 
     136        m = eval(module_name) 
     137 
     138#        self.log.debug("Connecting to database module [%s] with: args=%s, " \ 
     139#                       "kargs=%s" % (module_name, str(args), str(kargs))) 
     140        conn = m.connect(*args, **kargs) 
     141        return conn 
     142 
     143 
     144    def create(self, db_str=None): 
    91145        def _create_file(fname, data=None): 
    92146            fd = open(fname, 'w') 
    93147            if data: fd.write(data) 
     
    128182""") 
    129183        # Create default database 
    130184        os.mkdir(os.path.join(self.path, 'db')) 
    131         cnx = sqlite.connect(os.path.join(self.path, 'db', 'trac.db')) 
     185        self.load_config() 
     186        self.setup_default_config() 
     187        if db_str: 
     188            self.cfg.set('trac', 'database', db_str) 
     189        self.save_config() 
     190        cnx = self.get_db_cnx(check_exists=0) 
    132191        cursor = cnx.cursor() 
    133         cursor.execute(db_default.schema) 
     192 
     193        # get right db schema based on db_str 
     194        dbschema = db_default.schema 
     195        if db_str: 
     196            pos = db_str.find(':') 
     197            if pos == -1: 
     198                raise EnvironmentError, 'Connection param must be of form ' \ 
     199                      '(db_module_name):(db_connect_params), the value "%s ' \ 
     200                      'does not match' % db_str 
     201            module_name = db_str[:pos] 
     202            if module_name.lower() == "pgsql": 
     203                dbschema = db_default.schema_pgsql 
     204        cursor.execute(dbschema) 
    134205        cnx.commit() 
    135206 
    136207    def insert_default_data(self): 
     
    138209            if v == None: 
    139210                return 'NULL' 
    140211            else: 
    141                 return '"%s"' % v 
     212                prepped = v 
     213                if type(v) == str: 
     214                    prepped = prepped.replace("'", "''") 
     215                return "'%s'" % prepped 
    142216        cnx = self.get_db_cnx() 
    143217        cursor = cnx.cursor() 
    144218         
     
    149223                values = ','.join(map(prep_value, row)) 
    150224                sql = "INSERT INTO %s (%s) VALUES(%s);" % (table, cols, values) 
    151225                cursor.execute(sql) 
     226        cnx.commit() 
     227 
     228    def setup_default_config(self): 
    152229        for s,n,v in db_default.default_config: 
    153230            if not self.cfg.has_section(s): 
    154231                self.cfg.add_section(s) 
    155232            self.cfg.set(s, n, v) 
    156         self.save_config() 
    157         cnx.commit() 
    158233 
    159234    def get_version(self): 
    160235        cnx = self.get_db_cnx() 
     
    216291 
    217292    def get_attachments(self, cnx, type, id): 
    218293        cursor = cnx.cursor() 
    219         cursor.execute('SELECT filename,description,type,size,time,author,ipnr ' 
    220                        'FROM attachment ' 
    221                        'WHERE type=%s AND id=%s ORDER BY time', type, id) 
     294        sql = "SELECT filename,description,type,size,time,author,ipnr " \ 
     295              "FROM attachment " \ 
     296              "WHERE type='%s' AND id='%s' ORDER BY time" % (type, id) 
     297        cursor.execute(sql) 
    222298        return cursor.fetchall() 
    223299     
    224300    def get_attachments_hdf(self, cnx, type, id, hdf, prefix): 
  • trac/Ticket.py

    old new  
    11# -*- coding: iso8859-1 -*- 
    22# 
    33# Copyright (C) 2003, 2004 Edgewall Software 
    4 # Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com> 
     4# Copyright (C) 2003, 2004 Jonas Borgstr?m <jonas@edgewall.com> 
    55# 
    66# Trac is free software; you can redistribute it and/or 
    77# modify it under the terms of the GNU General Public License as 
     
    1717# along with this program; if not, write to the Free Software 
    1818# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
    1919# 
    20 # Author: Jonas Borgström <jonas@edgewall.com> 
     20# Author: Jonas Borgstr?m <jonas@edgewall.com> 
    2121 
    2222import re 
    2323import time 
     
    7373            self[Ticket.std_fields[i]] = row[i] or '' 
    7474 
    7575        cursor = db.cursor () 
    76         cursor.execute('SELECT name,value FROM ticket_custom WHERE ticket=%i', id) 
     76        sql = "SELECT name,value FROM ticket_custom WHERE ticket=%s" % id 
     77        cursor.execute(sql) 
    7778        rows = cursor.fetchall() 
    7879        if rows: 
    7980            for r in rows: 
     
    134135        # is updated accordingly. (#623). 
    135136        if self['status'] == 'new' and self._old.has_key('component') and \ 
    136137               not self._old.has_key('owner'): 
    137             cursor.execute('SELECT owner FROM component ' 
    138                            'WHERE name=%s', self._old['component']) 
     138            sql = "SELECT owner FROM component " \ 
     139                  "WHERE name=%s" % self._old['component'] 
     140            cursor.execute(sql) 
    139141            old_owner = cursor.fetchone()[0] 
    140142            if self['owner'] == old_owner: 
    141                 cursor.execute('SELECT owner FROM component ' 
    142                                'WHERE name=%s', self['component']) 
     143                sql = "SELECT owner FROM component " \ 
     144                      "WHERE name=%s" % self['component'] 
     145                cursor.execute(sql) 
    143146                self['owner'] = cursor.fetchone()[0] 
    144147            
    145148 
    146149        for name in self._old.keys(): 
    147150            if name[:7] == 'custom_': 
    148151                fname = name[7:] 
    149                 cursor.execute('REPLACE INTO ticket_custom(ticket,name,value)' 
    150                                ' VALUES(%s, %s, %s)', id, fname, self[name]) 
     152                sql = "REPLACE INTO ticket_custom(ticket,name,value) " \ 
     153                      "VALUES(%s, '%s', '%s')" \ 
     154                      % (id, util.sql_escape(fname), util.sql_escape(self[name])) 
     155                cursor.execute(sql) 
    151156            else: 
    152157                fname = name 
    153                 cursor.execute ('UPDATE ticket SET %s=%s WHERE id=%s', 
    154                                 fname, self[name], id) 
    155  
    156             cursor.execute ('INSERT INTO ticket_change ' 
    157                             '(ticket, time, author, field, oldvalue, newvalue) ' 
    158                             'VALUES (%s, %s, %s, %s, %s, %s)', 
    159                             id, when, author, fname, self._old[name], self[name]) 
     158                sql = "UPDATE ticket SET %s='%s' WHERE id=%s" \ 
     159                      % (fname, util.sql_escape(self[name]), id) 
     160                cursor.execute (sql) 
     161             
     162            sql = "INSERT INTO ticket_change " \ 
     163                  "(ticket, time, author, field, oldvalue, newvalue) " \ 
     164                  "VALUES (%s, %s, '%s', '%s', '%s', '%s')" \ 
     165                  % ( 
     166                     id, when, util.sql_escape(author), util.sql_escape(fname), 
     167                     util.sql_escape(self._old[name]), util.sql_escape(self[name]) 
     168                    ) 
     169            cursor.execute (sql) 
    160170        if comment: 
    161             cursor.execute ('INSERT INTO ticket_change ' 
    162                             '(ticket,time,author,field,oldvalue,newvalue) ' 
    163                             "VALUES (%s, %s, %s, 'comment', '', %s)", 
    164                             id, when, author, comment) 
     171            sql = "INSERT INTO ticket_change " \ 
     172                  "(ticket,time,author,field,oldvalue,newvalue) " \ 
     173                  "VALUES (%s, %s, '%s', 'comment', '', '%s')" \ 
     174                  % ( id, when, util.sql_escape(author), util.sql_escape(comment) ) 
     175            cursor.execute (sql) 
    165176 
    166         cursor.execute ('UPDATE ticket SET changetime=%s WHERE id=%s', when, id) 
     177        sql = "UPDATE ticket SET changetime=%s WHERE id=%s" % (when, id) 
     178        cursor.execute (sql) 
    167179        db.commit() 
    168180        self._forget_changes() 
    169181 
    170182    def get_changelog(self, db, when=0): 
    171183        """Returns the changelog as a list of dictionaries""" 
    172184        cursor = db.cursor() 
     185        when_clause = "" 
    173186        if when: 
    174             cursor.execute('SELECT time, author, field, oldvalue, newvalue ' 
    175                            'FROM ticket_change ' 
    176                            'WHERE ticket=%s AND time=%s' 
    177                            'UNION ' 
    178                            'SELECT time, author, "attachment", null, filename ' 
    179                            'FROM attachment ' 
    180                            'WHERE id=%s AND time=%s ' 
    181                            'ORDER BY time',  self['id'], when, self['id'], when) 
    182         else: 
    183             cursor.execute('SELECT time, author, field, oldvalue, newvalue ' 
    184                            'FROM ticket_change ' 
    185                            'WHERE ticket=%s ' 
    186                            'UNION ' 
    187                            'SELECT time, author, "attachment", null,filename ' 
    188                            'FROM attachment ' 
    189                            'WHERE id = %s ' 
    190                            'ORDER BY time', self['id'],  self['id']) 
     187            when_clause = " AND time=%s " % when 
     188        sql = "SELECT time, author, field, oldvalue, newvalue " \ 
     189              "FROM ticket_change " \ 
     190              "WHERE ticket=%s %s " \ 
     191              "UNION " \ 
     192              "SELECT time, author, 'attachment', null, filename " \ 
     193              "FROM attachment " \ 
     194              "WHERE id=%s %s " \ 
     195              "ORDER BY time" \ 
     196              % (self['id'], when_clause, self['id'], when_clause) 
     197        # raise util.TracError(sql) 
     198        cursor.execute(sql) 
    191199        log = [] 
    192200        while 1: 
    193201            row = cursor.fetchone() 
  • contrib/tracdb-sqlite2pg.py

    old new  
     1#!/usr/bin/env python 
     2 
     3""" 
     4Import a Trac database from sqlite to postgresql. 
     5 
     6Requires:  Trac from http://trac.edgewall.com/ 
     7           Python 2.3 from http://www.python.org/ 
     8           PostgreSQL from http://www.postgresql.org/ 
     9           PySQLITE ? 
     10           others? 
     11            
     12Author: Brad Anderson <brad@dsource.org> 
     13 
     14 
     15""" 
     16 
     17import sys, os 
     18import sqlite 
     19import pgdb 
     20from trac.util import sql_escape 
     21 
     22tables=['revision','node_change', 'auth_cookie', 'enum', 'system', 'lock',  
     23        'ticket', 'ticket_change', 'ticket_custom', 'report', 'permission', 
     24        'component', 'milestone', 'version', 'attachment', 'session', 'wiki', 
     25        'forums', 'topics', 'posts'] 
     26 
     27# for debugging, one table at a time 
     28# tables=['wiki'] 
     29 
     30 
     31## simple field translation mapping.  if string not in 
     32## mapping, just return string, otherwise return value 
     33#class FieldTranslator(dict): 
     34#    def __getitem__(self, item): 
     35#        if not dict.has_key(self, item): 
     36#            return item 
     37#             
     38#        return dict.__getitem__(self, item) 
     39 
     40 
     41 
     42def convert(_env, _host, _db, _user, _password, _clean): 
     43     
     44     
     45    # init PostgreSQL environment 
     46    print "PostgreSQL('%s':'%s':'%s'): connecting..." \ 
     47                      % (_host, _db, _user) 
     48    pg_con = pgdb.connect(host=_host, database=_db,  
     49                          user=_user, password=_password) 
     50    pg_cur = pg_con.cursor() 
     51 
     52    # init Trac environment 
     53    print "Trac SQLite('%s'): connecting..." % (_env) 
     54    trac_con = sqlite.connect(os.path.join(_env, "db/trac.db"), 
     55                              timeout=10000) 
     56    trac_cur = trac_con.cursor() 
     57    print 
     58 
     59#    fieldtypes = FieldTranslator() 
     60#    fieldtypes['0'] = 'int' 
     61#    fieldtypes['6'] = 'text' 
     62     
     63    # loop thru tables, converting them 
     64    for t in tables: 
     65        print 
     66        print "Converting Table: '%s'" % t 
     67 
     68        # clear out existing table 
     69#        if _clean == 1: 
     70#            pg_cur.execute("truncate table %s;" % t) 
     71        pg_cur.execute("truncate table %s;" % t) 
     72         
     73        # get table info 
     74        sql = "SELECT * FROM %s" % t 
     75        trac_cur.execute(sql) 
     76        cols = trac_cur.rs.col_defs 
     77        counter = 0 
     78         
     79        # loop thru rows, moving data from sqlite to pgsql 
     80        while 1: 
     81            row = trac_cur.fetchone() 
     82            counter += 1 
     83            if not row: 
     84                break 
     85            flds="" 
     86            vals="" 
     87            for c in cols: 
     88                field = c[0] 
     89                type = c[1] 
     90                value = row[field] 
     91                if value != None: 
     92                    flds += ", %s" % field 
     93                    if type in [6]: 
     94                        value = "'%s'" % sql_escape(value) 
     95                    vals += ", %s" % value 
     96            flds = flds[2:] 
     97            vals = vals[2:] 
     98            sql  = "INSERT INTO %s " % t 
     99            sql += "(%s) " % flds 
     100            sql += "VALUES (%s);" % vals 
     101 
     102            pg_cur.execute(sql) 
     103            pg_con.commit() 
     104             
     105            if counter % 100 == 0: 
     106                print "%s rows" % counter 
     107         
     108    trac_cur.close() 
     109    trac_con.close() 
     110    pg_cur.close() 
     111    pg_con.close() 
     112    print 
     113         
     114     
     115def usage(): 
     116    print "tracdb-sqlite2pg - Converts a Trac database from sqlite to " \ 
     117          "postgresql." 
     118    print 
     119    print "This script is designed to transfer an existing Trac SQLite " 
     120    print "database to an existing Trac PosgreSQL database.  The two "  
     121    print "databases should be of the same version.  Check in the 'system' " 
     122    print "table in each database to verify.  This script runs on version 8 " 
     123    print "and above.  This is for Trac pre 0.9 (revision 1169 and higher)." 
     124    print 
     125    print "Note: you can make a Trac PosgreSQL database with trac-admin " 
     126    print "(the version that accompanies this script)" 
     127    print 
     128    print "THIS WILL DESTROY ALL DATA IN THE POSTGRESQL DATABASE !! " 
     129    print 
     130    print 
     131    print "Usage: tracdb-sqlite2pg.py [options]" 
     132    print 
     133    print "Available Options:" 
     134    print "  -t  | --tracenv /path/to/trac/env - full path to Trac environment" 
     135    print "  -h  | --host <pgsql hostname>     - PostgreSQL hostname" 
     136    print "  -db | --database <pgsql database> - PostgreSQL database name" 
     137    print "  -u  | --user <pgsql username>     - PostgreSQL username" 
     138    print "  -p  | --passwd <pgsql password>   - PostgreSQL password" 
     139#    print "  -c  | --clean                     - clean out PG database " \ 
     140#          "before converting. (recommended)" 
     141    print "  --help | help                     - this help info" 
     142    print 
     143    print "Additional configuration options can be defined directly in the " \ 
     144          "script." 
     145    print 
     146    sys.exit(0) 
     147 
     148def main(): 
     149    global TRAC_ENV, PG_HOST, PG_DB, PG_USER, PG_PASSWORD, PG_CLEAN 
     150    if len (sys.argv) > 1: 
     151        if sys.argv[1] in ['--help','help'] or len(sys.argv) < 4: 
     152            usage() 
     153        iter = 1 
     154        while iter < len(sys.argv): 
     155            if sys.argv[iter] in ['-t', '--tracenv'] and iter+1 < len(sys.argv): 
     156                TRAC_ENV = sys.argv[iter+1] 
     157                iter = iter + 1 
     158            elif sys.argv[iter] in ['-h', '--host'] and iter+1 < len(sys.argv): 
     159                PG_HOST = sys.argv[iter+1] 
     160                iter = iter + 1 
     161            elif sys.argv[iter] in ['-db', '--database'] and \ 
     162                    iter+1 < len(sys.argv): 
     163                PG_DB = sys.argv[iter+1] 
     164                iter = iter + 1 
     165            elif sys.argv[iter] in ['-u', '--user'] and iter+1 < len(sys.argv): 
     166                PG_USER = sys.argv[iter+1] 
     167                iter = iter + 1 
     168            elif sys.argv[iter] in ['-p', '--passwd'] and \ 
     169                    iter+1 < len(sys.argv): 
     170                PG_PASSWORD = sys.argv[iter+1] 
     171                iter = iter + 1 
     172#            elif sys.argv[iter] in ['-c', '--clean']: 
     173#                PG_CLEAN = 1 
     174            else: 
     175                print "Error: unknown parameter: " + sys.argv[iter] 
     176                sys.exit(0) 
     177            iter = iter + 1 
     178    else: 
     179        usage() 
     180         
     181    convert(TRAC_ENV, PG_HOST, PG_DB, PG_USER, PG_PASSWORD, PG_CLEAN) 
     182 
     183 
     184if __name__ == '__main__': 
     185    main()