PostgresqlPatch: pgsql_patch_13.diff

File pgsql_patch_13.diff, 34.3 kB (added by brad <brad@dsource.org>, 3 years ago)
  • trac/env.py

    old new  
    2222from __future__ import generators 
    2323 
    2424from trac import db, db_default, Logging, Mimeview, util 
     25from types import * 
    2526 
    2627import ConfigParser 
    2728import os 
     
    4445     * Project specific templates and wiki macros. 
    4546     * wiki and ticket attachments. 
    4647    """ 
    47     def __init__(self, path, create=0): 
     48    def __init__(self, path, create=0, db_str='sqlite:db/trac.db'): 
    4849        self.path = path 
    4950        if create: 
    50             self.create(
     51            self.create(db_str
    5152        self.verify() 
    5253        self.load_config() 
    5354        try: # Use binary I/O on Windows 
     
    8182        repos = SubversionRepository(repos_dir, authz, self.log) 
    8283        return CachedRepository(self.get_db_cnx(), repos, authz, self.log) 
    8384 
    84     def create(self): 
     85    def create(self, db_str): 
    8586        def _create_file(fname, data=None): 
    8687            fd = open(fname, 'w') 
    8788            if data: fd.write(data) 
     
    120121# Site CSS - Place custom CSS, including overriding styles here. 
    121122?> 
    122123""") 
    123         # Create default database 
    124         import sqlite 
    125         os.mkdir(os.path.join(self.path, 'db')) 
    126         cnx = sqlite.connect(os.path.join(self.path, 'db', 'trac.db')) 
    127         cursor = cnx.cursor() 
    128         cursor.execute(db_default.schema) 
    129         cnx.commit() 
     124        # set up the config file 
     125        self.load_config() 
     126        self.setup_default_config() 
     127        self.set_config('trac', 'database', db_str) 
     128        self.save_config() 
    130129 
     130        # Create default database by attempting to get connection 
     131        cnx = db.get_cnx(self, create=1) 
     132        cnx.close 
     133 
    131134    def insert_default_data(self): 
    132135        def prep_value(v): 
    133136            if v == None: 
    134137                return 'NULL' 
    135138            else: 
    136                 return '"%s"' % v 
     139                prepped = v 
     140                if type(v) is StringType: 
     141                    prepped = util.sql_escape(prepped) 
     142                return "'%s'" % prepped 
    137143        cnx = self.get_db_cnx() 
    138144        cursor = cnx.cursor() 
    139145         
     
    144150                values = ','.join(map(prep_value, row)) 
    145151                sql = "INSERT INTO %s (%s) VALUES(%s);" % (table, cols, values) 
    146152                cursor.execute(sql) 
     153        cnx.commit() 
     154 
     155    def setup_default_config(self): 
    147156        for s,n,v in db_default.default_config: 
    148157            if not self.cfg.has_section(s): 
    149158                self.cfg.add_section(s) 
    150159            self.cfg.set(s, n, v) 
    151160        self.save_config() 
    152         cnx.commit() 
    153161 
    154162    def get_version(self): 
    155163        cnx = self.get_db_cnx() 
  • trac/db_default.py

    old new  
    3737## Default data 
    3838## 
    3939 
    40 schema = """ 
    41 CREATE TABLE revision ( 
    42         rev             text PRIMARY KEY, 
    43         time            integer, 
    44         author          text, 
    45         message         text 
    46 ); 
    47 CREATE TABLE node_change ( 
    48         rev             text, 
    49         path            text, 
    50         kind            char(1), -- 'D' for directory, 'F' for file 
    51         change          char(1), 
    52         base_path       text, 
    53         base_rev        text, 
    54         UNIQUE(rev, path, change) 
    55 ); 
    56 CREATE TABLE auth_cookie ( 
    57         cookie          text, 
    58         name            text, 
    59         ipnr            text, 
    60         time            integer, 
    61         UNIQUE(cookie, name, ipnr) 
    62 ); 
    63 CREATE TABLE enum ( 
    64         type            text, 
    65         name            text, 
    66         value           text, 
    67         UNIQUE(name,type) 
    68 ); 
    69 CREATE TABLE system ( 
    70         name            text PRIMARY KEY, 
    71         value           text, 
    72         UNIQUE(name) 
    73 ); 
    74 CREATE TABLE ticket ( 
    75         id              integer PRIMARY KEY, 
    76         time            integer,        -- the time it was created 
    77         changetime      integer, 
    78         component       text, 
    79         severity        text, 
    80         priority        text, 
    81         owner           text,           -- who is this ticket assigned to 
    82         reporter        text, 
    83         cc              text,           -- email addresses to notify 
    84         url             text,           -- url related to this ticket 
    85         version         text,           --  
    86         milestone       text,           --  
    87         status          text, 
    88         resolution      text, 
    89         summary         text,           -- one-line summary 
    90         description     text,           -- problem description (long) 
    91         keywords        text 
    92 ); 
    93 CREATE TABLE ticket_change ( 
    94         ticket          integer, 
    95         time            integer, 
    96         author          text, 
    97         field           text, 
    98         oldvalue        text, 
    99         newvalue        text, 
    100         UNIQUE(ticket, time, field) 
    101 ); 
    102 CREATE TABLE ticket_custom ( 
    103        ticket               integer, 
    104        name             text, 
    105        value            text, 
    106        UNIQUE(ticket,name) 
    107 ); 
    108 CREATE TABLE report ( 
    109         id              integer PRIMARY KEY, 
    110         author          text, 
    111         title           text, 
    112         sql             text, 
    113         description     text 
    114 ); 
    115 CREATE TABLE permission ( 
    116         username        text,           --  
    117         action          text,           -- allowable activity 
    118         UNIQUE(username,action) 
    119 ); 
    120 CREATE TABLE component ( 
    121          name            text PRIMARY KEY, 
    122          owner           text 
    123 ); 
    124 CREATE TABLE milestone ( 
    125          name            text PRIMARY KEY, 
    126          due             integer, 
    127          completed       integer, 
    128          description     text 
    129 ); 
    130 CREATE TABLE version ( 
    131          name            text PRIMARY KEY, 
    132          time            integer 
    133 ); 
    134 CREATE TABLE wiki ( 
    135          name            text, 
    136          version         integer, 
    137          time            integer, 
    138          author          text, 
    139          ipnr            text, 
    140          text            text, 
    141          comment         text, 
    142          readonly        integer, 
    143          UNIQUE(name,version) 
    144 ); 
    145 CREATE TABLE attachment ( 
    146          type            text, 
    147          id              text, 
    148          filename        text, 
    149          size            integer, 
    150          time            integer, 
    151          description     text, 
    152          author          text, 
    153          ipnr            text, 
    154          UNIQUE(type,id,filename) 
    155 ); 
     40schema = ( 
     41('revision', ( 
     42    ('rev', 'text', '', 'u'), 
     43    ('time', 'int', '', ''), 
     44    ('author', 'text', '', ''), 
     45    ('message', 'text', '', ''))), 
     46('node_change', ( 
     47    ('rev', 'text', '', 'u'), 
     48    ('path', 'text', '', 'u'), 
     49    ('kind', 'char', '1', ''), 
     50    ('change', 'text', '1', 'u'), 
     51    ('base_path', 'text', '', ''), 
     52    ('base_rev', 'text', '', ''))), 
     53('auth_cookie', ( 
     54    ('cookie', 'text', '', 'u'), 
     55    ('name', 'text', '', 'u'), 
     56    ('ipnr', 'text', '', 'u'), 
     57    ('time', 'int', '', ''))), 
     58('enum', ( 
     59    ('type', 'text', '', 'u'), 
     60    ('name', 'text', '', 'u'), 
     61    ('value', 'text', '', ''))), 
     62('system', ( 
     63    ('name', 'text', '', 'u'), 
     64    ('value', 'text', '', ''))), 
     65('ticket', ( 
     66    ('id', 'auto', '', 'u'), 
     67    ('time', 'int', '', ''), 
     68    ('changetime', 'int', '', ''), 
     69    ('component', 'text', '', ''), 
     70    ('severity', 'text', '', ''), 
     71    ('priority', 'text', '', ''), 
     72    ('owner', 'text', '', ''), 
     73    ('reporter', 'text', '', ''), 
     74    ('cc', 'text', '', ''), 
     75    ('url', 'text', '', ''), 
     76    ('version', 'text', '', ''), 
     77    ('milestone', 'text', '', ''), 
     78    ('status', 'text', '', ''), 
     79    ('resolution', 'text', '', ''), 
     80    ('summary', 'text', '', ''), 
     81    ('description', 'text', '', ''), 
     82    ('keywords', 'text', '', ''))), 
     83('ticket_change', ( 
     84    ('ticket', 'int', '', 'u'), 
     85    ('time', 'int', '', 'u'), 
     86    ('author', 'text', '', ''), 
     87    ('field', 'text', '', 'u'), 
     88    ('oldvalue', 'text', '', ''), 
     89    ('newvalue', 'text', '', ''))), 
     90('ticket_custom', ( 
     91    ('ticket', 'int', '', 'u'), 
     92    ('name', 'text', '', 'u'), 
     93    ('value', 'text', '', ''))), 
     94('report', ( 
     95    ('id', 'auto', '', 'u'), 
     96    ('author', 'text', '', ''), 
     97    ('title', 'text', '', ''), 
     98    ('sql', 'text', '', ''), 
     99    ('description', 'text', '', ''))), 
     100('permission', ( 
     101    ('username', 'text', '', 'u'), 
     102    ('action', 'text', '', 'u'))), 
     103('component', ( 
     104    ('name', 'text', '', 'u'), 
     105    ('owner', 'text', '', ''))), 
     106('milestone',  ( 
     107    ('name', 'text', '', 'u'), 
     108    ('due', 'int', '', ''), 
     109    ('completed', 'int', '', ''), 
     110    ('description', 'text', '', ''))), 
     111('version', ( 
     112    ('name', 'text', '', 'u'), 
     113    ('time', 'int', '', ''))), 
     114('wiki', ( 
     115    ('name', 'text', '', 'u'), 
     116    ('version', 'int', '', 'u'), 
     117    ('time', 'int', '', ''), 
     118    ('author', 'text', '', ''), 
     119    ('ipnr', 'text', '', ''), 
     120    ('text', 'text', '', ''), 
     121    ('comment', 'text', '', ''), 
     122    ('readonly', 'int', '', ''))), 
     123('attachment', ( 
     124    ('type', 'text', '', 'u'), 
     125    ('id', 'text', '', 'u'), 
     126    ('filename', 'text', '', 'u'), 
     127    ('size', 'int', '', ''), 
     128    ('time', 'int', '', ''), 
     129    ('description', 'text', '', ''), 
     130    ('author', 'text', '', ''), 
     131    ('ipnr', 'text', '', ''))), 
     132('session', ( 
     133    ('sid', 'text', '', 'u'), 
     134    ('username', 'text', '', ''), 
     135    ('var_name', 'text', '', 'u'), 
     136    ('var_value', 'text', '', '')))) 
     137     
     138# TODO: do we need these, or will the u's above do? 
     139#CREATE INDEX node_change_idx    ON node_change(rev); 
     140#CREATE INDEX ticket_change_idx  ON ticket_change(ticket, time); 
     141#CREATE INDEX wiki_idx           ON wiki(name,version); 
     142#CREATE INDEX session_idx        ON session(sid,var_name); 
     143#""" 
    156144 
    157 CREATE TABLE session ( 
    158          sid             text, 
    159          username        text, 
    160          var_name        text, 
    161          var_value       text, 
    162          UNIQUE(sid,var_name) 
    163 ); 
    164145 
    165 CREATE INDEX node_change_idx    ON node_change(rev); 
    166 CREATE INDEX ticket_change_idx  ON ticket_change(ticket, time); 
    167 CREATE INDEX wiki_idx           ON wiki(name,version); 
    168 CREATE INDEX session_idx        ON session(sid,var_name); 
    169 """ 
    170146 
    171147## 
    172148## Default Reports 
     
    289265  FROM ticket t,enum p 
    290266  WHERE p.name=t.priority AND p.type='priority' 
    291267  ORDER BY (milestone IS NULL), milestone DESC, (status = 'closed'),  
    292         (CASE status WHEN 'closed' THEN modified ELSE (-1)*p.value END) DESC 
     268        (CASE status WHEN 'closed' THEN changetime ELSE (-1)*p.value END) DESC 
    293269"""), 
    294270#---------------------------------------------------------------------------- 
    295271('My Tickets', 
  • trac/scripts/admin.py

    old new  
    2828import cmd 
    2929import shlex 
    3030import StringIO 
     31import traceback 
    3132 
    3233from trac import perm, util 
    3334from trac.env import Environment 
     
    9596            return 0 
    9697        return 1 
    9798         
    98     def env_create(self): 
     99    def env_create(self, db_str): 
    99100        try: 
    100             self.__env = Environment(self.envname, create=1
     101            self.__env = Environment(self.envname, 1, db_str
    101102            return self.__env 
    102103        except Exception, e: 
    103104            print 'Failed to create environment.', e 
     105            print traceback.print_exc() 
    104106            sys.exit(1) 
    105107 
    106108    def db_open(self): 
     
    473475 
    474476    ## Initenv 
    475477    _help_initenv = [('initenv', 'Create and initialize a new environment interactively'), 
    476                      ('initenv <projectname> <repospath> <templatepath>', 
     478                     ('initenv <projectname> <repospath> <templatepath> <dbstr>', 
    477479                      'Create and initialize a new environment from arguments')] 
    478480 
    479481    def do_initdb(self, line): 
     
    506508        dt = trac.siteconfig.__default_templates_dir__ 
    507509        prompt = 'Templates directory [%s]> ' % dt 
    508510        returnvals.append(raw_input(prompt) or dt) 
     511        print 
     512        print ' Please specify the database connection string.' 
     513        print ' Default is for SQLite database.' 
     514        print ' Examples of current options:' 
     515        print "  SQLite     -  sqlite:db/trac.db" 
     516        print "  PostgreSQL -  pypgsql:host='localhost',port='5432',database='trac',user='trac',password='trac'" 
     517        print 
     518        db = 'sqlite:db/trac.db' 
     519        # db = "pypgsql:host='localhost',port='5432',database='trac',user='trac',password='trac'" 
     520        prompt = 'Database connection string [%s]> ' % db 
     521        returnvals.append(raw_input(prompt) or db) 
    509522        return returnvals 
    510523          
    511524    def do_initenv(self, line): 
     
    521534            project_name = returnvals[0] 
    522535            repository_dir = returnvals[1] 
    523536            templates_dir = returnvals[2] 
    524         elif len(arg)!= 3: 
     537            db_str = returnvals[3] 
     538        elif len(arg)!= 4: 
    525539            print 'Wrong number of arguments to initenv %d' % len(arg) 
    526540            return 
    527541        else: 
    528542            project_name = arg[0] 
    529543            repository_dir = arg[1] 
    530544            templates_dir = arg[2] 
     545            db_str = arg[3] 
    531546 
    532547        if not os.access(os.path.join(templates_dir, 'browser.cs'), os.F_OK) \ 
    533548           or not os.access(os.path.join(templates_dir, 'ticket.cs'), os.F_OK): 
     
    535550            return 
    536551        try: 
    537552            print 'Creating and Initializing Project' 
    538             self.env_create(
     553            self.env_create(db_str
    539554            cnx = self.__env.get_db_cnx() 
    540555            print ' Inserting default data' 
    541556            self.__env.insert_default_data() 
     
    560575 
    561576        except Exception, e: 
    562577            print 'Failed to initialize database.', e 
     578            print traceback.print_exc() 
    563579            sys.exit(2) 
    564580 
    565581 
  • trac/Search.py

    old new  
    136136                                'Search Error') 
    137137 
    138138        cursor = self.db.cursor () 
    139  
     139        union_fields = self.db.get_union_fields('search') 
     140         
    140141        q = [] 
    141142        if changeset: 
    142143            q.append("SELECT 1 as type, message AS title, message, author, " 
    143                      "'' AS keywords, rev AS data, time,0 AS ver " 
     144                     "'' AS keywords, %s AS data, time,0 AS ver " 
    144145                     "FROM revision WHERE %s OR %s" % 
    145                      (self.query_to_sql(query, 'message'), 
     146                     (union_fields['changeset'], 
     147                      self.query_to_sql(query, 'message'), 
    146148                      self.query_to_sql(query, 'author'))) 
    147149        if tickets: 
    148150            q.append("SELECT DISTINCT 2 as type, a.summary AS title, " 
    149151                     "a.description AS message, a.reporter AS author, " 
    150                      "a.keywords as keywords, a.id AS data, a.time as time, 0 AS ver " 
     152                     "a.keywords as keywords, %s AS data, a.time as time, 0 AS ver " 
    151153                     "FROM ticket a LEFT JOIN ticket_change b ON a.id = b.ticket " 
    152154                     "WHERE (b.field='comment' AND %s ) OR " 
    153155                     "%s OR %s OR %s OR %s OR %s" % 
    154                      (self.query_to_sql(query, 'b.newvalue'), 
     156                     (union_fields['ticket'], 
     157                      self.query_to_sql(query, 'b.newvalue'), 
    155158                      self.query_to_sql(query, 'summary'), 
    156159                      self.query_to_sql(query, 'keywords'), 
    157160                      self.query_to_sql(query, 'description'), 
  • trac/Timeline.py

    old new  
    2020# Author: Jonas Borgström <jonas@edgewall.com> 
    2121 
    2222from trac import perm 
    23 from trac.util import enum, escape, shorten_line 
     23from trac.util import enum, escape, shorten_line, TracError 
    2424from trac.Module import Module 
    2525from trac.versioncontrol.svn_authz import SubversionAuthorizer 
    2626from trac.web.main import add_link 
     
    4343        if not filters: 
    4444            return [] 
    4545 
    46         sql, params = [], [] 
     46        sql = [] 
     47        union_fields = self.db.get_union_fields('timeline') 
     48         
     49        # sql being formatted for each query below is necessary for casts as  
     50        # string replacements.  This doesn't work in cursor.execute() b/c it's  
     51        # a string replacement.  You'd end up with select 'cast(a.id as text)' - 
     52        # with the undesirable quotes. 
    4753        if 'changeset' in filters: 
    48             sql.append("SELECT time,rev,'','changeset',message,author" 
    49                        " FROM revision WHERE time>=%s AND time<=%s") 
    50             params += (start, stop
     54            sql.append("SELECT time,%s,'','changeset',message,author" 
     55                       " FROM revision WHERE time>=%s AND time<=%s" 
     56                       % (union_fields['changeset'], start, stop)
    5157        if 'ticket' in filters: 
    52             sql.append("SELECT time,id,'','newticket',summary,reporter" 
    53                        " FROM ticket WHERE time>=%s AND time<=%s") 
    54             params += (start, stop
    55             sql.append("SELECT time,ticket,'','reopenedticket','',author " 
     58            sql.append("SELECT time,%s,'','newticket',summary,reporter" 
     59                       " FROM ticket WHERE time>=%s AND time<=%s" 
     60                       % (union_fields['ticket'], start, stop)
     61            sql.append("SELECT time,%s,'','reopenedticket','',author " 
    5662                       "FROM ticket_change WHERE field='status' " 
    57                        "AND newvalue='reopened' AND time>=%s AND time<=%s") 
    58             params += (start, stop
    59             sql.append("SELECT t1.time,t1.ticket,t2.newvalue,'closedticket'," 
     63                       "AND newvalue='reopened' AND time>=%s AND time<=%s" 
     64                       % (union_fields['ticket_change_1'], start, stop)
     65            sql.append("SELECT t1.time,%s,t2.newvalue,'closedticket'," 
    6066                       "t3.newvalue,t1.author" 
    6167                       " FROM ticket_change t1" 
    6268                       "   INNER JOIN ticket_change t2 ON t1.ticket = t2.ticket" 
     
    6571                       "     AND t1.ticket = t3.ticket AND t3.field = 'comment'" 
    6672                       " WHERE t1.field = 'status' AND t1.newvalue = 'closed'" 
    6773                       "   AND t2.field = 'resolution'" 
    68                        "   AND t1.time >= %s AND t1.time <= %s") 
    69             params += (start,stop
     74                       "   AND t1.time >= %s AND t1.time <= %s" 
     75                       % (union_fields['ticket_change_2'], start, stop)
    7076        if 'wiki' in filters: 
    71             sql.append("SELECT time,-1,name,'wiki',comment,author" 
    72                        " FROM wiki WHERE time>=%s AND time<=%s") 
    73             params += (start, stop
     77            sql.append("SELECT time,'',name,'wiki',comment,author" 
     78                       " FROM wiki WHERE time>=%s AND time<=%s"  
     79                       % (start, stop)
    7480        if 'milestone' in filters: 
    75             sql.append("SELECT completed AS time,-1,name,'milestone','',''"  
    76                        " FROM milestone WHERE completed>=%s AND completed<=%s") 
    77             params += (start, stop
     81            sql.append("SELECT completed AS time,'',name,'milestone','',''"  
     82                       " FROM milestone WHERE completed>=%s AND completed<=%s" 
     83                       % (start, stop)
    7884 
    7985        sql = ' UNION ALL '.join(sql) + ' ORDER BY time DESC' 
    8086        if maxrows: 
    81             sql += ' LIMIT %d' 
    82             params += (maxrows,) 
    83  
     87            sql += ' LIMIT %d' % maxrows 
     88         
    8489        cursor = self.db.cursor() 
    85         cursor.execute(sql, params
    86  
     90        cursor.execute(sql
     91         
    8792        # Make the data more HDF-friendly 
    8893        info = [] 
    8994        for idx, row in enum(cursor): 
     
    95100                'time': time.strftime('%H:%M', t), 
    96101                'date': time.strftime('%x', t), 
    97102                'datetime': time.strftime('%a, %d %b %Y %H:%M:%S GMT', gmt), 
    98                 'idata': int(row[1])
     103                'idata': row[1]
    99104                'tdata': escape(row[2]), 
    100105                'type': row[3], 
    101106                'message': row[4] or '', 
  • trac/Report.py

    old new  
    110110        cursor = self.db.cursor() 
    111111        cursor.execute("INSERT INTO report (title,sql,description) " 
    112112                       "VALUES (%s,%s,%s)", (title, sql, description)) 
    113         id = self.db.get_last_id(
     113        id = self.db.get_last_id("report", "id"
    114114        self.db.commit() 
    115115        req.redirect(self.env.href.report(id)) 
    116116 
  • trac/db.py

    old new  
    2121 
    2222from __future__ import generators 
    2323 
     24from trac import db_default 
    2425from trac.util import TracError 
    2526 
    2627import os 
    2728import os.path 
     29import string 
    2830from threading import Condition, Lock 
    2931 
    3032 
     
    7678 
    7779    __slots__ = ['cnx'] 
    7880 
    79     def __init__(self, dbpath, timeout=10000): 
     81    def __init__(self, dbpath, env, create=0, timeout=10000): 
    8082        self.cnx = None 
     83        if create: 
     84            self.create_db(env.path, dbpath) 
     85 
    8186        if dbpath != ':memory:': 
    8287            if not os.access(dbpath, os.F_OK): 
    8388                raise TracError, 'Database "%s" not found.' % dbpath 
     
    9398        import sqlite 
    9499        cnx = sqlite.connect(dbpath, timeout=timeout) 
    95100        ConnectionWrapper.__init__(self, cnx) 
    96  
    97     def get_last_id(self): 
     101         
     102    def get_last_id(self, table, field): 
     103        # table, field needed in other dbms but not sqlite, so ignore them here. 
    98104        return self.cnx.db.sqlite_last_insert_rowid() 
    99105 
     106    def create_db(self, path, dbpath): 
     107         
     108        # make the directory to hold the database 
     109        os.mkdir(os.path.join(path, 'db')) 
     110         
     111        # create the database by getting a connection 
     112        import sqlite 
     113        cnx = sqlite.connect(dbpath, timeout=100) 
     114         
     115        # populate the default schema 
     116        schema = db_default.schema 
     117        sql = "" 
     118         
     119        for tables in schema: 
     120            table = tables[0] 
     121            fields = tables[1] 
     122            sql_fields = [] 
     123            unique = [] 
     124            sql += "CREATE TABLE %s (\n" % table 
     125             
     126            for field in fields: 
     127                name = field[0] 
     128                type = field[1] 
     129                size = field[2] 
     130                pk   = field[3] 
     131                 
     132                if type == 'auto': 
     133                    type = 'INTEGER PRIMARY KEY' 
     134                     
     135                if pk == 'u': 
     136                    unique.append(name) 
     137                 
     138                sql_fields.append(" %s %s" % (name, type)) 
     139                 
     140            if len(unique): 
     141                sql_fields.append(" UNIQUE(%s)" % ",".join(unique)) 
     142            sql += ",\n".join(sql_fields) 
     143            sql += "\n);\n\n" 
     144             
     145        cursor = cnx.cursor() 
     146        cursor.execute(sql) 
     147        cnx.commit() 
     148         
     149        cursor.close() 
     150        cnx.close() 
    100151 
    101 def get_cnx(env): 
     152    def get_union_fields(self, module): 
     153        if module == 'search': 
     154            return {'changeset'       : 'rev', 
     155                    'ticket'          : 'a.id'} 
     156        elif module == 'timeline': 
     157            return {'changeset'       : 'rev', 
     158                    'ticket'          : 'id', 
     159                    'ticket_change_1' : 'ticket', 
     160                    'ticket_change_2' : 't1.ticket'} 
     161             
     162                 
     163                 
     164class PyPgSQLConnection(ConnectionWrapper): 
     165    """ 
     166    Connection wrapper for PostgreSQL using the PyPgSQL driver. 
     167    """ 
     168 
     169    __slots__ = ['cnx'] 
     170 
     171    def __init__(self, dbargs, env, create=0): 
     172        if create: 
     173            self.create_db(env.path, dbargs) 
     174         
     175        # TODO: check to see if db exists, or throw error (see sqlite cnx) 
     176 
     177        args = self.parse_args(dbargs) 
     178         
     179        from pyPgSQL import PgSQL 
     180        cnx = PgSQL.connect("", **args) 
     181        ConnectionWrapper.__init__(self, cnx) 
     182 
     183    def get_last_id(self, table, field): 
     184        cursor = self.cursor() 
     185        sql = "SELECT %s FROM %s " \ 
     186              "WHERE %s = CURRVAL('%s_%s_seq')" \ 
     187              % (field, table, field, table, field) 
     188        cursor.execute(sql) 
     189        id = cursor.fetchone()[0] 
     190        cursor.close() 
     191        return id 
     192 
     193    def create_db(self, path, dbargs): 
     194         
     195        from pyPgSQL import PgSQL 
     196         
     197        args = self.parse_args(dbargs) 
     198        createdb_str = "createdb --host=%s --port=%s --owner=%s " \ 
     199                       "--username=%s %s\n" \ 
     200                       % (args['host'], args['port'], args['user'],  
     201                          args['user'], args['database']) 
     202        print createdb_str 
     203        try: 
     204            # TODO: this is not cross-platform. 
     205            # for Windows, look at win32pipe.popen() 
     206            os.popen(createdb_str) 
     207        except Exception, e: 
     208            print "Error creating PostgreSQL database: %s" % e 
     209            print "command: %s" % createdb_str 
     210         
     211        # get a connection 
     212        cnx = PgSQL.connect("", **args) 
     213         
     214        # populate the default schema 
     215        schema = db_default.schema 
     216        sql = "" 
     217         
     218        for tables in schema: 
     219            table = tables[0] 
     220            fields = tables[1] 
     221            sql_fields = [] 
     222            unique = [] 
     223            sql += "CREATE TABLE %s (\n" % table 
     224             
     225            for field in fields: 
     226                name = field[0] 
     227                type = field[1] 
     228                size = field[2] 
     229                pk   = field[3] 
     230                 
     231                if type == 'auto': 
     232                    type = 'serial' 
     233                     
     234                if pk == 'u': 
     235                    unique.append(name) 
     236                 
     237                sql_fields.append(" %s %s" % (name, type)) 
     238                 
     239            if len(unique): 
     240                sql_fields.append(" CONSTRAINT %s_pkey PRIMARY KEY(%s)" %  
     241                    (table, ",".join(unique))) 
     242            sql += ",\n".join(sql_fields) 
     243            sql += "\n);\n\n" 
     244             
     245        cursor = cnx.cursor() 
     246        cursor.execute(sql) 
     247        cnx.commit() 
     248         
     249        cursor.close() 
     250        cnx.close() 
     251 
     252    def parse_args(self, dbargs): 
     253        """very crude code for parsing the arguments in connect_params""" 
     254         
     255        kargs = {} 
     256        args = dbargs.split(",") 
     257         
     258        for arg in args: 
     259            pair = arg.split("=") 
     260            name = pair[0] 
     261            value = pair[1].strip("'") 
     262            kargs[name] = value 
     263             
     264        return kargs 
     265  
     266    def get_union_fields(self, module): 
     267        if module == 'search': 
     268            return {'changeset'       : 'cast(rev as text)', 
     269                    'ticket'          : 'cast(a.id as text)'} 
     270        elif module == 'timeline': 
     271            return {'changeset'       : 'cast(rev as text)', 
     272                    'ticket'          : 'cast(id as text)', 
     273                    'ticket_change_1' : 'cast(ticket as text)', 
     274                    'ticket_change_2' : 'cast(t1.ticket as text)'} 
     275 
     276def get_cnx(env, create=0): 
    102277    db_str = env.get_config('trac', 'database', 'sqlite:db/trac.db') 
    103278    scheme, rest = db_str.split(':', 1) 
    104279 
    105280    if scheme == 'sqlite': 
    106281        if not rest.startswith('/'): 
    107282            rest = os.path.join(env.path, rest) 
    108         return SQLiteConnection(rest
     283        return SQLiteConnection(rest, env, create
    109284 
     285    if scheme == 'pypgsql': 
     286        return PyPgSQLConnection(rest, env, create) 
     287 
    110288    raise TracError, 'Unsupported database type "%s"' % scheme 
    111289 
    112290 
  • trac/Ticket.py

    old new  
    108108                       % (','.join(std_fields), 
    109109                          ','.join(['%s'] * len(std_fields))), 
    110110                       map(lambda n, self=self: self[n], std_fields)) 
    111         id = db.get_last_id(
     111        id = db.get_last_id("ticket", "id"
    112112 
    113113        custom_fields = filter(lambda n: n[:7] == 'custom_', self.keys()) 
    114114        for name in custom_fields: 
  • 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 
     14Note:  Haven't maintained this for a while.  Use very carefully. 
     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()