PostgresqlPatch: pgsql_patch_06.diff
| File pgsql_patch_06.diff, 74.3 kB (added by brad, 7 years ago) |
|---|
-
scripts/trac-admin
old new 27 27 import time 28 28 import cmd 29 29 import shlex 30 import sqlite31 30 import StringIO 31 import traceback 32 32 33 33 from trac import util 34 34 from trac import sync … … 92 92 return 0 93 93 return 1 94 94 95 def env_create(self ):95 def env_create(self, db_str): 96 96 try: 97 self.__env = trac.Environment.Environment (self.envname, create=1)97 self.__env = trac.Environment.Environment (self.envname, 1, db_str) 98 98 return self.__env 99 99 except Exception, e: 100 100 print 'Failed to create environment.', e … … 111 111 112 112 def db_execsql (self, sql, cursor=None): 113 113 data = [] 114 row = None 114 115 if not cursor: 115 116 cnx=self.db_open() 116 117 cursor = cnx.cursor() … … 118 119 cnx = None 119 120 cursor.execute(sql) 120 121 while 1: 121 row = cursor.fetchone() 122 try: 123 row = cursor.fetchone() 124 except: 125 pass 122 126 if row == None: 123 127 break 124 128 data.append(row) … … 457 461 458 462 ## Initenv 459 463 _help_initenv = [('initenv', 'Create and initialize a new environment interactively'), 460 ('initenv <projectname> <repospath> <templatepath> ',464 ('initenv <projectname> <repospath> <templatepath> <dbms> [dbms options]', 461 465 'Create and initialize a new environment from arguments')] 462 466 463 467 def do_initdb(self, line): … … 490 494 dt = trac.siteconfig.__default_templates_dir__ 491 495 prompt = 'Templates directory [%s]> ' % dt 492 496 returnvals.append(raw_input(prompt) or dt) 497 print 498 print " Please enter the database in which you wish to store Trac data." 499 print " Default is 'sqlite', but others are supported:" 500 print " 'sqlite' - SQLite http://www.sqlite.org" 501 print " 'pgsql' - PostgreSQL http://www.postgresql.org" 502 print 503 ddb = "sqlite" 504 prompt = 'database system [%s]> ' % ddb 505 dbms = raw_input(prompt) or ddb 506 returnvals.append(dbms) 507 508 # PostgreSQL - additional questions 509 if dbms == "pgsql": 510 print 511 print " Please enter the host of your PostgreSQL database." 512 print " Default is 'localhost'" 513 print 514 host = "localhost" 515 prompt = "PostgreSQL host [%s]> " % host 516 returnvals.append(raw_input(prompt) or host) 517 518 print 519 print " Please enter the port of your PostgreSQL database." 520 print " Default is '5432'" 521 print 522 port = "5432" 523 prompt = "PostgreSQL port [%s]> " % port 524 returnvals.append(raw_input(prompt) or port) 525 526 print 527 print " Please enter the name of your PostgreSQL database." 528 print " Default is 'trac'" 529 print " Note: This database should not exist, as trac-admin will" \ 530 " attempt to create it." 531 print 532 name = "trac" 533 prompt = "PostgreSQL database [%s]> " % name 534 returnvals.append(raw_input(prompt) or name) 535 536 print 537 print " Please enter the user of your PostgreSQL database." 538 print " Default is 'trac'" 539 print 540 user = "trac" 541 prompt = "PostgreSQL user [%s]> " % user 542 returnvals.append(raw_input(prompt) or user) 543 544 print 545 print " Please enter the password of your PostgreSQL database." 546 print " Default is 'trac'" 547 print 548 password = "trac" 549 prompt = "PostgreSQL password [%s]> " % password 550 returnvals.append(raw_input(prompt) or password) 551 493 552 return returnvals 494 553 495 554 def do_initenv(self, line): … … 500 559 project_name = None 501 560 repository_dir = None 502 561 templates_dir = None 562 db_str = None 503 563 if len(arg) == 1: 504 564 returnvals = self.get_initenv_args() 505 565 project_name = returnvals[0] 506 566 repository_dir = returnvals[1] 507 567 templates_dir = returnvals[2] 508 elif len(arg)!= 3: 568 db_str = returnvals[3] 569 elif len(arg) < 4: 509 570 print 'Wrong number of arguments to initenv %d' % len(arg) 510 571 return 511 572 else: 512 573 project_name = arg[0] 513 574 repository_dir = arg[1] 514 575 templates_dir = arg[2] 576 db_str = arg[3] 577 578 # sqlite-specific stuff 579 if db_str.lower() == "sqlite": 580 db_str = 'sqlite:"db/trac.db",timeout=10000' 581 582 # postgres-specific stuff 583 if db_str.lower() == "pgsql": 584 if len(arg) == 1: 585 host = returnvals[4] 586 port = returnvals[5] 587 database = returnvals[6] 588 user = returnvals[7] 589 password = returnvals[8] 590 elif len(arg) != 9: 591 print 'Wrong number of arguments to initenv %d' % len(arg) 592 print 'For PostgreSQL (after pgsql): <host> <port> <database>' \ 593 ' <user> <password>' 594 return 595 else: 596 host = arg[4] 597 port = arg[5] 598 database = arg[6] 599 user = arg[7] 600 password = arg[8] 601 db_str = "pgsql:\"\",host='%s:%s',database='%s',user='%s'," \ 602 "password='%s'" \ 603 % (host, port, database, user, password) 604 createdb_str = "createdb --host=%s --port=%s --owner=%s " \ 605 "--username=%s %s\n" \ 606 % (host, port, user, user, database) 607 print createdb_str 608 try: 609 # TODO: this is not cross-platform. 610 # for Windows, look at win32pipe.popen() 611 os.popen(createdb_str) 612 except Exception, e: 613 print "Error creating PostgreSQL database: %s" % e 614 print "command: %s" % createdb_str 615 515 616 from svn import util, repos, core 516 617 core.apr_initialize() 517 618 pool = core.svn_pool_create(None) … … 530 631 return 531 632 try: 532 633 print 'Creating and Initializing Project' 533 self.env_create( )634 self.env_create(db_str) 534 635 cnx = self.__env.get_db_cnx() 535 636 print ' Inserting default data' 536 637 self.__env.insert_default_data() … … 669 770 self.do_help ('wiki') 670 771 except Exception, e: 671 772 print 'Wiki %s failed:' % arg[0], e 773 print traceback.print_exc() 774 672 775 673 776 def _do_wiki_list(self): 674 777 data = self.db_execsql('SELECT name,max(version),time' … … 694 797 data = data.replace("'", "''") # Escape ' for safe SQL 695 798 f.close() 696 799 697 sql = ("INSERT INTO wiki('version','name','time','author','ipnr','text') " 698 " SELECT 1+ifnull(max(version),0),'%(title)s','%(time)s','%(author)s'," 699 " '%(ipnr)s','%(text)s' FROM wiki WHERE name='%(title)s'" 800 sql = ("INSERT INTO wiki(version,name,time,author,ipnr,text) " 801 " SELECT 1+COALESCE(max(version),0),'%(title)s','%(time)s'," 802 "'%(author)s','%(ipnr)s','%(text)s' " 803 "FROM wiki WHERE name='%(title)s'" 700 804 % {'title':title, 701 805 'time':int(time.time()), 702 806 'author':'trac', … … 799 903 800 904 def _do_enum_add(self, type, name): 801 905 sql = ("INSERT INTO enum('value','type','name') " 802 " SELECT 1+ ifnull(max(value),0),'%(type)s','%(name)s'"906 " SELECT 1+COALESCE(max(value),0),'%(type)s','%(name)s'" 803 907 " FROM enum WHERE type='%(type)s'" 804 908 % {'type':type, 805 909 'name':name}) … … 867 971 868 972 def _do_milestone_list(self): 869 973 data = self.db_execsql("SELECT name,due,completed FROM milestone " 870 "ORDER BY IFNULL(due,0)!=0 DESC,due,name")974 "ORDER BY COALESCE(due,0)!=0 DESC,due,name") 871 975 data = map(lambda x: (x[0], x[1] and time.strftime('%c', time.localtime(x[1])), 872 976 x[2] and time.strftime('%c', time.localtime(x[2]))), data) 873 977 self.print_listing(['Name', 'Due', 'Completed'], data) … … 1007 1111 print "Upgrade: Backup of old database saved in " \ 1008 1112 "%s/db/trac.db.%i.bak" % (self.envname, curr) 1009 1113 else: 1010 print "Upgrade: Backup disabled. Non-exist ant warranty voided."1114 print "Upgrade: Backup disabled. Non-existent warranty voided." 1011 1115 self.__env.upgrade(do_backup) 1012 1116 else: 1013 1117 print "Upgrade: Database is up to date, no upgrade necessary." -
trac/db_default.py
old new 30 30 result = [] 31 31 i = 1 32 32 for r in reps: 33 result.append (( i,None, r[0], r[2], r[1]))33 result.append ((None, r[0], r[2], r[1])) 34 34 i = i + 1 35 35 return result 36 36 … … 174 174 CREATE INDEX session_idx ON session(sid,var_name); 175 175 """ 176 176 177 schema_pgsql = """ 178 CREATE TABLE revision ( 179 rev integer, 180 time integer, 181 author text, 182 message text, 183 CONSTRAINT revision_pkey PRIMARY KEY (rev) 184 ); 185 186 CREATE TABLE node_change ( 187 rev integer, 188 name text, 189 change char(1), 190 CONSTRAINT node_change_pkey PRIMARY KEY (rev, name, change) 191 ); 192 193 CREATE TABLE auth_cookie ( 194 cookie text, 195 name text, 196 ipnr text, 197 time integer, 198 CONSTRAINT auth_cookie_pkey PRIMARY KEY(cookie, name, ipnr) 199 ); 200 201 CREATE TABLE enum ( 202 type text, 203 name text, 204 value integer, 205 CONSTRAINT enum_pkey PRIMARY KEY(name,type) 206 ); 207 208 CREATE TABLE system ( 209 name text, 210 value text, 211 CONSTRAINT system_pkey PRIMARY KEY(name) 212 ); 213 214 CREATE TABLE lock ( 215 name text, 216 owner text, 217 ipnr text, 218 time integer, 219 CONSTRAINT lock_pkey PRIMARY KEY(name) 220 ); 221 222 --CREATE SEQUENCE ticket_id_seq; 223 CREATE TABLE ticket ( 224 id serial, 225 time integer, -- the time it was created 226 changetime integer, 227 component text, 228 severity text, 229 priority text, 230 owner text, -- who is this ticket assigned to 231 reporter text, 232 cc text, -- email addresses to notify 233 url text, -- url related to this ticket 234 version text, -- 235 milestone text, -- 236 status text, 237 resolution text, 238 summary text, -- one-line summary 239 description text, -- problem description (long) 240 keywords text, 241 CONSTRAINT ticket_pkey PRIMARY KEY(id) 242 ); 243 244 CREATE TABLE ticket_change ( 245 ticket integer, 246 time integer, 247 author text, 248 field text, 249 oldvalue text, 250 newvalue text, 251 CONSTRAINT ticket_change_pkey PRIMARY KEY(ticket, time, field) 252 ); 253 254 CREATE TABLE ticket_custom ( 255 ticket integer, 256 name text, 257 value text, 258 CONSTRAINT ticket_custom_pkey PRIMARY KEY(ticket,name) 259 ); 260 261 --CREATE SEQUENCE report_id_seq; 262 CREATE TABLE report ( 263 id serial, 264 author text, 265 title text, 266 sql text, 267 description text, 268 CONSTRAINT report_pkey PRIMARY KEY(id) 269 ); 270 271 CREATE TABLE permission ( 272 username text, -- 273 action text, -- allowable activity 274 CONSTRAINT permission_pkey PRIMARY KEY(username,action) 275 ); 276 277 CREATE TABLE component ( 278 name text, 279 owner text, 280 CONSTRAINT component_pkey PRIMARY KEY(name) 281 ); 282 283 CREATE TABLE milestone ( 284 name text, 285 due integer, -- Due date/time 286 completed integer, -- Completed date/time 287 description text, 288 CONSTRAINT milestone_pkey PRIMARY KEY(name) 289 ); 290 291 CREATE TABLE version ( 292 name text, 293 time integer, 294 CONSTRAINT version_pkey PRIMARY KEY(name) 295 ); 296 297 CREATE TABLE wiki ( 298 name text, 299 version integer, 300 time integer, 301 author text, 302 ipnr text, 303 text text, 304 comment text, 305 readonly integer, 306 CONSTRAINT wiki_pkey PRIMARY KEY(name,version) 307 ); 308 309 CREATE TABLE attachment ( 310 type text, 311 id text, 312 filename text, 313 size integer, 314 time integer, 315 description text, 316 author text, 317 ipnr text, 318 CONSTRAINT attachment_pkey PRIMARY KEY(type,id,filename) 319 ); 320 321 CREATE TABLE session ( 322 sid text, 323 username text, 324 var_name text, 325 var_value text, 326 CONSTRAINT session_pkey PRIMARY KEY(sid,var_name) 327 ); 328 329 """ 330 177 331 ## 178 332 ## Default Reports 179 333 ## … … 295 449 FROM ticket t,enum p 296 450 WHERE p.name=t.priority AND p.type='priority' 297 451 ORDER BY (milestone IS NULL), milestone DESC, (status = 'closed'), 298 (CASE status WHEN 'closed' THEN modified ELSE -p.value END) DESC452 (CASE status WHEN 'closed' THEN changetime ELSE (-1)*p.value END) DESC 299 453 """), 300 454 #---------------------------------------------------------------------------- 301 455 ('My Tickets', … … 406 560 ('name', 'value'), 407 561 (('database_version', str(db_version)),)), 408 562 ('report', 409 (' id', 'author', 'title', 'sql', 'description'),563 ('author', 'title', 'sql', 'description'), 410 564 __mkreports(reports))) 411 565 412 566 default_config = \ 413 567 (('trac', 'htdocs_location', '/trac/'), 414 568 ('trac', 'repository_dir', '/var/svn/myrep'), 415 569 ('trac', 'templates_dir', '/usr/lib/trac/templates'), 416 ('trac', 'database', 'sqlite: db/trac.db'),570 ('trac', 'database', 'sqlite:"db/trac.db",timeout=10000'), 417 571 ('trac', 'default_charset', 'iso-8859-15'), 418 572 ('logging', 'log_type', 'none'), 419 573 ('logging', 'log_file', 'trac.log'), -
trac/Milestone.py
old new 157 157 cursor = self.db.cursor() 158 158 self.log.debug("Creating new milestone '%s'" % name) 159 159 cursor.execute("INSERT INTO milestone (name,due,completed,description) " 160 "VALUES (%s,% d,%d,%s)", name, due, completed,160 "VALUES (%s,%s,%s,%s)", name, due, completed, 161 161 description) 162 162 self.db.commit() 163 163 self.req.redirect(self.env.href.milestone(name)) … … 196 196 'associated with milestone %s' % id) 197 197 cursor.execute("UPDATE ticket SET milestone = %s " 198 198 "WHERE milestone = %s", name, id) 199 cursor.execute("UPDATE milestone SET name = %s, due = % d, "200 "completed = % d, description = %s WHERE name = %s",199 cursor.execute("UPDATE milestone SET name = %s, due = %s, " 200 "completed = %s, description = %s WHERE name = %s", 201 201 name, due, completed, description, id) 202 202 self.db.commit() 203 203 self.req.redirect(self.env.href.milestone(name)) … … 209 209 groups = [] 210 210 if by in ['status', 'resolution', 'severity', 'priority']: 211 211 cursor.execute("SELECT name FROM enum WHERE type = %s " 212 "AND IFNULL(name,'') != '' ORDER BY value", by)212 "AND COALESCE(name,'') != '' ORDER BY value", by) 213 213 elif by in ['component', 'milestone', 'version']: 214 214 cursor.execute("SELECT name FROM %s " 215 "WHERE IFNULL(name,'') != '' ORDER BY name" % by)215 "WHERE COALESCE(name,'') != '' ORDER BY name" % by) 216 216 elif by == 'owner': 217 217 cursor.execute("SELECT DISTINCT owner AS name FROM ticket " 218 218 "ORDER BY owner") -
trac/Search.py
old new 117 117 118 118 cursor = self.db.cursor () 119 119 120 # ugly 'cast' hack for sqlite vs other dbms 121 # and UNION ALL requiring like column datatypes 122 data_changeset = 'rev' 123 data_tickets = 'a.id' 124 dbms = self.env.dbms 125 if dbms != 'sqlite': 126 data_changeset = 'cast(rev as text)' 127 data_tickets = 'cast(a.id as text)' 128 120 129 q = [] 121 130 if changeset: 122 131 q.append('SELECT 1 as type, message AS title, message, author, ' 123 ' \'\' AS keywords, revAS data, time,0 AS ver'132 ' \'\' AS keywords, %s AS data, time,0 AS ver' 124 133 ' FROM revision WHERE %s OR %s' % 125 (self.query_to_sql(query, 'message'), 134 (data_changeset, 135 self.query_to_sql(query, 'message'), 126 136 self.query_to_sql(query, 'author'))) 127 137 if tickets: 128 138 q.append('SELECT DISTINCT 2 as type, a.summary AS title, ' 129 139 ' a.description AS message, a.reporter AS author, ' 130 ' a.keywords as keywords, a.id AS data, a.time as time, 0 AS ver' 131 ' FROM ticket a LEFT JOIN ticket_change b ON a.id = b.ticket' 132 ' WHERE (b.field=\'comment\' AND %s ) OR' 133 ' %s OR %s OR %s OR %s OR %s' % 134 (self.query_to_sql(query, 'b.newvalue'), 140 ' a.keywords as keywords, %s AS data, a.time as time' 141 ' , 0 AS ver FROM ticket a LEFT JOIN ticket_change b' 142 ' ON a.id = b.ticket WHERE (b.field=\'comment\' AND %s )' 143 ' OR %s OR %s OR %s OR %s OR %s' % 144 (data_tickets, 145 self.query_to_sql(query, 'b.newvalue'), 135 146 self.query_to_sql(query, 'summary'), 136 147 self.query_to_sql(query, 'keywords'), 137 148 self.query_to_sql(query, 'description'), -
trac/Query.py
old new 154 154 sql.append("\nFROM ticket") 155 155 for k in [k for k in cols if k in custom_fields]: 156 156 sql.append("\n LEFT OUTER JOIN ticket_custom AS %s ON " \ 157 "(id=%s.ticket AND %s.name='%s') " % (k, k, k, k))157 "(id=%s.ticket AND %s.name='%s') tc" % (k, k, k, k)) 158 158 159 159 for col in [c for c in ['status', 'resolution', 'priority', 'severity'] 160 160 if c == self.order or c == self.group]: 161 161 sql.append("\n LEFT OUTER JOIN (SELECT name AS %s_name, " \ 162 162 "value AS %s_value " \ 163 "FROM enum WHERE type='%s') " \163 "FROM enum WHERE type='%s') e" \ 164 164 " ON %s_name=%s" % (col, col, col, col, col)) 165 165 for col in [c for c in ['milestone', 'version'] 166 166 if c == self.order or c == self.group]: 167 167 time_col = col == 'milestone' and 'due' or 'time' 168 168 sql.append("\n LEFT OUTER JOIN (SELECT name AS %s_name, " \ 169 "%s AS %s_time FROM %s) " \169 "%s AS %s_time FROM %s) a" \ 170 170 " ON %s_name=%s" % (col, time_col, col, col, col, col)) 171 171 172 172 def get_constraint_sql(name, value, mode, neg): 173 173 value = sql_escape(value[len(mode and '!' or '' + mode):]) 174 174 if mode == '~' and value: 175 return " IFNULL(%s,'') %sLIKE '%%%s%%'" % (175 return "COALESCE(%s,'') %sLIKE '%%%s%%'" % ( 176 176 name, neg and 'NOT ' or '', value) 177 177 elif mode == '^' and value: 178 return " IFNULL(%s,'') %sLIKE '%s%%'" % (178 return "COALESCE(%s,'') %sLIKE '%s%%'" % ( 179 179 name, neg and 'NOT ' or '', value) 180 180 elif mode == '$' and value: 181 return " IFNULL(%s,'') %sLIKE '%%%s'" % (181 return "COALESCE(%s,'') %sLIKE '%%%s'" % ( 182 182 name, neg and 'NOT ' or '', value) 183 183 elif mode == '': 184 return " IFNULL(%s,'')%s='%s'" % (name, neg and '!' or '', value)184 return "COALESCE(%s,'')%s='%s'" % (name, neg and '!' or '', value) 185 185 186 186 clauses = [] 187 187 for k, v in self.constraints.items(): … … 195 195 # Special case for exact matches on multiple values 196 196 if not mode and len(v) > 1: 197 197 inlist = ",".join(["'" + sql_escape(val[neg and 1 or 0:]) + "'" for val in v]) 198 clauses.append(" IFNULL(%s,'') %sIN (%s)" % (k, neg and "NOT " or "", inlist))198 clauses.append("COALESCE(%s,'') %sIN (%s)" % (k, neg and "NOT " or "", inlist)) 199 199 elif len(v) > 1: 200 200 constraint_sql = [get_constraint_sql(k, val, mode, neg) for val in v] 201 201 if neg: … … 214 214 if self.group and self.group != self.order: 215 215 order_cols.insert(0, (self.group, self.groupdesc)) 216 216 for col, desc in order_cols: 217 if desc: 218 sql.append("IFNULL(%s,'')='' DESC," % col) 217 if col == 'id': 218 # TODO: this is a somewhat ugly hack. Can we also have the 219 # column type for this? If it's an integer, we do first 220 # one, if text, we do 'else' 221 if desc: 222 sql.append("COALESCE(%s,0)=0 DESC," % col) 223 else: 224 sql.append("COALESCE(%s,0)=0," % col) 219 225 else: 220 sql.append("IFNULL(%s,'')=''," % col) 226 if desc: 227 sql.append("COALESCE(%s,'')='' DESC," % col) 228 else: 229 sql.append("COALESCE(%s,'')=''," % col) 221 230 if col in ['status', 'resolution', 'priority', 'severity']: 222 231 if desc: 223 232 sql.append("%s_value DESC" % col) … … 225 234 sql.append("%s_value" % col) 226 235 elif col in ['milestone', 'version']: 227 236 if desc: 228 sql.append(" IFNULL(%s_time,0)=0 DESC,%s_time DESC,%s DESC"237 sql.append("COALESCE(%s_time,0)=0 DESC,%s_time DESC,%s DESC" 229 238 % (col, col, col)) 230 239 else: 231 sql.append(" IFNULL(%s_time,0)=0,%s_time,%s"240 sql.append("COALESCE(%s_time,0)=0,%s_time,%s" 232 241 % (col, col, col)) 233 242 else: 234 243 if desc: -
trac/Timeline.py
old new 142 142 if max_node != 0: 143 143 cursor_node = self.db.cursor () 144 144 cursor_node.execute("SELECT name, change " 145 "FROM node_change WHERE rev=% d" %item['idata'])145 "FROM node_change WHERE rev=%s", item['idata']) 146 146 node_list = '' 147 147 node_data = '' 148 148 node_count = 0; -
trac/Report.py
old new 110 110 def create_report(self, title, description, sql): 111 111 self.perm.assert_permission(perm.REPORT_CREATE) 112 112 113 dbms = self.env.get_dbms() 113 114 cursor = self.db.cursor() 114 cursor.execute('INSERT INTO report (id, title, sql, description)' 115 'VALUES (NULL, %s, %s, %s)', title, sql, description) 116 id = self.db.db.sqlite_last_insert_rowid() 115 cursor.execute('INSERT INTO report (title, sql, description)' 116 'VALUES (%s, %s, %s)', (title, sql, description,)) 117 118 if dbms == 'pgsql': 119 cursor.execute("SELECT id FROM report " \ 120 "WHERE id = CURRVAL('report_id_seq')") 121 id = cursor.fetchone()[0] 122 else: # sqlite way 123 id = self.db.db.sqlite_last_insert_rowid() 124 117 125 self.db.commit() 118 126 self.req.redirect(self.env.href.report(id)) 119 127 … … 140 148 141 149 # FIXME: fetchall should probably not be used. 142 150 info = cursor.fetchall() 143 cols = cursor. rs.col_defs151 cols = cursor.description 144 152 # Escape the values so that they are safe to have as html parameters 145 153 #info = map(lambda row: map(lambda x: escape(x), row), info) 146 154 -
trac/tests/tracadmin-tests.txt
old new 1 1 ===== test_help_ok ===== 2 trac-admin - The Trac Administration Console %(version)s2 trac-admin - The Trac Administration Console 0.8 3 3 4 4 Usage: trac-admin </path/to/projenv> [command [subcommand] [option ...]] 5 5 6 6 Invoking trac-admin without command starts interactive mode. 7 7 8 about -- Shows information about trac-admin9 help -- Show documentation10 initenv -- Create and initialize a new environment interactively11 initenv <projectname> <repospath> <templatepath> -- Create and initialize a new environment from arguments12 hotcopy <backupdir> -- Make a hot backup copy of an environment13 resync -- Re-synchronize trac with the repository14 upgrade -- Upgrade database to current version15 wiki list -- List wiki pages16 wiki export <page> [file] -- Export wiki page to file or stdout17 wiki import <page> [file] -- Import wiki page from file or stdin18 wiki dump <directory> -- Export all wiki pages to files named by title19 wiki load <directory> -- Import all wiki pages from directory20 wiki upgrade -- Upgrade default wiki pages to current version21 permission list -- List permission rules22 permission add <user> <action> [action] [...] -- Add a new permission rule23 permission remove <user> <action> [action] [...] -- Remove permission rule24 component list -- Show available components25 component add <name> <owner> -- Add a new component26 component rename <name> <newname> -- Rename a component27 component remove <name> -- Remove/uninstall component28 component chown <name> <owner> -- Change component ownership29 priority list -- Show possible ticket priorities30 priority add <value> -- Add a priority value option31 priority change <value> <newvalue> -- Change a priority value32 priority remove <value> -- Remove priority value33 severity list -- Show possible ticket priorities34 severity add <value> -- Add a severity value option35 severity change <value> <newvalue> -- Change a severity value36 severity remove <value> -- Remove severity value37 version list -- Show versions38 version add <name> [time] -- Add version39 version rename <name> <newname> -- Rename version40 version time <name> <time> -- Set version date (Format: "%(date_format_hint)s" or "now")41 version remove <name> -- Remove version42 milestone list -- Show milestones43 milestone add <name> [due] -- Add milestone44 milestone rename <name> <newname> -- Rename milestone45 milestone due <name> <due> -- Set milestone due date (Format: "%(date_format_hint)s" or "now")46 milestone completed <name> <completed> -- Set milestone completed date (Format: "%(date_format_hint)s" or "now")47 milestone remove <name> -- Remove milestone8 about -- Shows information about trac-admin 9 help -- Show documentation 10 initenv -- Create and initialize a new environment interactively 11 initenv <projectname> <repospath> <templatepath> <dbms> [dbms options] -- Create and initialize a new environment from arguments 12 hotcopy <backupdir> -- Make a hot backup copy of an environment 13 resync -- Re-synchronize trac with the repository 14 upgrade -- Upgrade database to current version 15 wiki list -- List wiki pages 16 wiki export <page> [file] -- Export wiki page to file or stdout 17 wiki import <page> [file] -- Import wiki page from file or stdin 18 wiki dump <directory> -- Export all wiki pages to files named by title 19 wiki load <directory> -- Import all wiki pages from directory 20 wiki upgrade -- Upgrade default wiki pages to current version 21 permission list -- List permission rules 22 permission add <user> <action> [action] [...] -- Add a new permission rule 23 permission remove <user> <action> [action] [...] -- Remove permission rule 24 component list -- Show available components 25 component add <name> <owner> -- Add a new component 26 component rename <name> <newname> -- Rename a component 27 component remove <name> -- Remove/uninstall component 28 component chown <name> <owner> -- Change component ownership 29 priority list -- Show possible ticket priorities 30 priority add <value> -- Add a priority value option 31 priority change <value> <newvalue> -- Change a priority value 32 priority remove <value> -- Remove priority value 33 severity list -- Show possible ticket priorities 34 severity add <value> -- Add a severity value option 35 severity change <value> <newvalue> -- Change a severity value 36 severity remove <value> -- Remove severity value 37 version list -- Show versions 38 version add <name> [time] -- Add version 39 version rename <name> <newname> -- Rename version 40 version time <name> <time> -- Set version date (Format: "MM/DD/YY" or "now") 41 version remove <name> -- Remove version 42 milestone list -- Show milestones 43 milestone add <name> [due] -- Add milestone 44 milestone rename <name> <newname> -- Rename milestone 45 milestone due <name> <due> -- Set milestone due date (Format: "MM/DD/YY" or "now") 46 milestone completed <name> <completed> -- Set milestone completed date (Format: "MM/DD/YY" or "now") 47 milestone remove <name> -- Remove milestone 48 48 49 49 Visit the Trac Project at http://trac.edgewall.com/ 50 50 -
trac/tests/ticket.py
old new 18 18 assert ticket['reporter'] == 'santa' 19 19 assert ticket['summary'] == 'Foo' 20 20 assert ticket['custom_foo'] == 'This is a custom field' 21 ticket.insert(self.db )21 ticket.insert(self.db, self.dbms) 22 22 # Retrieving ticket 23 23 ticket2 = Ticket(self.db, 1) 24 24 assert ticket2['id'] == 1 -
trac/tests/environment.py
old new 10 10 self.env = Environment(self._get_envpath(), create=1) 11 11 self.env.insert_default_data() 12 12 self.db = self.env.get_db_cnx() 13 self.dbms = self.env.get_dbms() 13 14 14 15 def tearDown(self): 15 16 self.env = None … … 36 37 37 38 def test_config(self): 38 39 """Testing env.get/set_config""" 39 assert self.env.get_config('trac', 'database') == 'sqlite:db/trac.db' 40 # Any way to do this with multiple backends now supported? 41 # assert self.env.get_config('trac', 'database') == 'sqlite:db/trac.db' 40 42 self.env.set_config('foo', 'bar', 'baz') 41 43 self.env.save_config() 42 44 assert self.env.get_config('foo', 'bar') == 'baz' -
trac/tests/query.py
old new 11 11 self.assertEqual(sql, 12 12 """SELECT id,summary,status,owner,priority,milestone,component 13 13 FROM ticket 14 ORDER BY IFNULL(id,'')='',id""")14 ORDER BY COALESCE(id,0)=0,id""") 15 15 16 16 def test_all_ordered_by_id_desc(self): 17 17 query = Query(self.env, order='id', desc=1) … … 19 19 self.assertEqual(sql, 20 20 """SELECT id,summary,status,owner,priority,milestone,component 21 21 FROM ticket 22 ORDER BY IFNULL(id,'')=''DESC,id DESC""")22 ORDER BY COALESCE(id,0)=0 DESC,id DESC""") 23 23 24 24 def test_all_ordered_by_id_verbose(self): 25 25 query = Query(self.env, order='id', verbose=1) … … 27 27 self.assertEqual(sql, 28 28 """SELECT id,summary,status,owner,priority,milestone,component,reporter,time,description 29 29 FROM ticket 30 ORDER BY IFNULL(id,'')='',id""")30 ORDER BY COALESCE(id,0)=0,id""") 31 31 32 32 def test_all_ordered_by_priority(self): 33 33 query = Query(self.env) # priority is default order … … 35 35 self.assertEqual(sql, 36 36 """SELECT id,summary,status,owner,priority,milestone,component 37 37 FROM ticket 38 LEFT OUTER JOIN (SELECT name AS priority_name, value AS priority_value FROM enum WHERE type='priority') ON priority_name=priority39 ORDER BY IFNULL(priority,'')='',priority_value,id""")38 LEFT OUTER JOIN (SELECT name AS priority_name, value AS priority_value FROM enum WHERE type='priority') e ON priority_name=priority 39 ORDER BY COALESCE(priority,'')='',priority_value,id""") 40 40 41 41 def test_all_ordered_by_priority_desc(self): 42 42 query = Query(self.env, desc=1) # priority is default order … … 44 44 self.assertEqual(sql, 45 45 """SELECT id,summary,status,owner,priority,milestone,component 46 46 FROM ticket 47 LEFT OUTER JOIN (SELECT name AS priority_name, value AS priority_value FROM enum WHERE type='priority') ON priority_name=priority48 ORDER BY IFNULL(priority,'')='' DESC,priority_value DESC,id""")47 LEFT OUTER JOIN (SELECT name AS priority_name, value AS priority_value FROM enum WHERE type='priority') e ON priority_name=priority 48 ORDER BY COALESCE(priority,'')='' DESC,priority_value DESC,id""") 49 49 50 50 def test_all_ordered_by_version(self): 51 51 query = Query(self.env, order='version') … … 53 53 self.assertEqual(sql, 54 54 """SELECT id,summary,status,owner,priority,milestone,version 55 55 FROM ticket 56 LEFT OUTER JOIN (SELECT name AS version_name, time AS version_time FROM version) ON version_name=version57 ORDER BY IFNULL(version,'')='',IFNULL(version_time,0)=0,version_time,version,id""")56 LEFT OUTER JOIN (SELECT name AS version_name, time AS version_time FROM version) a ON version_name=version 57 ORDER BY COALESCE(version,'')='',COALESCE(version_time,0)=0,version_time,version,id""") 58 58 59 59 def test_all_ordered_by_version_desc(self): 60 60 query = Query(self.env, order='version', desc=1) … … 62 62 self.assertEqual(sql, 63 63 """SELECT id,summary,status,owner,priority,milestone,version 64 64 FROM ticket 65 LEFT OUTER JOIN (SELECT name AS version_name, time AS version_time FROM version) ON version_name=version66 ORDER BY IFNULL(version,'')='' DESC,IFNULL(version_time,0)=0 DESC,version_time DESC,version DESC,id""")65 LEFT OUTER JOIN (SELECT name AS version_name, time AS version_time FROM version) a ON version_name=version 66 ORDER BY COALESCE(version,'')='' DESC,COALESCE(version_time,0)=0 DESC,version_time DESC,version DESC,id""") 67 67 68 68 def test_constrained_by_milestone(self): 69 69 query = Query(self.env, order='id') … … 72 72 self.assertEqual(sql, 73 73 """SELECT id,summary,status,owner,priority,component,version,milestone 74 74 FROM ticket 75 WHERE IFNULL(milestone,'')='milestone1'76 ORDER BY IFNULL(id,'')='',id""")75 WHERE COALESCE(milestone,'')='milestone1' 76 ORDER BY COALESCE(id,0)=0,id""") 77 77 78 78 def test_all_grouped_by_milestone(self): 79 79 query = Query(self.env, order='id', group='milestone') … … 81 81 self.assertEqual(sql, 82 82 """SELECT id,summary,status,owner,priority,component,version,milestone 83 83 FROM ticket 84 LEFT OUTER JOIN (SELECT name AS milestone_name, due AS milestone_time FROM milestone) ON milestone_name=milestone85 ORDER BY IFNULL(milestone,'')='',IFNULL(milestone_time,0)=0,milestone_time,milestone,IFNULL(id,'')='',id""")84 LEFT OUTER JOIN (SELECT name AS milestone_name, due AS milestone_time FROM milestone) a ON milestone_name=milestone 85 ORDER BY COALESCE(milestone,'')='',COALESCE(milestone_time,0)=0,milestone_time,milestone,COALESCE(id,0)=0,id""") 86 86 87 87 def test_all_grouped_by_milestone_desc(self): 88 88 query = Query(self.env, order='id', group='milestone', groupdesc=1) … … 90 90 self.assertEqual(sql, 91 91 """SELECT id,summary,status,owner,priority,component,version,milestone 92 92 FROM ticket 93 LEFT OUTER JOIN (SELECT name AS milestone_name, due AS milestone_time FROM milestone) ON milestone_name=milestone94 ORDER BY IFNULL(milestone,'')='' DESC,IFNULL(milestone_time,0)=0 DESC,milestone_time DESC,milestone DESC,IFNULL(id,'')='',id""")93 LEFT OUTER JOIN (SELECT name AS milestone_name, due AS milestone_time FROM milestone) a ON milestone_name=milestone 94 ORDER BY COALESCE(milestone,'')='' DESC,COALESCE(milestone_time,0)=0 DESC,milestone_time DESC,milestone DESC,COALESCE(id,0)=0,id""") 95 95 96 96 def test_grouped_by_priority(self): 97 97 query = Query(self.env, group='priority') … … 99 99 self.assertEqual(sql, 100 100 """SELECT id,summary,status,owner,milestone,component,version,priority 101 101 FROM ticket 102 LEFT OUTER JOIN (SELECT name AS priority_name, value AS priority_value FROM enum WHERE type='priority') ON priority_name=priority103 ORDER BY IFNULL(priority,'')='',priority_value,id""")102 LEFT OUTER JOIN (SELECT name AS priority_name, value AS priority_value FROM enum WHERE type='priority') e ON priority_name=priority 103 ORDER BY COALESCE(priority,'')='',priority_value,id""") 104 104 105 105 def test_constrained_by_milestone_not(self): 106 106 query = Query(self.env, order='id') … … 109 109 self.assertEqual(sql, 110 110 """SELECT id,summary,milestone,status,owner,priority,component 111 111 FROM ticket 112 WHERE IFNULL(milestone,'')!='milestone1'113 ORDER BY IFNULL(id,'')='',id""")112 WHERE COALESCE(milestone,'')!='milestone1' 113 ORDER BY COALESCE(id,0)=0,id""") 114 114 115 115 def test_constrained_by_status(self): 116 116 query = Query(self.env, order='id') … … 119 119 self.assertEqual(sql, 120 120 """SELECT id,summary,status,owner,priority,milestone,component 121 121 FROM ticket 122 WHERE IFNULL(status,'') IN ('new','assigned','reopened')123 ORDER BY IFNULL(id,'')='',id""")122 WHERE COALESCE(status,'') IN ('new','assigned','reopened') 123 ORDER BY COALESCE(id,0)=0,id""") 124 124 125 125 def test_constrained_by_owner_containing(self): 126 126 query = Query(self.env, order='id') … … 129 129 self.assertEqual(sql, 130 130 """SELECT id,summary,owner,status,priority,milestone,component 131 131 FROM ticket 132 WHERE IFNULL(owner,'') LIKE '%someone%'133 ORDER BY IFNULL(id,'')='',id""")132 WHERE COALESCE(owner,'') LIKE '%someone%' 133 ORDER BY COALESCE(id,0)=0,id""") 134 134 135 135 def test_constrained_by_owner_not_containing(self): 136 136 query = Query(self.env, order='id') … … 139 139 self.assertEqual(sql, 140 140 """SELECT id,summary,owner,status,priority,milestone,component 141 141 FROM ticket 142 WHERE IFNULL(owner,'') NOT LIKE '%someone%'143 ORDER BY IFNULL(id,'')='',id""")142 WHERE COALESCE(owner,'') NOT LIKE '%someone%' 143 ORDER BY COALESCE(id,0)=0,id""") 144 144 145 145 def test_constrained_by_owner_beginswith(self): 146 146 query = Query(self.env, order='id') … … 149 149 self.assertEqual(sql, 150 150 """SELECT id,summary,owner,status,priority,milestone,component 151 151 FROM ticket 152 WHERE IFNULL(owner,'') LIKE 'someone%'153 ORDER BY IFNULL(id,'')='',id""")152 WHERE COALESCE(owner,'') LIKE 'someone%' 153 ORDER BY COALESCE(id,0)=0,id""") 154 154 155 155 def test_constrained_by_owner_endswith(self): 156 156 query = Query(self.env, order='id') … … 159 159 self.assertEqual(sql, 160 160 """SELECT id,summary,owner,status,priority,milestone,component 161 161 FROM ticket 162 WHERE IFNULL(owner,'') LIKE '%someone'163 ORDER BY IFNULL(id,'')='',id""")162 WHERE COALESCE(owner,'') LIKE '%someone' 163 ORDER BY COALESCE(id,0)=0,id""") 164 164 165 165 def test_constrained_by_custom_field(self): 166 166 self.env.set_config('ticket-custom', 'foo', 'text') … … 170 170 self.assertEqual(sql, 171 171 """SELECT id,summary,status,owner,priority,milestone,component, foo.value AS foo 172 172 FROM ticket 173 LEFT OUTER JOIN ticket_custom AS foo ON (id=foo.ticket AND foo.name='foo') 174 WHERE IFNULL(foo,'')='something'175 ORDER BY IFNULL(id,'')='',id""")173 LEFT OUTER JOIN ticket_custom AS foo ON (id=foo.ticket AND foo.name='foo') tc 174 WHERE COALESCE(foo,'')='something' 175 ORDER BY COALESCE(id,0)=0,id""") 176 176 177 177 def test_constrained_by_multiple_owners(self): 178 178 query = Query(self.env, order='id') … … 181 181 self.assertEqual(sql, 182 182 """SELECT id,summary,owner,status,priority,milestone,component 183 183 FROM ticket 184 WHERE IFNULL(owner,'') IN ('someone','someone_else')185 ORDER BY IFNULL(id,'')='',id""")184 WHERE COALESCE(owner,'') IN ('someone','someone_else') 185 ORDER BY COALESCE(id,0)=0,id""") 186 186 187 187 def test_constrained_by_multiple_owners_not(self): 188 188 query = Query(self.env, order='id') … … 191 191 self.assertEqual(sql, 192 192 """SELECT id,summary,owner,status,priority,milestone,component 193 193 FROM ticket 194 WHERE IFNULL(owner,'') NOT IN ('someone','someone_else')195 ORDER BY IFNULL(id,'')='',id""")194 WHERE COALESCE(owner,'') NOT IN ('someone','someone_else') 195 ORDER BY COALESCE(id,0)=0,id""") 196 196 197 197 def test_constrained_by_multiple_owners_contain(self): 198 198 query = Query(self.env, order='id') … … 201 201 self.assertEqual(sql, 202 202 """SELECT id,summary,owner,status,priority,milestone,component 203 203 FROM ticket 204 WHERE ( IFNULL(owner,'') LIKE '%someone%' OR IFNULL(owner,'') LIKE '%someone_else%')205 ORDER BY IFNULL(id,'')='',id""")204 WHERE (COALESCE(owner,'') LIKE '%someone%' OR COALESCE(owner,'') LIKE '%someone_else%') 205 ORDER BY COALESCE(id,0)=0,id""") 206 206 207 207 def suite(): 208 208 return unittest.makeSuite(QueryTestCase, 'test') -
trac/sync.py
old new 35 35 (util.SVN_VER_MAJOR, util.SVN_VER_MINOR, util.SVN_VER_MICRO) 36 36 37 37 cursor = db.cursor() 38 cursor.execute('SELECT ifnull(max(rev), 0) FROM revision')38 cursor.execute('SELECT COALESCE(max(rev), 0) FROM revision') 39 39 youngest_stored = int(cursor.fetchone()[0]) 40 40 max_rev = fs.youngest_rev(fs_ptr, pool) 41 41 num = max_rev - youngest_stored -
trac/Roadmap.py
old new 44 44 if show == 'all': 45 45 icalhref += '&show=all' 46 46 query = "SELECT name,due,completed,description FROM milestone " \ 47 "WHERE IFNULL(name,'')!='' " \48 "ORDER BY IFNULL(due,0)=0,due,name"47 "WHERE COALESCE(name,'')!='' " \ 48 "ORDER BY COALESCE(due,0)=0,due,name" 49 49 else: 50 50 self.req.hdf.setValue('roadmap.showall', '1') 51 51 query = "SELECT name,due,completed,description FROM milestone " \ 52 "WHERE IFNULL(name,'')!='' " \53 "AND IFNULL(completed,0)=0 " \54 "ORDER BY IFNULL(due,0)=0,due,name"52 "WHERE COALESCE(name,'')!='' " \ 53 "AND COALESCE(completed,0)=0 " \ 54 "ORDER BY COALESCE(due,0)=0,due,name" 55 55 56 56 if self.req.authname and self.req.authname != 'anonymous': 57 57 icalhref += '&user=' + self.req.authname … … 176 176 if ticket['status'] == 'closed': 177 177 cursor = self.db.cursor() 178 178 cursor.execute("SELECT time FROM ticket_change " 179 "WHERE ticket = % iAND field = 'status' "179 "WHERE ticket = %s AND field = 'status' " 180 180 "ORDER BY time desc LIMIT 1", ticket['id']) 181 181 row = cursor.fetchone() 182 182 if row: write_utctime('COMPLETED', localtime(row['time'])) -
trac/Session.py
old new 103 103 def get_session(self, sid): 104 104 self.sid = sid 105 105 curs = self.db.cursor() 106 curs.execute("SELECT username,var_name,var_value FROM session" 107 " WHERE sid=%s", self.sid)106 curs.execute("SELECT username,var_name,var_value FROM session" 107 " WHERE sid=%s", (self.sid,)) 108 108 rows = curs.fetchall() 109 109 if (not rows # No session data yet 110 110 or rows[0][0] == 'anonymous' # Anon session … … 138 138 self.purge_expired() 139 139 curs.execute('INSERT INTO session(sid,username,var_name,var_value)' 140 140 ' VALUES(%s,%s,%s,%s)', 141 self.sid, self.req.authname, key, val)141 (self.sid, self.req.authname, key, val,)) 142 142 else: 143 143 curs.execute('UPDATE session SET username=%s,var_value=%s' 144 144 ' WHERE sid=%s AND var_name=%s', 145 self.req.authname, val, self.sid, key)145 (self.req.authname, val, self.sid, key,)) 146 146 self.db.commit() 147 147 self.vars[key] = val 148 148 … … 172 172 curs = self.db.cursor() 173 173 curs.execute("DELETE FROM session WHERE sid IN" 174 174 " (SELECT sid FROM session WHERE var_name='mod_time'" 175 " AND var_value < % i)", mintime)175 " AND var_value < %s)", mintime) 176 176 self.db.commit() 177 177 -
trac/Changeset.py
old new 296 296 def get_changeset_info (self, rev): 297 297 cursor = self.db.cursor () 298 298 cursor.execute ('SELECT time, author, message FROM revision ' + 299 'WHERE rev=% d', rev)299 'WHERE rev=%s', (rev,)) 300 300 row = cursor.fetchone() 301 301 if not row: 302 302 raise util.TracError('Changeset %d does not exist.' % rev, … … 306 306 def get_change_info(self, rev): 307 307 cursor = self.db.cursor () 308 308 cursor.execute ('SELECT name, change FROM node_change ' + 309 'WHERE rev=% d', rev)309 'WHERE rev=%s', (rev,)) 310 310 info = [] 311 311 while 1: 312 312 row = cursor.fetchone() -
trac/auth.py
old new 32 32 cookie = req.incookie['trac_auth'].value 33 33 cursor.execute ("SELECT name FROM auth_cookie " 34 34 "WHERE cookie=%s AND ipnr=%s" 35 ,cookie, req.remote_addr) 36 if cursor.rowcount >= 1: 37 self.authname = cursor.fetchone()[0] 35 , (cookie, req.remote_addr,)) 36 row = cursor.fetchone() 37 if row: 38 self.authname = row[0] 38 39 39 40 def login(self, req): 40 41 cursor = self.db.cursor () 41 42 cookie = util.hex_entropy() 42 43 cursor.execute ("INSERT INTO auth_cookie (cookie, name, ipnr, time)" + 43 "VALUES (%s, %s, %s, % d)",44 cookie, req.remote_user, req.remote_addr,45 int(time.time()) );44 "VALUES (%s, %s, %s, %s)", 45 (cookie, req.remote_user, req.remote_addr, 46 int(time.time()),)); 46 47 self.db.commit () 47 48 self.authname = req.remote_user 48 49 req.outcookie['trac_auth'] = cookie … … 51 52 def logout(self): 52 53 cursor = self.db.cursor () 53 54 cursor.execute ("DELETE FROM auth_cookie WHERE name=%s", 54 self.authname)55 (self.authname,)) 55 56 self.db.commit () -
trac/Wiki.py
old new 59 59 if version: 60 60 cursor.execute ('SELECT version, text, readonly FROM wiki ' 61 61 'WHERE name=%s AND version=%s', 62 name, version)62 (name, version,)) 63 63 else: 64 64 cursor.execute ('SELECT version, text, readonly FROM wiki ' 65 'WHERE name=%s ORDER BY version DESC LIMIT 1', name) 65 'WHERE name=%s ORDER BY version DESC LIMIT 1', 66 (name,)) 66 67 row = cursor.fetchone() 67 68 if row: 68 69 self.new = 0 -
trac/Environment.py
old new 35 35 import Mimeview 36 36 import unicodedata 37 37 38 import sqlite 38 from types import * 39 39 40 40 db_version = db_default.db_version 41 41 … … 46 46 A Trac environment consists of a directory structure containing 47 47 among other things: 48 48 * a configuration file. 49 * a sqlitedatabase (stores tickets, wiki pages...)49 * a database (stores tickets, wiki pages...) 50 50 * Project specific templates and wiki macros. 51 51 * wiki and ticket attachments. 52 52 """ 53 def __init__(self, path, create=0 ):53 def __init__(self, path, create=0, db_str=None): 54 54 self.path = path 55 55 if create: 56 self.create( )56 self.create(db_str) 57 57 self.verify() 58 58 self.load_config() 59 59 try: # Use binary I/O on Windows … … 64 64 pass 65 65 self.setup_log() 66 66 self.setup_mimeviewer() 67 self.dbms = self.get_dbms() 67 68 68 69 def verify(self): 69 70 """Verifies that self.path is a compatible trac environment""" … … 71 72 assert fd.read(26) == 'Trac Environment Version 1' 72 73 fd.close() 73 74 74 def get_db_cnx(self): 75 db_str = self.get_config('trac', 'database', 'sqlite:db/trac.db') 76 assert db_str[:7] == 'sqlite:' 77 db_name = os.path.join(self.path, db_str[7:]) 78 if not os.access(db_name, os.F_OK): 79 raise EnvironmentError, 'Database "%s" not found.' % db_name 75 def get_dbms(self): 76 db_str = self.get_config('trac', 'database') 77 if not db_str: 78 return 'sqlite' 79 pos = db_str.find(':') 80 if pos == -1: 81 raise EnvironmentError, 'Connection param must be of form ' \ 82 '(db_module_name):(db_connect_params), the value "%s ' \ 83 'does not match' % db_str 80 84 81 directory = os.path.dirname(db_name) 82 if not os.access(db_name, os.R_OK + os.W_OK) or \ 83 not os.access(directory, os.R_OK + os.W_OK): 84 raise EnvironmentError, \ 85 'The web server user requires read _and_ write permission\n' \ 86 'to the database %s and the directory this file is located in.' % db_name 87 return sqlite.connect(os.path.join(self.path, db_str[7:]), 88 timeout=10000) 85 dbms = db_str[:pos] 86 return dbms 87 88 89 def get_db_cnx(self, check_exists=1): 90 db_str = self.get_config('trac', 91 'database', 92 'sqlite:"db/trac.db",timeout=10000') 93 94 pos = db_str.find(':') 95 if pos == -1: 96 raise EnvironmentError, 'Connection param must be of form ' \ 97 '(db_module_name):(db_connect_params), the value "%s ' \ 98 'does not match' % db_str 99 100 module_name = db_str[:pos] 101 connect_params = db_str[pos+1:].split(',') 102 103 # following is very crude code for parsing the arguments in the 104 # db_connect_params string 105 kargs = {} 106 arg_list = [] 107 for x in connect_params: 108 pos1 = x.find('=') 109 pos2 = x.find('"') 110 pos3 = x.find("'") 111 if pos1 > -1: 112 if pos2 > -1 and pos2 < pos1: 113 arg_list.append(eval(x)) 114 elif pos3 > -1 and pos3 < pos1: 115 arg_list.append(eval(x)) 116 else: 117 name = x[:pos1].strip() 118 value = eval(x[pos1+1:].strip()) 119 kargs[name] = value 120 else: 121 # self.log.debug("Environment - get_db_cnx - x: %s" % x) 122 arg_list.append(eval(x)) 123 args = tuple(arg_list) 124 125 import_str = 'import %s' % module_name 89 126 90 def create(self): 127 # since Trac has a slightly closer relationship with sqlite than 128 # other db's, there's a special case setup here so that when the 129 # path to the sqlite db is specified, its relative to TRAC_ENV 130 if module_name == 'sqlite': 131 db_name = os.path.join(self.path, args[0]) 132 args = list(args) 133 args[0] = '%s' % db_name 134 args = tuple(args) 135 if check_exists == 1 and not os.access(db_name, os.F_OK): 136 raise EnvironmentError, 'Database "%s" not found.' % db_name 137 138 directory = os.path.dirname(db_name) 139 if (check_exists == 1 and not os.access(db_name, os.R_OK + os.W_OK)) \ 140 or not os.access(directory, os.R_OK + os.W_OK): 141 raise EnvironmentError, \ 142 'The web server user requires read _and_ write permission\n' \ 143 'to the database %s and the directory this file is located in.' % db_name 144 145 # handle weird import for PostgreSQL module 146 if module_name.lower() == 'pgsql': 147 import_str = "from pyPgSQL import PgSQL" 148 module_name = "PgSQL" 149 150 exec import_str 151 m = eval(module_name) 152 153 # self.log.debug("Connecting to database module [%s] with: args=%s, " \ 154 # "kargs=%s" % (module_name, str(args), str(kargs))) 155 conn = m.connect(*args, **kargs) 156 return conn 157 158 159 def create(self, db_str=None): 91 160 def _create_file(fname, data=None): 92 161 fd = open(fname, 'w') 93 162 if data: fd.write(data) … … 128 197 """) 129 198 # Create default database 130 199 os.mkdir(os.path.join(self.path, 'db')) 131 cnx = sqlite.connect(os.path.join(self.path, 'db', 'trac.db')) 200 self.load_config() 201 self.setup_default_config() 202 if db_str: 203 self.cfg.set('trac', 'database', db_str) 204 self.save_config() 205 cnx = self.get_db_cnx(check_exists=0) 132 206 cursor = cnx.cursor() 133 cursor.execute(db_default.schema) 207 208 # get right db schema based on db_str 209 dbschema = db_default.schema 210 if db_str: 211 pos = db_str.find(':') 212 if pos == -1: 213 raise EnvironmentError, 'Connection param must be of form ' \ 214 '(db_module_name):(db_connect_params), the value "%s ' \ 215 'does not match' % db_str 216 module_name = db_str[:pos] 217 if module_name.lower() == "pgsql": 218 dbschema = db_default.schema_pgsql 219 cursor.execute(dbschema) 134 220 cnx.commit() 135 221 136 222 def insert_default_data(self): … … 138 224 if v == None: 139 225 return 'NULL' 140 226 else: 141 return '"%s"' % v 227 prepped = v 228 if type(v) is StringType: 229 prepped = prepped.replace("'", "''") 230 return "'%s'" % prepped 142 231 cnx = self.get_db_cnx() 143 232 cursor = cnx.cursor() 144 233 … … 149 238 values = ','.join(map(prep_value, row)) 150 239 sql = "INSERT INTO %s (%s) VALUES(%s);" % (table, cols, values) 151 240 cursor.execute(sql) 241 cnx.commit() 242 243 def setup_default_config(self): 152 244 for s,n,v in db_default.default_config: 153 245 if not self.cfg.has_section(s): 154 246 self.cfg.add_section(s) 155 247 self.cfg.set(s, n, v) 156 self.save_config()157 cnx.commit()158 248 159 249 def get_version(self): 160 250 cnx = self.get_db_cnx() … … 218 308 cursor = cnx.cursor() 219 309 cursor.execute('SELECT filename,description,type,size,time,author,ipnr ' 220 310 'FROM attachment ' 221 'WHERE type=%s AND id=%s ORDER BY time', type, id)311 'WHERE type=%s AND id=%s ORDER BY time', (type, id,)) 222 312 return cursor.fetchall() 223 313 224 314 def get_attachments_hdf(self, cnx, type, id, hdf, prefix): … … 290 380 291 381 def backup(self, dest=None): 292 382 """Simple SQLite-specific backup. Copy the database file.""" 293 db_str = self.get_config('trac', 'database', 'sqlite:db/trac.db') 383 db_str = self.get_config('trac', 'database', 384 'sqlite:"db/trac.db",timeout=10000') 294 385 if db_str[:7] != 'sqlite:': 295 raise EnvironmentError, 'Can only backup sqlite databases' 386 print 'BACKUP FAILED: Can only backup sqlite databases.' 387 # TODO: should probably ask if they want to continue 388 # or at least handle this better by shelling out to backup 389 # other dbs like pgsql... 390 return 296 391 db_name = os.path.join(self.path, db_str[7:]) 297 392 if not dest: 298 393 dest = '%s.%i.bak' % (db_name, self.get_version()) … … 321 416 err = 'No upgrade module for version %i (%s.py)' % (i, upg) 322 417 raise EnvironmentError, err 323 418 d.do_upgrade(self, i, cursor) 324 cursor.execute("UPDATE system SET value=% iWHERE "419 cursor.execute("UPDATE system SET value=%s WHERE " 325 420 "name='database_version'", db_default.db_version) 326 421 self.log.info('Upgraded db version from %d to %d', 327 422 dbver, db_default.db_version) 328 423 cnx.commit() 424 print 'Upgrade succeeded.' 329 425 return 1 -
trac/Ticket.py
old new 73 73 self[Ticket.std_fields[i]] = row[i] or '' 74 74 75 75 cursor = db.cursor () 76 cursor.execute('SELECT name,value FROM ticket_custom WHERE ticket=% i', id)76 cursor.execute('SELECT name,value FROM ticket_custom WHERE ticket=%s', id) 77 77 rows = cursor.fetchall() 78 78 if rows: 79 79 for r in rows: … … 93 93 if not dict.has_key(name): 94 94 self[name] = '0' 95 95 96 def insert(self, db ):96 def insert(self, db, dbms): 97 97 """Add ticket to database""" 98 98 cursor = db.cursor() 99 99 assert not self.has_key('id') … … 106 106 std_fields = filter(lambda n: n[:7] != 'custom_', self.keys()) 107 107 custom_fields = filter(lambda n: n[:7] == 'custom_', self.keys()) 108 108 std_values = map(lambda n, self=self: self[n], std_fields) 109 109 110 nstr = string.join(std_fields, ',') 110 111 vstr = ('%s,' * len(std_fields))[:-1] 111 cursor.execute('INSERT INTO ticket (%s) VALUES (%s)' % (nstr, vstr),112 cursor.execute('INSERT INTO ticket (%s) VALUES (%s)' % (nstr, vstr), 112 113 *std_values) 113 id = db.db.sqlite_last_insert_rowid() 114 115 if dbms == 'pgsql': 116 cursor.execute("SELECT id FROM ticket " \ 117 "WHERE id = CURRVAL('ticket_id_seq')") 118 id = cursor.fetchone()[0] 119 else: # sqlite way 120 id = db.db.sqlite_last_insert_rowid() 121 114 122 for name in custom_fields: 115 123 cursor.execute('INSERT INTO ticket_custom(ticket,name,value)' 116 ' VALUES(% d, %s, %s)', id, name[7:], self[name])124 ' VALUES(%s, %s, %s)', id, name[7:], self[name]) 117 125 db.commit() 118 126 self['id'] = id 119 127 self._forget_changes() … … 146 154 for name in self._old.keys(): 147 155 if name[:7] == 'custom_': 148 156 fname = name[7:] 149 cursor.execute('REPLACE INTO ticket_custom(ticket,name,value)' 157 # some dbms's don't support REPLACE INTO, so we have to do 158 # this detection and delete 159 cursor.execute("SELECT * FROM ticket_custom " 160 "WHERE ticket=%s and name=%s" 161 , id, fname) 162 if cursor.fetchone() is not None: 163 cursor.execute("DELETE FROM ticket_custom " 164 "WHERE ticket=%s and name=%s" 165 , id, fname) 166 cursor.execute('INSERT INTO ticket_custom(ticket,name,value)' 150 167 ' VALUES(%s, %s, %s)', id, fname, self[name]) 151 168 else: 152 169 fname = name 153 cursor.execute ('UPDATE ticket SET %s=%s WHERE id=%s',154 fname, self[name], id)170 sql = "UPDATE ticket SET %s='%s' WHERE id=%s" \ 171 % (fname, self[name], id) 155 172 173 cursor.execute (sql) 174 156 175 cursor.execute ('INSERT INTO ticket_change ' 157 176 '(ticket, time, author, field, oldvalue, newvalue) ' 158 177 'VALUES (%s, %s, %s, %s, %s, %s)', … … 171 190 """Returns the changelog as a list of dictionaries""" 172 191 cursor = db.cursor() 173 192 if when: 174 cursor.execute( 'SELECT time, author, field, oldvalue, newvalue '175 'FROM ticket_change '176 'WHERE ticket=%s AND time=%s'177 'UNION '178 'SELECT time, author, "attachment", null, filename '179 'FROM attachment '180 'WHERE id=%s AND time=%s '181 'ORDER BY time', self['id'], when, self['id'], when)193 cursor.execute("SELECT time, author, field, oldvalue, newvalue " 194 "FROM ticket_change " 195 "WHERE ticket=%s AND time=%s" 196 "UNION " 197 "SELECT time, author, 'attachment', null, filename " 198 "FROM attachment " 199 "WHERE id=%s AND time=%s " 200 "ORDER BY time", self['id'], when, self['id'], when) 182 201 else: 183 cursor.execute( 'SELECT time, author, field, oldvalue, newvalue '184 'FROM ticket_change '185 'WHERE ticket=%s '186 'UNION '187 'SELECT time, author, "attachment", null,filename '188 'FROM attachment '189 'WHERE id = %s '190 'ORDER BY time', self['id'], self['id'])202 cursor.execute("SELECT time, author, field, oldvalue, newvalue " 203 "FROM ticket_change " 204 "WHERE ticket=%s " 205 "UNION " 206 "SELECT time, author, 'attachment', null,filename " 207 "FROM attachment " 208 "WHERE id = %s " 209 "ORDER BY time", self['id'], self['id']) 191 210 log = [] 192 211 while 1: 193 212 row = cursor.fetchone() … … 283 302 owner = cursor.fetchone()[0] 284 303 ticket['owner'] = owner 285 304 286 tktid = ticket.insert(self.db) 305 dbms = self.env.get_dbms() 306 tktid = ticket.insert(self.db, dbms) 287 307 288 308 # Notify 289 309 tn = TicketNotifyEmail(self.env) -
trac/WikiFormatter.py
old new 130 130 def _changesethref_formatter(self, match, fullmatch): 131 131 number = int(match[1:-1]) 132 132 cursor = self.db.cursor () 133 cursor.execute('SELECT message FROM revision WHERE rev=% d', number)133 cursor.execute('SELECT message FROM revision WHERE rev=%s', number) 134 134 row = cursor.fetchone () 135 135 if not row: 136 136 return '[<a class="missing" href="%s">%d</a>]' % (self._href.changeset(number), number) -
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 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()
