PostgresqlPatch: pgsql_patch_14.diff

File pgsql_patch_14.diff, 35.7 kB (added by brad <brad@dsource.org>, 7 years ago)
  • trac/env.py

    old new  
    2828import shutil 
    2929import sys 
    3030import time 
     31from types import * 
    3132import urllib 
    3233import unicodedata 
    3334 
     
    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.config.set('trac', 'database', db_str) 
     128        self.config.save() 
    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() 
    147154 
     155    def setup_default_config(self): 
    148156        for section,name,value in db_default.default_config: 
    149157            self.config.set(section, name, value) 
    150158        self.config.save() 
    151159 
    152         cnx.commit() 
    153  
    154160    def get_version(self): 
    155161        cnx = self.get_db_cnx() 
    156162        cursor = cnx.cursor() 
  • 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
     48    ('rev', 'text', '', 'u')
     49    ('path', 'text', '', 'u')
     50    ('kind', 'char', '1', ''), 
     51    ('change', 'text', '1', 'u'), 
     52    ('base_path', 'text', '', '')
     53    ('base_rev', 'text', '', ''))
     54 ( 
     55    ('node_change_idx', ('rev',)), )), 
     56('auth_cookie',
     57    ('cookie', 'text', '', 'u')
     58    ('name', 'text', '', 'u')
     59    ('ipnr', 'text', '', 'u')
     60    ('time', 'int', '', '')))
     61('enum', ( 
     62    ('type', 'text', '', 'u'), 
     63    ('name', 'text', '', 'u'), 
     64    ('value', 'text', '', '')))
     65('system', ( 
     66    ('name', 'text', '', 'u')
     67    ('value', 'text', '', ''))), 
     68('ticket', ( 
     69    ('id', 'auto', '', 'u'), 
     70    ('time', 'int', '', '')
     71    ('changetime', 'int', '', '')
     72    ('component', 'text', '', ''), 
     73    ('severity', 'text', '', ''), 
     74    ('priority', 'text', '', ''), 
     75    ('owner', 'text', '', '')
     76    ('reporter', 'text', '', ''), 
     77    ('cc', 'text', '', '')
     78    ('url', 'text', '', '')
     79    ('version', 'text', '', '')
     80    ('milestone', 'text', '', '')
     81    ('status', 'text', '', ''), 
     82    ('resolution', 'text', '', '')
     83    ('summary', 'text', '', ''), 
     84    ('description', 'text', '', ''), 
     85    ('keywords', 'text', '', ''))), 
     86('ticket_change', ( 
     87    ('ticket', 'int', '', 'u')
     88    ('time', 'int', '', 'u')
     89    ('author', 'text', '', ''), 
     90    ('field', 'text', '', 'u'), 
     91    ('oldvalue', 'text', '', ''), 
     92    ('newvalue', 'text', '', '')), 
     93
     94    ('ticket_change_idx', ('ticket', 'time')), ))
     95('ticket_custom', ( 
     96    ('ticket', 'int', '', 'u')
     97    ('name', 'text', '', 'u')
     98    ('value', 'text', '', '')))
     99('report', ( 
     100    ('id', 'auto', '', 'u'), 
     101    ('author', 'text', '', ''), 
     102    ('title', 'text', '', ''), 
     103    ('sql', 'text', '', '')
     104    ('description', 'text', '', '')))
     105('permission', ( 
     106    ('username', 'text', '', 'u'), 
     107    ('action', 'text', '', 'u'))), 
     108('component',
     109    ('name', 'text', '', 'u')
     110    ('owner', 'text', '', '')))
     111('milestone',  ( 
     112    ('name', 'text', '', 'u')
     113    ('due', 'int', '', ''), 
     114    ('completed', 'int', '', ''), 
     115    ('description', 'text', '', ''))), 
     116('version', ( 
     117    ('name', 'text', '', 'u'), 
     118    ('time', 'int', '', ''))), 
     119('wiki',  
     120
     121    ('name', 'text', '', 'u')
     122    ('version', 'int', '', 'u'), 
     123    ('time', 'int', '', ''), 
     124    ('author', 'text', '', ''), 
     125    ('ipnr', 'text', '', '')
     126    ('text', 'text', '', '')
     127    ('comment', 'text', '', '')
     128    ('readonly', 'int', '', '')), 
     129 ( 
     130    ('wiki_idx', ('name', 'version')), )), 
     131('attachment', ( 
     132    ('type', 'text', '', 'u'), 
     133    ('id', 'text', '', 'u'), 
     134    ('filename', 'text', '', 'u'), 
     135    ('size', 'int', '', '')
     136    ('time', 'int', '', '')
     137    ('description', 'text', '', '')
     138    ('author', 'text', '', '')
     139    ('ipnr', 'text', '', '')))
     140('session', ( 
     141    ('sid', 'text', '', 'u')
     142    ('username', 'text', '', '')
     143    ('var_name', 'text', '', 'u'), 
     144    ('var_value', 'text', '', '')), 
     145
     146    ('session_idx', ('sid', 'var_name')), )) 
     147     
     148
     149     
     150# TODO: do we need these, or will the u's above do? 
     151#CREATE INDEX node_change_idx    ON node_change(rev); 
     152#CREATE INDEX ticket_change_idx  ON ticket_change(ticket, time); 
     153#CREATE INDEX wiki_idx           ON wiki(name,version); 
     154#CREATE INDEX session_idx        ON session(sid,var_name); 
     155#""" 
    156156 
    157 CREATE TABLE session ( 
    158          sid             text, 
    159          username        text, 
    160          var_name        text, 
    161          var_value       text, 
    162          UNIQUE(sid,var_name) 
    163 ); 
    164157 
    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 """ 
    170158 
    171159## 
    172160## Default Reports 
     
    289277  FROM ticket t,enum p 
    290278  WHERE p.name=t.priority AND p.type='priority' 
    291279  ORDER BY (milestone IS NULL), milestone DESC, (status = 'closed'),  
    292         (CASE status WHEN 'closed' THEN modified ELSE (-1)*p.value END) DESC 
     280        (CASE status WHEN 'closed' THEN changetime ELSE (-1)*p.value END) DESC 
    293281"""), 
    294282#---------------------------------------------------------------------------- 
    295283('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): 
     
    121123            cnx = None 
    122124        cursor.execute(sql) 
    123125        while 1: 
    124             row = cursor.fetchone() 
     126            row = None; 
     127            try: 
     128                row = cursor.fetchone() 
     129            except Exception, e: 
     130                pass 
    125131            if row == None: 
    126132                break 
    127133            data.append(row) 
     
    473479 
    474480    ## Initenv 
    475481    _help_initenv = [('initenv', 'Create and initialize a new environment interactively'), 
    476                      ('initenv <projectname> <repospath> <templatepath>', 
     482                     ('initenv <projectname> <repospath> <templatepath> <dbstr>', 
    477483                      'Create and initialize a new environment from arguments')] 
    478484 
    479485    def do_initdb(self, line): 
     
    506512        dt = trac.siteconfig.__default_templates_dir__ 
    507513        prompt = 'Templates directory [%s]> ' % dt 
    508514        returnvals.append(raw_input(prompt) or dt) 
     515        print 
     516        print ' Please specify the database connection string.' 
     517        print ' Default is for SQLite database.' 
     518        print ' Examples of current options:' 
     519        print "  SQLite     -  sqlite:db/trac.db" 
     520        print "  PostgreSQL -  pypgsql:host='localhost',port='5432',database='trac',user='trac',password='trac'" 
     521        print 
     522        db = 'sqlite:db/trac.db' 
     523        # db = "pypgsql:host='localhost',port='5432',database='trac',user='trac',password='trac'" 
     524        prompt = 'Database connection string [%s]> ' % db 
     525        returnvals.append(raw_input(prompt) or db) 
    509526        return returnvals 
    510527          
    511528    def do_initenv(self, line): 
     
    521538            project_name = returnvals[0] 
    522539            repository_dir = returnvals[1] 
    523540            templates_dir = returnvals[2] 
    524         elif len(arg)!= 3: 
     541            db_str = returnvals[3] 
     542        elif len(arg)!= 4: 
    525543            print 'Wrong number of arguments to initenv %d' % len(arg) 
    526544            return 
    527545        else: 
    528546            project_name = arg[0] 
    529547            repository_dir = arg[1] 
    530548            templates_dir = arg[2] 
     549            db_str = arg[3] 
    531550 
    532551        if not os.access(os.path.join(templates_dir, 'browser.cs'), os.F_OK) \ 
    533552           or not os.access(os.path.join(templates_dir, 'ticket.cs'), os.F_OK): 
     
    535554            return 
    536555        try: 
    537556            print 'Creating and Initializing Project' 
    538             self.env_create(
     557            self.env_create(db_str
    539558            cnx = self.__env.get_db_cnx() 
    540559            print ' Inserting default data' 
    541560            self.__env.insert_default_data() 
     
    562581 
    563582        except Exception, e: 
    564583            print 'Failed to initialize database.', e 
     584            print traceback.print_exc() 
    565585            sys.exit(2) 
    566586 
    567587 
  • 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         
     120        for tables in schema: 
     121            table = tables[0] 
     122            fields = tables[1] 
     123            indices = None 
     124            if len(tables) > 2: 
     125                indices = tables[2] 
     126             
     127            sql_fields = [] 
     128            unique = [] 
     129            sql += "CREATE TABLE %s (\n" % table 
     130             
     131            for field in fields: 
     132                name = field[0] 
     133                type = field[1] 
     134                size = field[2] 
     135                pk   = field[3] 
     136                 
     137                if type == 'auto': 
     138                    type = 'INTEGER PRIMARY KEY' 
     139                     
     140                if pk == 'u': 
     141                    unique.append(name) 
     142                 
     143                sql_fields.append(" %s %s" % (name, type)) 
     144                 
     145            if len(unique): 
     146                sql_fields.append(" UNIQUE(%s)" % ",".join(unique)) 
     147            sql += ",\n".join(sql_fields) 
     148            sql += "\n);\n\n" 
     149             
     150            if indices: 
     151                for index in indices: 
     152                    iname = index[0] 
     153                    ifields = index[1] 
     154                    sql += "CREATE INDEX %s ON %s (%s);\n\n" \ 
     155                           % (iname, table, ','.join(ifields)) 
     156             
     157        #print "%s \n------------------------" % sql 
     158        cursor = cnx.cursor() 
     159        cursor.execute(sql) 
     160        cnx.commit() 
     161         
     162        cursor.close() 
     163        cnx.close() 
    100164 
    101 def get_cnx(env): 
     165    def get_union_fields(self, module): 
     166        if module == 'search': 
     167            return {'changeset'       : 'rev', 
     168                    'ticket'          : 'a.id'} 
     169        elif module == 'timeline': 
     170            return {'changeset'       : 'rev', 
     171                    'ticket'          : 'id', 
     172                    'ticket_change_1' : 'ticket', 
     173                    'ticket_change_2' : 't1.ticket'} 
     174             
     175                 
     176                 
     177class PyPgSQLConnection(ConnectionWrapper): 
     178    """ 
     179    Connection wrapper for PostgreSQL using the PyPgSQL driver. 
     180    """ 
     181 
     182    __slots__ = ['cnx'] 
     183 
     184    def __init__(self, dbargs, env, create=0): 
     185        if create: 
     186            self.create_db(env.path, dbargs) 
     187         
     188        # TODO: check to see if db exists, or throw error (see sqlite cnx) 
     189 
     190        args = self.parse_args(dbargs) 
     191         
     192        from pyPgSQL import PgSQL 
     193        cnx = PgSQL.connect("", **args) 
     194        ConnectionWrapper.__init__(self, cnx) 
     195 
     196    def get_last_id(self, table, field): 
     197        cursor = self.cursor() 
     198        sql = "SELECT %s FROM %s " \ 
     199              "WHERE %s = CURRVAL('%s_%s_seq')" \ 
     200              % (field, table, field, table, field) 
     201        cursor.execute(sql) 
     202        id = cursor.fetchone()[0] 
     203        cursor.close() 
     204        return id 
     205 
     206    def create_db(self, path, dbargs): 
     207         
     208        from pyPgSQL import PgSQL 
     209         
     210        args = self.parse_args(dbargs) 
     211        createdb_str = "createdb --host=%s --port=%s --owner=%s " \ 
     212                       "--username=%s %s\n" \ 
     213                       % (args['host'], args['port'], args['user'],  
     214                          args['user'], args['database']) 
     215        print createdb_str 
     216        try: 
     217            # TODO: this is not cross-platform. 
     218            # for Windows, look at win32pipe.popen() 
     219            os.popen(createdb_str) 
     220        except Exception, e: 
     221            print "Error creating PostgreSQL database: %s" % e 
     222            print "command: %s" % createdb_str 
     223         
     224        # get a connection 
     225        cnx = PgSQL.connect("", **args) 
     226         
     227        # populate the default schema 
     228        schema = db_default.schema 
     229        sql = "" 
     230         
     231        for tables in schema: 
     232            table = tables[0] 
     233            fields = tables[1] 
     234            indices = None 
     235            if len(tables) > 2: 
     236                indices = tables[2] 
     237 
     238            sql_fields = [] 
     239            unique = [] 
     240            sql += "CREATE TABLE %s (\n" % table 
     241             
     242            for field in fields: 
     243                name = field[0] 
     244                type = field[1] 
     245                size = field[2] 
     246                pk   = field[3] 
     247                 
     248                if type == 'auto': 
     249                    type = 'serial' 
     250                     
     251                if pk == 'u': 
     252                    unique.append(name) 
     253                 
     254                sql_fields.append(" %s %s" % (name, type)) 
     255                 
     256            if len(unique): 
     257                sql_fields.append(" CONSTRAINT %s_pkey PRIMARY KEY(%s)" %  
     258                    (table, ",".join(unique))) 
     259            sql += ",\n".join(sql_fields) 
     260            sql += "\n);\n\n" 
     261             
     262            if indices: 
     263                for index in indices: 
     264                    iname = index[0] 
     265                    ifields = index[1] 
     266                    sql += "CREATE INDEX %s ON %s (%s);\n\n" \ 
     267                           % (iname, table, ','.join(ifields)) 
     268             
     269        #print "%s \n------------------------" % sql 
     270        cursor = cnx.cursor() 
     271        cursor.execute(sql) 
     272        cnx.commit() 
     273         
     274        cursor.close() 
     275        cnx.close() 
     276 
     277    def parse_args(self, dbargs): 
     278        """very crude code for parsing the arguments in connect_params""" 
     279         
     280        kargs = {} 
     281        args = dbargs.split(",") 
     282         
     283        for arg in args: 
     284            pair = arg.split("=") 
     285            name = pair[0] 
     286            value = pair[1].strip("'") 
     287            kargs[name] = value 
     288             
     289        return kargs 
     290  
     291    def get_union_fields(self, module): 
     292        if module == 'search': 
     293            return {'changeset'       : 'cast(rev as text)', 
     294                    'ticket'          : 'cast(a.id as text)'} 
     295        elif module == 'timeline': 
     296            return {'changeset'       : 'cast(rev as text)', 
     297                    'ticket'          : 'cast(id as text)', 
     298                    'ticket_change_1' : 'cast(ticket as text)', 
     299                    'ticket_change_2' : 'cast(t1.ticket as text)'} 
     300 
     301def get_cnx(env, create=0): 
    102302    db_str = env.config.get('trac', 'database') 
    103303    scheme, rest = db_str.split(':', 1) 
    104304 
    105305    if scheme == 'sqlite': 
    106306        if not rest.startswith('/'): 
    107307            rest = os.path.join(env.path, rest) 
    108         return SQLiteConnection(rest
     308        return SQLiteConnection(rest, env, create
    109309 
     310    if scheme == 'pypgsql': 
     311        return PyPgSQLConnection(rest, env, create) 
     312 
    110313    raise TracError, 'Unsupported database type "%s"' % scheme 
    111314 
    112315 
  • trac/Ticket.py

    old new  
    106106                       % (','.join(std_fields), 
    107107                          ','.join(['%s'] * len(std_fields))), 
    108108                       map(lambda n, self=self: self[n], std_fields)) 
    109         id = db.get_last_id(
     109        id = db.get_last_id("ticket", "id"
    110110 
    111111        custom_fields = filter(lambda n: n[:7] == 'custom_', self.keys()) 
    112112        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()