PostgresqlPatch: pgsql_patch_03.diff

File pgsql_patch_03.diff, 44.4 kB (added by brad, 4 years ago)

more modules done, trac-admin upgrade

  • scripts/trac-admin

    old new  
    9292            return 0 
    9393        return 1 
    9494         
    95     def env_create(self): 
     95    def env_create(self, db_str): 
    9696        try: 
    97             self.__env = trac.Environment.Environment (self.envname, create=1
     97            self.__env = trac.Environment.Environment (self.envname, 1, db_str
    9898            return self.__env 
    9999        except Exception, e: 
    100100            print 'Failed to create environment.', e 
     
    448448 
    449449    ## Initenv 
    450450    _help_initenv = [('initenv', 'Create and initialize a new environment interactively'), 
    451                      ('initenv <projectname> <repospath> <templatepath>', 
     451                     ('initenv <projectname> <repospath> <templatepath> <dbms> [dbms options]', 
    452452                      'Create and initialize a new environment from arguments')] 
    453453 
    454454    def do_initdb(self, line): 
     
    481481        dt = trac.siteconfig.__default_templates_dir__ 
    482482        prompt = 'Templates directory [%s]> ' % dt 
    483483        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             
    484539        return returnvals 
    485540          
    486541    def do_initenv(self, line): 
     
    491546        project_name = None 
    492547        repository_dir = None 
    493548        templates_dir = None 
     549        db_str = None 
    494550        if len(arg) == 1: 
    495551            returnvals = self.get_initenv_args() 
    496552            project_name = returnvals[0] 
    497553            repository_dir = returnvals[1] 
    498554            templates_dir = returnvals[2] 
    499         elif len(arg)!= 3: 
     555            db_str = returnvals[3] 
     556        elif len(arg) < 4: 
    500557            print 'Wrong number of arguments to initenv %d' % len(arg) 
    501558            return 
    502559        else: 
    503560            project_name = arg[0] 
    504561            repository_dir = arg[1] 
    505562            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         
    506599        from svn import util, repos, core 
    507600        core.apr_initialize() 
    508601        pool = core.svn_pool_create(None) 
     
    521614            return 
    522615        try: 
    523616            print 'Creating and Initializing Project' 
    524             self.env_create(
     617            self.env_create(db_str
    525618            cnx = self.__env.get_db_cnx() 
    526619            print ' Inserting default data' 
    527620            self.__env.insert_default_data() 
     
    685778        data = data.replace("'", "''") # Escape ' for safe SQL 
    686779        f.close() 
    687780         
    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'"  
    691785               % {'title':title, 
    692786                  'time':int(time.time()), 
    693787                  'author':'trac', 
     
    9981092                    print "Upgrade: Backup of old database saved in " \ 
    9991093                          "%s/db/trac.db.%i.bak" % (self.envname, curr) 
    10001094                else: 
    1001                     print "Upgrade: Backup disabled. Non-existant warranty voided." 
     1095                    print "Upgrade: Backup disabled. Non-existent warranty voided." 
    10021096                self.__env.upgrade(do_backup) 
    10031097            else: 
    10041098                print "Upgrade: Database is up to date, no upgrade necessary." 
  • trac/db_default.py

    old new  
    174174CREATE INDEX session_idx        ON session(sid,var_name); 
    175175""" 
    176176 
     177schema_pgsql = """ 
     178CREATE 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 
     186CREATE 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 
     193CREATE 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 
     201CREATE TABLE enum ( 
     202        type            text, 
     203        name            text, 
     204        value           text, 
     205        CONSTRAINT enum_pkey PRIMARY KEY(name,type) 
     206) WITHOUT OIDS; 
     207 
     208CREATE TABLE system ( 
     209        name            text, 
     210        value           text, 
     211        CONSTRAINT system_pkey PRIMARY KEY(name) 
     212) WITHOUT OIDS; 
     213 
     214CREATE 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 
     222CREATE 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 
     243CREATE 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 
     253CREATE 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 
     260CREATE 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 
     269CREATE TABLE permission ( 
     270        username        text,           --  
     271        action          text,           -- allowable activity 
     272        CONSTRAINT permission_pkey PRIMARY KEY(username,action) 
     273) WITHOUT OIDS; 
     274 
     275CREATE TABLE component ( 
     276         name            text, 
     277         owner           text, 
     278         CONSTRAINT component_pkey PRIMARY KEY(name) 
     279) WITHOUT OIDS; 
     280 
     281CREATE 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 
     289CREATE TABLE version ( 
     290         name            text, 
     291         time            integer, 
     292         CONSTRAINT version_pkey PRIMARY KEY(name) 
     293) WITHOUT OIDS; 
     294 
     295CREATE 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 
     307CREATE 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 
     319CREATE 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 
    177329## 
    178330## Default Reports 
    179331## 
     
    413565 (('trac', 'htdocs_location', '/trac/'), 
    414566  ('trac', 'repository_dir', '/var/svn/myrep'), 
    415567  ('trac', 'templates_dir', '/usr/lib/trac/templates'), 
    416   ('trac', 'database', 'sqlite:db/trac.db'), 
     568  ('trac', 'database', 'sqlite:"db/trac.db",timeout=10000'), 
    417569  ('trac', 'default_charset', 'iso-8859-15'), 
    418570  ('logging', 'log_type', 'none'), 
    419571  ('logging', 'log_file', 'trac.log'), 
  • trac/Milestone.py

    old new  
    157157        cursor = self.db.cursor() 
    158158        self.log.debug("Creating new milestone '%s'" % name) 
    159159        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, 
    161161                       description) 
    162162        self.db.commit() 
    163163        self.req.redirect(self.env.href.milestone(name)) 
     
    196196                          'associated with milestone %s' % id) 
    197197            cursor.execute("UPDATE ticket SET milestone = %s " 
    198198                           "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", 
    201201                           name, due, completed, description, id) 
    202202            self.db.commit() 
    203203            self.req.redirect(self.env.href.milestone(name)) 
     
    209209        groups = [] 
    210210        if by in ['status', 'resolution', 'severity', 'priority']: 
    211211            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) 
    213213        elif by in ['component', 'milestone', 'version']: 
    214214            cursor.execute("SELECT name FROM %s " 
    215                            "WHERE IFNULL(name,'') != '' ORDER BY name" % by) 
     215                           "WHERE COALESCE(name,'') != '' ORDER BY name" % by) 
    216216        elif by == 'owner': 
    217217            cursor.execute("SELECT DISTINCT owner AS name FROM ticket " 
    218218                           "ORDER BY owner") 
  • trac/Search.py

    old new  
    117117 
    118118        cursor = self.db.cursor () 
    119119 
     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 
    120129        q = [] 
    121130        if changeset: 
    122131            q.append('SELECT 1 as type, message AS title, message, author, ' 
    123                      ' \'\' AS keywords, rev AS data, time,0 AS ver' 
     132                     ' \'\' AS keywords, %s AS data, time,0 AS ver' 
    124133                     ' FROM revision WHERE %s OR %s' %  
    125                      (self.query_to_sql(query, 'message'), 
     134                     (data_changeset, 
     135                      self.query_to_sql(query, 'message'), 
    126136                      self.query_to_sql(query, 'author'))) 
    127137        if tickets: 
    128138            q.append('SELECT DISTINCT 2 as type, a.summary AS title, ' 
    129139                     ' 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'), 
    135146                       self.query_to_sql(query, 'summary'), 
    136147                       self.query_to_sql(query, 'keywords'), 
    137148                       self.query_to_sql(query, 'description'), 
  • trac/Query.py

    old new  
    154154        sql.append("\nFROM ticket") 
    155155        for k in [k for k in cols if k in custom_fields]: 
    156156           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)) 
    158158 
    159159        for col in [c for c in ['status', 'resolution', 'priority', 'severity'] 
    160160                    if c == self.order or c == self.group]: 
    161161            sql.append("\n  LEFT OUTER JOIN (SELECT name AS %s_name, " \ 
    162162                                            "value AS %s_value " \ 
    163                                             "FROM enum WHERE type='%s')" \ 
     163                                            "FROM enum WHERE type='%s') e" \ 
    164164                       " ON %s_name=%s" % (col, col, col, col, col)) 
    165165        for col in [c for c in ['milestone', 'version'] 
    166166                    if c == self.order or c == self.group]: 
    167167            time_col = col == 'milestone' and 'due' or 'time' 
    168168            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" \ 
    170170                       " ON %s_name=%s" % (col, time_col, col, col, col, col)) 
    171171 
    172172        def get_constraint_sql(name, value, mode, neg): 
    173173            value = sql_escape(value[len(mode and '!' or '' + mode):]) 
    174174            if mode == '~' and value: 
    175                 return "IFNULL(%s,'') %sLIKE '%%%s%%'" % ( 
     175                return "COALESCE(%s,'') %sLIKE '%%%s%%'" % ( 
    176176                       name, neg and 'NOT ' or '', value) 
    177177            elif mode == '^' and value: 
    178                 return "IFNULL(%s,'') %sLIKE '%s%%'" % ( 
     178                return "COALESCE(%s,'') %sLIKE '%s%%'" % ( 
    179179                       name, neg and 'NOT ' or '', value) 
    180180            elif mode == '$' and value: 
    181                 return "IFNULL(%s,'') %sLIKE '%%%s'" % ( 
     181                return "COALESCE(%s,'') %sLIKE '%%%s'" % ( 
    182182                       name, neg and 'NOT ' or '', value) 
    183183            elif mode == '': 
    184                 return "IFNULL(%s,'')%s='%s'" % (name, neg and '!' or '', value) 
     184                return "COALESCE(%s,'')%s='%s'" % (name, neg and '!' or '', value) 
    185185 
    186186        clauses = [] 
    187187        for k, v in self.constraints.items(): 
     
    195195            # Special case for exact matches on multiple values 
    196196            if not mode and len(v) > 1: 
    197197                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)) 
    199199            elif len(v) > 1: 
    200200                constraint_sql = [get_constraint_sql(k, val, mode, neg) for val in v] 
    201201                if neg: 
     
    214214        if self.group and self.group != self.order: 
    215215            order_cols.insert(0, (self.group, self.groupdesc)) 
    216216        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) 
    219225            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) 
    221230            if col in ['status', 'resolution', 'priority', 'severity']: 
    222231                if desc: 
    223232                    sql.append("%s_value DESC" % col) 
     
    225234                    sql.append("%s_value" % col) 
    226235            elif col in ['milestone', 'version']: 
    227236                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" 
    229238                               % (col, col, col)) 
    230239                else: 
    231                     sql.append("IFNULL(%s_time,0)=0,%s_time,%s" 
     240                    sql.append("COALESCE(%s_time,0)=0,%s_time,%s" 
    232241                               % (col, col, col)) 
    233242            else: 
    234243                if desc: 
  • trac/Report.py

    old new  
    140140 
    141141        # FIXME: fetchall should probably not be used. 
    142142        info = cursor.fetchall() 
    143         cols = cursor.rs.col_defs 
     143        cols = cursor.description 
    144144        # Escape the values so that they are safe to have as html parameters 
    145145        #info = map(lambda row: map(lambda x: escape(x), row), info) 
    146146 
  • trac/sync.py

    old new  
    3535              (util.SVN_VER_MAJOR, util.SVN_VER_MINOR, util.SVN_VER_MICRO) 
    3636 
    3737    cursor = db.cursor() 
    38     cursor.execute('SELECT ifnull(max(rev), 0) FROM revision') 
     38    cursor.execute('SELECT COALESCE(max(rev), 0) FROM revision') 
    3939    youngest_stored =  int(cursor.fetchone()[0]) 
    4040    max_rev = fs.youngest_rev(fs_ptr, pool) 
    4141    num = max_rev - youngest_stored 
  • trac/util.py

    old new  
    329329        d[k] = v 
    330330    return d 
    331331 
     332def 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.''' 
    332334 
     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 
    333351if __name__ == '__main__ ': 
    334352    pass 
    335353    #print pre 
  • trac/Roadmap.py

    old new  
    4444        if show == 'all': 
    4545            icalhref += '&show=all' 
    4646            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" 
    4949        else: 
    5050            self.req.hdf.setValue('roadmap.showall', '1') 
    5151            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" 
    5555 
    5656        if self.req.authname and self.req.authname != 'anonymous': 
    5757            icalhref += '&user=' + self.req.authname 
  • trac/auth.py

    old new  
    4040        cursor = self.db.cursor () 
    4141        cookie = util.hex_entropy() 
    4242        cursor.execute ("INSERT INTO auth_cookie (cookie, name, ipnr, time)" + 
    43                         "VALUES (%s, %s, %s, %d)", 
     43                        "VALUES (%s, %s, %s, %s)", 
    4444                        cookie, req.remote_user, req.remote_addr, 
    4545                        int(time.time())); 
    4646        self.db.commit () 
  • trac/Environment.py

    old new  
    4646    A Trac environment consists of a directory structure containing 
    4747    among other things: 
    4848     * a configuration file. 
    49      * a sqlite database (stores tickets, wiki pages...) 
     49     * a database (stores tickets, wiki pages...) 
    5050     * Project specific templates and wiki macros. 
    5151     * wiki and ticket attachments. 
    5252    """ 
    53     def __init__(self, path, create=0): 
     53    def __init__(self, path, create=0, db_str=None): 
    5454        self.path = path 
    5555        if create: 
    56             self.create(
     56            self.create(db_str
    5757        self.verify() 
    5858        self.load_config() 
    5959        try: # Use binary I/O on Windows 
     
    6464            pass 
    6565        self.setup_log() 
    6666        self.setup_mimeviewer() 
     67        self.dbms = self.get_dbms() 
    6768 
    6869    def verify(self): 
    6970        """Verifies that self.path is a compatible trac environment""" 
     
    7172        assert fd.read(26) == 'Trac Environment Version 1' 
    7273        fd.close() 
    7374 
    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 
    8084         
    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 
    89126 
    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): 
    91160        def _create_file(fname, data=None): 
    92161            fd = open(fname, 'w') 
    93162            if data: fd.write(data) 
     
    128197""") 
    129198        # Create default database 
    130199        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) 
    132206        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) 
    134220        cnx.commit() 
    135221 
    136222    def insert_default_data(self): 
     
    138224            if v == None: 
    139225                return 'NULL' 
    140226            else: 
    141                 return '"%s"' % v 
     227                prepped = v 
     228                if type(v) == str: 
     229                    prepped = prepped.replace("'", "''") 
     230                return "'%s'" % prepped 
    142231        cnx = self.get_db_cnx() 
    143232        cursor = cnx.cursor() 
    144233         
     
    149238                values = ','.join(map(prep_value, row)) 
    150239                sql = "INSERT INTO %s (%s) VALUES(%s);" % (table, cols, values) 
    151240                cursor.execute(sql) 
     241        cnx.commit() 
     242 
     243    def setup_default_config(self): 
    152244        for s,n,v in db_default.default_config: 
    153245            if not self.cfg.has_section(s): 
    154246                self.cfg.add_section(s) 
    155247            self.cfg.set(s, n, v) 
    156         self.save_config() 
    157         cnx.commit() 
    158248 
    159249    def get_version(self): 
    160250        cnx = self.get_db_cnx() 
     
    290380 
    291381    def backup(self, dest=None): 
    292382        """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') 
    294385        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 
    296391        db_name = os.path.join(self.path, db_str[7:]) 
    297392        if not dest: 
    298393            dest = '%s.%i.bak' % (db_name, self.get_version()) 
     
    321416                    err = 'No upgrade module for version %i (%s.py)' % (i, upg) 
    322417                    raise EnvironmentError, err 
    323418                d.do_upgrade(self, i, cursor) 
    324             cursor.execute("UPDATE system SET value=%i WHERE " 
     419            cursor.execute("UPDATE system SET value=%s WHERE " 
    325420                           "name='database_version'", db_default.db_version) 
    326421            self.log.info('Upgraded db version from %d to %d', 
    327422                          dbver, db_default.db_version) 
    328423            cnx.commit() 
     424            print 'Upgrade succeeded.' 
    329425            return 1 
  • trac/Ticket.py

    old new  
    3535 
    3636 
    3737class Ticket(UserDict): 
    38     std_fields = ['time', 'component', 'severity', 'priority', 'milestone', 
     38    std_fields = ['id', 'time', 'component', 'severity', 'priority', 'milestone', 
    3939                  'reporter', 'owner', 'cc', 'url', 'version', 'status', 'resolution', 
    4040                  'keywords', 'summary', 'description'] 
    4141 
     
    7373            self[Ticket.std_fields[i]] = row[i] or '' 
    7474 
    7575        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) 
    7777        rows = cursor.fetchall() 
    7878        if rows: 
    7979            for r in rows: 
     
    9696    def insert(self, db): 
    9797        """Add ticket to database""" 
    9898        cursor = db.cursor() 
    99         assert not self.has_key('id') 
     99        # assert not self.has_key('id') 
    100100 
    101101        # Add a timestamp 
    102102        now = int(time.time()) 
    103103        self['time'] = now 
    104104        self['changetime'] = now 
    105105 
     106        self['id'] = util.get_next_key(db, 'ticket') 
     107 
    106108        std_fields = filter(lambda n: n[:7] != 'custom_', self.keys()) 
    107109        custom_fields = filter(lambda n: n[:7] == 'custom_', self.keys()) 
    108110        std_values = map(lambda n, self=self: self[n], std_fields) 
     111         
    109112        nstr = string.join(std_fields, ',') 
    110113        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), 
    112115                       *std_values) 
    113         id = db.db.sqlite_last_insert_rowid() 
     116        # id = db.db.sqlite_last_insert_rowid() 
    114117        for name in custom_fields: 
    115118            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]) 
    117120        db.commit() 
    118         self['id'] = id 
    119121        self._forget_changes() 
    120         return id 
     122        return self['id'] 
    121123 
    122124    def save_changes(self, db, author, comment, when = 0): 
    123125        """Store ticket changes in the database. 
     
    171173        """Returns the changelog as a list of dictionaries""" 
    172174        cursor = db.cursor() 
    173175        if when: 
    174             cursor.execute('SELECT time, author, field, oldvalue, newvalue '