PostgresqlPatch: pgsql_patch_03.diff
| File pgsql_patch_03.diff, 44.4 kB (added by brad, 4 years ago) |
|---|
-
scripts/trac-admin
old new 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 … … 448 448 449 449 ## Initenv 450 450 _help_initenv = [('initenv', 'Create and initialize a new environment interactively'), 451 ('initenv <projectname> <repospath> <templatepath> ',451 ('initenv <projectname> <repospath> <templatepath> <dbms> [dbms options]', 452 452 'Create and initialize a new environment from arguments')] 453 453 454 454 def do_initdb(self, line): … … 481 481 dt = trac.siteconfig.__default_templates_dir__ 482 482 prompt = 'Templates directory [%s]> ' % dt 483 483 returnvals.append(raw_input(prompt) or dt) 484 print 485 print " Please enter the database in which you wish to store Trac data." 486 print " Default is 'sqlite', but others are supported:" 487 print " 'sqlite' - SQLite http://www.sqlite.org" 488 print " 'pgsql' - PostgreSQL http://www.postgresql.org" 489 print 490 ddb = "sqlite" 491 prompt = 'database system [%s]> ' % ddb 492 dbms = raw_input(prompt) or ddb 493 returnvals.append(dbms) 494 495 # PostgreSQL - additional questions 496 if dbms == "pgsql": 497 print 498 print " Please enter the host of your PostgreSQL database." 499 print " Default is 'localhost'" 500 print 501 host = "localhost" 502 prompt = "PostgreSQL host [%s]> " % host 503 returnvals.append(raw_input(prompt) or host) 504 505 print 506 print " Please enter the port of your PostgreSQL database." 507 print " Default is '5432'" 508 print 509 port = "5432" 510 prompt = "PostgreSQL port [%s]> " % port 511 returnvals.append(raw_input(prompt) or port) 512 513 print 514 print " Please enter the name of your PostgreSQL database." 515 print " Default is 'trac'" 516 print " Note: This database should not exist, as trac-admin will" \ 517 " attempt to create it." 518 print 519 name = "trac" 520 prompt = "PostgreSQL host [%s]> " % name 521 returnvals.append(raw_input(prompt) or name) 522 523 print 524 print " Please enter the user of your PostgreSQL database." 525 print " Default is 'trac'" 526 print 527 user = "trac" 528 prompt = "PostgreSQL host [%s]> " % user 529 returnvals.append(raw_input(prompt) or user) 530 531 print 532 print " Please enter the password of your PostgreSQL database." 533 print " Default is 'trac'" 534 print 535 password = "trac" 536 prompt = "PostgreSQL host [%s]> " % password 537 returnvals.append(raw_input(prompt) or password) 538 484 539 return returnvals 485 540 486 541 def do_initenv(self, line): … … 491 546 project_name = None 492 547 repository_dir = None 493 548 templates_dir = None 549 db_str = None 494 550 if len(arg) == 1: 495 551 returnvals = self.get_initenv_args() 496 552 project_name = returnvals[0] 497 553 repository_dir = returnvals[1] 498 554 templates_dir = returnvals[2] 499 elif len(arg)!= 3: 555 db_str = returnvals[3] 556 elif len(arg) < 4: 500 557 print 'Wrong number of arguments to initenv %d' % len(arg) 501 558 return 502 559 else: 503 560 project_name = arg[0] 504 561 repository_dir = arg[1] 505 562 templates_dir = arg[2] 563 db_str = arg[3] 564 565 # postgres-specific stuff 566 if db_str.lower() == "pgsql": 567 if len(arg) == 1: 568 host = returnvals[4] 569 port = returnvals[5] 570 database = returnvals[6] 571 user = returnvals[7] 572 password = returnvals[8] 573 elif len(arg) != 9: 574 print 'Wrong number of arguments to initenv %d' % len(arg) 575 print 'For PostgreSQL (after pgsql): <host> <port> <database>' \ 576 ' <user> <password>' 577 return 578 else: 579 host = arg[4] 580 port = arg[5] 581 database = arg[6] 582 user = arg[7] 583 password = arg[8] 584 db_str = "pgsql:\"\",host='%s:%s',database='%s',user='%s'," \ 585 "password='%s'" \ 586 % (host, port, database, user, password) 587 createdb_str = "createdb --host=%s --port=%s --owner=%s " \ 588 "--username=%s %s\n" \ 589 % (host, port, user, user, database) 590 print createdb_str 591 try: 592 # TODO: this is not cross-platform. 593 # for Windows, look at win32pipe.popen() 594 os.popen(createdb_str) 595 except Exception, e: 596 print "Error creating PostgreSQL database: %s" % e 597 print "command: %s" % createdb_str 598 506 599 from svn import util, repos, core 507 600 core.apr_initialize() 508 601 pool = core.svn_pool_create(None) … … 521 614 return 522 615 try: 523 616 print 'Creating and Initializing Project' 524 self.env_create( )617 self.env_create(db_str) 525 618 cnx = self.__env.get_db_cnx() 526 619 print ' Inserting default data' 527 620 self.__env.insert_default_data() … … 685 778 data = data.replace("'", "''") # Escape ' for safe SQL 686 779 f.close() 687 780 688 sql = ("INSERT INTO wiki('version','name','time','author','ipnr','text') " 689 " SELECT 1+ifnull(max(version),0),'%(title)s','%(time)s','%(author)s'," 690 " '%(ipnr)s','%(text)s' FROM wiki WHERE name='%(title)s'" 781 sql = ("INSERT INTO wiki(version,name,time,author,ipnr,text) " 782 " SELECT 1+COALESCE(max(version),0),'%(title)s','%(time)s'," 783 "'%(author)s','%(ipnr)s','%(text)s' " 784 "FROM wiki WHERE name='%(title)s'" 691 785 % {'title':title, 692 786 'time':int(time.time()), 693 787 'author':'trac', … … 998 1092 print "Upgrade: Backup of old database saved in " \ 999 1093 "%s/db/trac.db.%i.bak" % (self.envname, curr) 1000 1094 else: 1001 print "Upgrade: Backup disabled. Non-exist ant warranty voided."1095 print "Upgrade: Backup disabled. Non-existent warranty voided." 1002 1096 self.__env.upgrade(do_backup) 1003 1097 else: 1004 1098 print "Upgrade: Database is up to date, no upgrade necessary." -
trac/db_default.py
old new 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 ) WITHOUT OIDS; 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 ) WITHOUT OIDS; 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 ) WITHOUT OIDS; 200 201 CREATE TABLE enum ( 202 type text, 203 name text, 204 value text, 205 CONSTRAINT enum_pkey PRIMARY KEY(name,type) 206 ) WITHOUT OIDS; 207 208 CREATE TABLE system ( 209 name text, 210 value text, 211 CONSTRAINT system_pkey PRIMARY KEY(name) 212 ) WITHOUT OIDS; 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 ) WITHOUT OIDS; 221 222 CREATE TABLE ticket ( 223 id integer, 224 time integer, -- the time it was created 225 changetime integer, 226 component text, 227 severity text, 228 priority text, 229 owner text, -- who is this ticket assigned to 230 reporter text, 231 cc text, -- email addresses to notify 232 url text, -- url related to this ticket 233 version text, -- 234 milestone text, -- 235 status text, 236 resolution text, 237 summary text, -- one-line summary 238 description text, -- problem description (long) 239 keywords text, 240 CONSTRAINT ticket_pkey PRIMARY KEY(id) 241 ) WITHOUT OIDS; 242 243 CREATE TABLE ticket_change ( 244 ticket integer, 245 time integer, 246 author text, 247 field text, 248 oldvalue text, 249 newvalue text, 250 CONSTRAINT ticket_change_pkey PRIMARY KEY(ticket, time, field) 251 ) WITHOUT OIDS; 252 253 CREATE TABLE ticket_custom ( 254 ticket integer, 255 name text, 256 value text, 257 CONSTRAINT ticket_custom_pkey PRIMARY KEY(ticket,name) 258 ) WITHOUT OIDS; 259 260 CREATE TABLE report ( 261 id integer, 262 author text, 263 title text, 264 sql text, 265 description text, 266 CONSTRAINT report_pkey PRIMARY KEY(id) 267 ) WITHOUT OIDS; 268 269 CREATE TABLE permission ( 270 username text, -- 271 action text, -- allowable activity 272 CONSTRAINT permission_pkey PRIMARY KEY(username,action) 273 ) WITHOUT OIDS; 274 275 CREATE TABLE component ( 276 name text, 277 owner text, 278 CONSTRAINT component_pkey PRIMARY KEY(name) 279 ) WITHOUT OIDS; 280 281 CREATE TABLE milestone ( 282 name text, 283 due integer, -- Due date/time 284 completed integer, -- Completed date/time 285 description text, 286 CONSTRAINT milestone_pkey PRIMARY KEY(name) 287 ) WITHOUT OIDS; 288 289 CREATE TABLE version ( 290 name text, 291 time integer, 292 CONSTRAINT version_pkey PRIMARY KEY(name) 293 ) WITHOUT OIDS; 294 295 CREATE TABLE wiki ( 296 name text, 297 version integer, 298 time integer, 299 author text, 300 ipnr text, 301 text text, 302 comment text, 303 readonly integer, 304 CONSTRAINT wiki_pkey PRIMARY KEY(name,version) 305 ) WITHOUT OIDS; 306 307 CREATE TABLE attachment ( 308 type text, 309 id text, 310 filename text, 311 size integer, 312 time integer, 313 description text, 314 author text, 315 ipnr text, 316 CONSTRAINT attachment_pkey PRIMARY KEY(type,id,filename) 317 ) WITHOUT OIDS; 318 319 CREATE TABLE session ( 320 sid text, 321 username text, 322 var_name text, 323 var_value text, 324 CONSTRAINT session_pkey PRIMARY KEY(sid,var_name) 325 ) WITHOUT OIDS; 326 327 """ 328 177 329 ## 178 330 ## Default Reports 179 331 ## … … 413 565 (('trac', 'htdocs_location', '/trac/'), 414 566 ('trac', 'repository_dir', '/var/svn/myrep'), 415 567 ('trac', 'templates_dir', '/usr/lib/trac/templates'), 416 ('trac', 'database', 'sqlite: db/trac.db'),568 ('trac', 'database', 'sqlite:"db/trac.db",timeout=10000'), 417 569 ('trac', 'default_charset', 'iso-8859-15'), 418 570 ('logging', 'log_type', 'none'), 419 571 ('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/Report.py
old new 140 140 141 141 # FIXME: fetchall should probably not be used. 142 142 info = cursor.fetchall() 143 cols = cursor. rs.col_defs143 cols = cursor.description 144 144 # Escape the values so that they are safe to have as html parameters 145 145 #info = map(lambda row: map(lambda x: escape(x), row), info) 146 146 -
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/util.py
old new 329 329 d[k] = v 330 330 return d 331 331 332 def get_next_key(db, table, key_column='id', cursor=None): 333 '''Provides a very basic way of getting the next available key for a particular table.''' 332 334 335 # the currently implementation here is a hack, this should be upgraded to 336 # use something like a separate table to maintain next_key references, but 337 # even this hack should work fine unless millions of records are getting 338 # inserted simultaneously 339 340 if cursor == None: 341 cursor = db.cursor() 342 cursor.execute('select max(%s) + 1 as next_key from %s' % (key_column, table)) 343 row = cursor.fetchone() 344 next_key = row[0] 345 346 if next_key == None: 347 next_key = 1 348 349 return next_key 350 333 351 if __name__ == '__main__ ': 334 352 pass 335 353 #print pre -
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 -
trac/auth.py
old new 40 40 cursor = self.db.cursor () 41 41 cookie = util.hex_entropy() 42 42 cursor.execute ("INSERT INTO auth_cookie (cookie, name, ipnr, time)" + 43 "VALUES (%s, %s, %s, % d)",43 "VALUES (%s, %s, %s, %s)", 44 44 cookie, req.remote_user, req.remote_addr, 45 45 int(time.time())); 46 46 self.db.commit () -
trac/Environment.py
old new 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) == str: 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() … … 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 35 35 36 36 37 37 class Ticket(UserDict): 38 std_fields = [' time', 'component', 'severity', 'priority', 'milestone',38 std_fields = ['id', 'time', 'component', 'severity', 'priority', 'milestone', 39 39 'reporter', 'owner', 'cc', 'url', 'version', 'status', 'resolution', 40 40 'keywords', 'summary', 'description'] 41 41 … … 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: … … 96 96 def insert(self, db): 97 97 """Add ticket to database""" 98 98 cursor = db.cursor() 99 assert not self.has_key('id')99 # assert not self.has_key('id') 100 100 101 101 # Add a timestamp 102 102 now = int(time.time()) 103 103 self['time'] = now 104 104 self['changetime'] = now 105 105 106 self['id'] = util.get_next_key(db, 'ticket') 107 106 108 std_fields = filter(lambda n: n[:7] != 'custom_', self.keys()) 107 109 custom_fields = filter(lambda n: n[:7] == 'custom_', self.keys()) 108 110 std_values = map(lambda n, self=self: self[n], std_fields) 111 109 112 nstr = string.join(std_fields, ',') 110 113 vstr = ('%s,' * len(std_fields))[:-1] 111 cursor.execute('INSERT INTO ticket (%s) VALUES (%s)' % (nstr, vstr),114 cursor.execute('INSERT INTO ticket (%s) VALUES (%s)' % (nstr, vstr), 112 115 *std_values) 113 id = db.db.sqlite_last_insert_rowid()116 # id = db.db.sqlite_last_insert_rowid() 114 117 for name in custom_fields: 115 118 cursor.execute('INSERT INTO ticket_custom(ticket,name,value)' 116 ' VALUES(% d, %s, %s)', id, name[7:], self[name])119 ' VALUES(%s, %s, %s)', self['id'], name[7:], self[name]) 117 120 db.commit() 118 self['id'] = id119 121 self._forget_changes() 120 return id122 return self['id'] 121 123 122 124 def save_changes(self, db, author, comment, when = 0): 123 125 """Store ticket changes in the database. … … 171 173 """Returns the changelog as a list of dictionaries""" 172 174 cursor = db.cursor() 173 175 if when: 174 cursor.execute( 'SELECT time, author, field, oldvalue, newvalue '
