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 22 22 from __future__ import generators 23 23 24 24 from trac import db, db_default, Logging, Mimeview, util 25 from types import * 25 26 26 27 import ConfigParser 27 28 import os … … 44 45 * Project specific templates and wiki macros. 45 46 * wiki and ticket attachments. 46 47 """ 47 def __init__(self, path, create=0 ):48 def __init__(self, path, create=0, db_str='sqlite:db/trac.db'): 48 49 self.path = path 49 50 if create: 50 self.create( )51 self.create(db_str) 51 52 self.verify() 52 53 self.load_config() 53 54 try: # Use binary I/O on Windows … … 81 82 repos = SubversionRepository(repos_dir, authz, self.log) 82 83 return CachedRepository(self.get_db_cnx(), repos, authz, self.log) 83 84 84 def create(self ):85 def create(self, db_str): 85 86 def _create_file(fname, data=None): 86 87 fd = open(fname, 'w') 87 88 if data: fd.write(data) … … 120 121 # Site CSS - Place custom CSS, including overriding styles here. 121 122 ?> 122 123 """) 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() 130 129 130 # Create default database by attempting to get connection 131 cnx = db.get_cnx(self, create=1) 132 cnx.close 133 131 134 def insert_default_data(self): 132 135 def prep_value(v): 133 136 if v == None: 134 137 return 'NULL' 135 138 else: 136 return '"%s"' % v 139 prepped = v 140 if type(v) is StringType: 141 prepped = util.sql_escape(prepped) 142 return "'%s'" % prepped 137 143 cnx = self.get_db_cnx() 138 144 cursor = cnx.cursor() 139 145 … … 144 150 values = ','.join(map(prep_value, row)) 145 151 sql = "INSERT INTO %s (%s) VALUES(%s);" % (table, cols, values) 146 152 cursor.execute(sql) 153 cnx.commit() 154 155 def setup_default_config(self): 147 156 for s,n,v in db_default.default_config: 148 157 if not self.cfg.has_section(s): 149 158 self.cfg.add_section(s) 150 159 self.cfg.set(s, n, v) 151 160 self.save_config() 152 cnx.commit()153 161 154 162 def get_version(self): 155 163 cnx = self.get_db_cnx() -
trac/db_default.py
old new 37 37 ## Default data 38 38 ## 39 39 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 ); 40 schema = ( 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 #""" 156 144 157 CREATE TABLE session (158 sid text,159 username text,160 var_name text,161 var_value text,162 UNIQUE(sid,var_name)163 );164 145 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 """170 146 171 147 ## 172 148 ## Default Reports … … 289 265 FROM ticket t,enum p 290 266 WHERE p.name=t.priority AND p.type='priority' 291 267 ORDER BY (milestone IS NULL), milestone DESC, (status = 'closed'), 292 (CASE status WHEN 'closed' THEN modifiedELSE (-1)*p.value END) DESC268 (CASE status WHEN 'closed' THEN changetime ELSE (-1)*p.value END) DESC 293 269 """), 294 270 #---------------------------------------------------------------------------- 295 271 ('My Tickets', -
trac/scripts/admin.py
old new 28 28 import cmd 29 29 import shlex 30 30 import StringIO 31 import traceback 31 32 32 33 from trac import perm, util 33 34 from trac.env import Environment … … 95 96 return 0 96 97 return 1 97 98 98 def env_create(self ):99 def env_create(self, db_str): 99 100 try: 100 self.__env = Environment(self.envname, create=1)101 self.__env = Environment(self.envname, 1, db_str) 101 102 return self.__env 102 103 except Exception, e: 103 104 print 'Failed to create environment.', e 105 print traceback.print_exc() 104 106 sys.exit(1) 105 107 106 108 def db_open(self): … … 473 475 474 476 ## Initenv 475 477 _help_initenv = [('initenv', 'Create and initialize a new environment interactively'), 476 ('initenv <projectname> <repospath> <templatepath> ',478 ('initenv <projectname> <repospath> <templatepath> <dbstr>', 477 479 'Create and initialize a new environment from arguments')] 478 480 479 481 def do_initdb(self, line): … … 506 508 dt = trac.siteconfig.__default_templates_dir__ 507 509 prompt = 'Templates directory [%s]> ' % dt 508 510 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) 509 522 return returnvals 510 523 511 524 def do_initenv(self, line): … … 521 534 project_name = returnvals[0] 522 535 repository_dir = returnvals[1] 523 536 templates_dir = returnvals[2] 524 elif len(arg)!= 3: 537 db_str = returnvals[3] 538 elif len(arg)!= 4: 525 539 print 'Wrong number of arguments to initenv %d' % len(arg) 526 540 return 527 541 else: 528 542 project_name = arg[0] 529 543 repository_dir = arg[1] 530 544 templates_dir = arg[2] 545 db_str = arg[3] 531 546 532 547 if not os.access(os.path.join(templates_dir, 'browser.cs'), os.F_OK) \ 533 548 or not os.access(os.path.join(templates_dir, 'ticket.cs'), os.F_OK): … … 535 550 return 536 551 try: 537 552 print 'Creating and Initializing Project' 538 self.env_create( )553 self.env_create(db_str) 539 554 cnx = self.__env.get_db_cnx() 540 555 print ' Inserting default data' 541 556 self.__env.insert_default_data() … … 560 575 561 576 except Exception, e: 562 577 print 'Failed to initialize database.', e 578 print traceback.print_exc() 563 579 sys.exit(2) 564 580 565 581 -
trac/Search.py
old new 136 136 'Search Error') 137 137 138 138 cursor = self.db.cursor () 139 139 union_fields = self.db.get_union_fields('search') 140 140 141 q = [] 141 142 if changeset: 142 143 q.append("SELECT 1 as type, message AS title, message, author, " 143 "'' AS keywords, revAS data, time,0 AS ver "144 "'' AS keywords, %s AS data, time,0 AS ver " 144 145 "FROM revision WHERE %s OR %s" % 145 (self.query_to_sql(query, 'message'), 146 (union_fields['changeset'], 147 self.query_to_sql(query, 'message'), 146 148 self.query_to_sql(query, 'author'))) 147 149 if tickets: 148 150 q.append("SELECT DISTINCT 2 as type, a.summary AS title, " 149 151 "a.description AS message, a.reporter AS author, " 150 "a.keywords as keywords, a.idAS data, a.time as time, 0 AS ver "152 "a.keywords as keywords, %s AS data, a.time as time, 0 AS ver " 151 153 "FROM ticket a LEFT JOIN ticket_change b ON a.id = b.ticket " 152 154 "WHERE (b.field='comment' AND %s ) OR " 153 155 "%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'), 155 158 self.query_to_sql(query, 'summary'), 156 159 self.query_to_sql(query, 'keywords'), 157 160 self.query_to_sql(query, 'description'), -
trac/Timeline.py
old new 20 20 # Author: Jonas Borgström <jonas@edgewall.com> 21 21 22 22 from trac import perm 23 from trac.util import enum, escape, shorten_line 23 from trac.util import enum, escape, shorten_line, TracError 24 24 from trac.Module import Module 25 25 from trac.versioncontrol.svn_authz import SubversionAuthorizer 26 26 from trac.web.main import add_link … … 43 43 if not filters: 44 44 return [] 45 45 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. 47 53 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) ) 51 57 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 " 56 62 "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'," 60 66 "t3.newvalue,t1.author" 61 67 " FROM ticket_change t1" 62 68 " INNER JOIN ticket_change t2 ON t1.ticket = t2.ticket" … … 65 71 " AND t1.ticket = t3.ticket AND t3.field = 'comment'" 66 72 " WHERE t1.field = 'status' AND t1.newvalue = 'closed'" 67 73 " 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) ) 70 76 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) ) 74 80 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) ) 78 84 79 85 sql = ' UNION ALL '.join(sql) + ' ORDER BY time DESC' 80 86 if maxrows: 81 sql += ' LIMIT %d' 82 params += (maxrows,) 83 87 sql += ' LIMIT %d' % maxrows 88 84 89 cursor = self.db.cursor() 85 cursor.execute(sql , params)86 90 cursor.execute(sql) 91 87 92 # Make the data more HDF-friendly 88 93 info = [] 89 94 for idx, row in enum(cursor): … … 95 100 'time': time.strftime('%H:%M', t), 96 101 'date': time.strftime('%x', t), 97 102 'datetime': time.strftime('%a, %d %b %Y %H:%M:%S GMT', gmt), 98 'idata': int(row[1]),103 'idata': row[1], 99 104 'tdata': escape(row[2]), 100 105 'type': row[3], 101 106 'message': row[4] or '', -
trac/Report.py
old new 110 110 cursor = self.db.cursor() 111 111 cursor.execute("INSERT INTO report (title,sql,description) " 112 112 "VALUES (%s,%s,%s)", (title, sql, description)) 113 id = self.db.get_last_id( )113 id = self.db.get_last_id("report", "id") 114 114 self.db.commit() 115 115 req.redirect(self.env.href.report(id)) 116 116 -
trac/db.py
old new 21 21 22 22 from __future__ import generators 23 23 24 from trac import db_default 24 25 from trac.util import TracError 25 26 26 27 import os 27 28 import os.path 29 import string 28 30 from threading import Condition, Lock 29 31 30 32 … … 76 78 77 79 __slots__ = ['cnx'] 78 80 79 def __init__(self, dbpath, timeout=10000):81 def __init__(self, dbpath, env, create=0, timeout=10000): 80 82 self.cnx = None 83 if create: 84 self.create_db(env.path, dbpath) 85 81 86 if dbpath != ':memory:': 82 87 if not os.access(dbpath, os.F_OK): 83 88 raise TracError, 'Database "%s" not found.' % dbpath … … 93 98 import sqlite 94 99 cnx = sqlite.connect(dbpath, timeout=timeout) 95 100 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. 98 104 return self.cnx.db.sqlite_last_insert_rowid() 99 105 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() 100 151 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 164 class 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 276 def get_cnx(env, create=0): 102 277 db_str = env.get_config('trac', 'database', 'sqlite:db/trac.db') 103 278 scheme, rest = db_str.split(':', 1) 104 279 105 280 if scheme == 'sqlite': 106 281 if not rest.startswith('/'): 107 282 rest = os.path.join(env.path, rest) 108 return SQLiteConnection(rest )283 return SQLiteConnection(rest, env, create) 109 284 285 if scheme == 'pypgsql': 286 return PyPgSQLConnection(rest, env, create) 287 110 288 raise TracError, 'Unsupported database type "%s"' % scheme 111 289 112 290 -
trac/Ticket.py
old new 108 108 % (','.join(std_fields), 109 109 ','.join(['%s'] * len(std_fields))), 110 110 map(lambda n, self=self: self[n], std_fields)) 111 id = db.get_last_id( )111 id = db.get_last_id("ticket", "id") 112 112 113 113 custom_fields = filter(lambda n: n[:7] == 'custom_', self.keys()) 114 114 for name in custom_fields: -
contrib/tracdb-sqlite2pg.py
old new 1 #!/usr/bin/env python 2 3 """ 4 Import a Trac database from sqlite to postgresql. 5 6 Requires: 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 12 Author: Brad Anderson <brad@dsource.org> 13 14 Note: Haven't maintained this for a while. Use very carefully. 15 """ 16 17 import sys, os 18 import sqlite 19 import pgdb 20 from trac.util import sql_escape 21 22 tables=['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 42 def 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 115 def 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 148 def 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 184 if __name__ == '__main__': 185 main()
