Edgewall Software

Ticket #6235: trac-ingres-v0.2.diff

File trac-ingres-v0.2.diff, 14.1 KB (added by AlexTrofast <alex.trofast@…>, 14 months ago)

Patch against revision 6142

  • setup.py

     
    6666        trac.db.mysql = trac.db.mysql_backend 
    6767        trac.db.postgres = trac.db.postgres_backend 
    6868        trac.db.sqlite = trac.db.sqlite_backend 
     69        trac.db.ingres = trac.db.ingres_backend 
    6970        trac.mimeview.enscript = trac.mimeview.enscript 
    7071        trac.mimeview.patch = trac.mimeview.patch 
    7172        trac.mimeview.php = trac.mimeview.php 
  • trac/db_default.py

     
    202202  FROM ticket t 
    203203  LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' 
    204204  WHERE status <> 'closed' 
    205   ORDER BY (version IS NULL),version, p.value, t.type, time 
     205  ORDER BY (CASE WHEN version IS NULL THEN 1 ELSE 2 END) DESC,version, p.value, t.type, time 
    206206"""), 
    207207#---------------------------------------------------------------------------- 
    208208('Active Tickets by Milestone', 
     
    224224  FROM ticket t 
    225225  LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' 
    226226  WHERE status <> 'closed'  
    227   ORDER BY (milestone IS NULL),milestone, p.value, t.type, time 
     227  ORDER BY (CASE WHEN milestone IS NULL THEN 1 ELSE 2 END) DESC,milestone, p.value, t.type, time 
    228228""" % db.concat("'Milestone '", 'milestone')), 
    229229#---------------------------------------------------------------------------- 
    230230('Accepted, Active Tickets by Owner', 
     
    279279   time AS _time,reporter AS _reporter 
    280280  FROM ticket t 
    281281  LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' 
    282   ORDER BY (milestone IS NULL), milestone DESC, (status = 'closed'),  
     282  ORDER BY (CASE WHEN milestone IS NULL THEN 1 ELSE 2 END) DESC, milestone DESC, (CASE WHEN status = 'closed' THEN 1 ELSE 2 END) DESC,  
    283283        (CASE status WHEN 'closed' THEN modified ELSE (-1)*p.value END) DESC 
    284284"""), 
    285285#---------------------------------------------------------------------------- 
     
    299299  FROM ticket t 
    300300  LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' 
    301301  WHERE t.status <> 'closed' AND owner = $USER 
    302   ORDER BY (status = 'accepted') DESC, p.value, milestone, t.type, time 
     302  ORDER BY (CASE WHEN status = 'accepted' THEN 1 ELSE 2), p.value, milestone, t.type, time 
    303303"""), 
    304304#---------------------------------------------------------------------------- 
    305305('Active Tickets, Mine first', 
     
    321321  FROM ticket t 
    322322  LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' 
    323323  WHERE status <> 'closed'  
    324   ORDER BY (owner = $USER) DESC, p.value, milestone, t.type, time 
     324  ORDER BY (CASE WHEN owner = $USER THEN 1 ELSE 2), p.value, milestone, t.type, time 
    325325""")) 
    326326 
    327327 
     
    347347                ('2.0', 0))), 
    348348           ('enum', 
    349349             ('type', 'name', 'value'), 
    350                (('resolution', 'fixed', 1), 
    351                 ('resolution', 'invalid', 2), 
    352                 ('resolution', 'wontfix', 3), 
    353                 ('resolution', 'duplicate', 4), 
    354                 ('resolution', 'worksforme', 5), 
    355                 ('priority', 'blocker', 1), 
    356                 ('priority', 'critical', 2), 
    357                 ('priority', 'major', 3), 
    358                 ('priority', 'minor', 4), 
    359                 ('priority', 'trivial', 5), 
    360                 ('ticket_type', 'defect', 1), 
    361                 ('ticket_type', 'enhancement', 2), 
    362                 ('ticket_type', 'task', 3))), 
     350               (('resolution', 'fixed', '1'), 
     351                ('resolution', 'invalid', '2'), 
     352                ('resolution', 'wontfix', '3'), 
     353                ('resolution', 'duplicate', '4'), 
     354                ('resolution', 'worksforme', '5'), 
     355                ('priority', 'blocker', '1'), 
     356                ('priority', 'critical', '2'), 
     357                ('priority', 'major', '3'), 
     358                ('priority', 'minor', '4'), 
     359                ('priority', 'trivial', '5'), 
     360                ('ticket_type', 'defect', '1'), 
     361                ('ticket_type', 'enhancement', '2'), 
     362                ('ticket_type', 'task', '3'))), 
    363363           ('permission', 
    364364             ('username', 'action'), 
    365365               (('anonymous', 'LOG_VIEW'), 
  • trac/ticket/query.py

     
    439439                else: 
    440440                    time_col = 'version.time' 
    441441                if desc: 
    442                     sql.append("COALESCE(%s,0)=0 DESC,%s DESC,%s DESC" 
    443                                % (time_col, time_col, col)) 
     442                    sql.append("(CASE WHEN COALESCE(%s,0)=0 THEN 1 ELSE 2 END), %s DESC, %s DESC" % (time_col, time_col, col)) 
     443                #    sql.append("COALESCE(%s,0)=0 DESC,%s DESC,%s DESC" 
     444                 #              % (time_col, time_col, col)) 
    444445                else: 
    445                     sql.append("COALESCE(%s,0)=0,%s,%s" 
    446                                % (time_col, time_col, col)) 
     446                    sql.append("(CASE WHEN COALESCE(%s,0)=0 THEN 1 ELSE 2 END) DESC,%s,%s" % (time_col, time_col, col)) 
     447                #    sql.append("COALESCE(%s,0)=0,%s,%s" 
     448                 #              % (time_col, time_col, col)) 
    447449            else: 
    448450                if desc: 
    449451                    sql.append("%s DESC" % col) 
  • trac/db/ingres_backend.py

     
     1# -*- coding: utf-8 -*- 
     2# 
     3# Copyright (C) 2007 Edgewall Software 
     4# Copyright (C) 2007 Alexander Trofast <alex.trofast@ingres.com> 
     5# All rights reserved. 
     6# 
     7# This software is licensed as described in the file COPYING, which 
     8# you should have received as part of this distribution. The terms 
     9# are also available at http://trac.edgewall.org/wiki/TracLicense. 
     10# 
     11# This software consists of voluntary contributions made by many 
     12# individuals. For the exact contribution history, see the revision 
     13# history and logs, available at http://trac.edgewall.org/log/. 
     14# 
     15# Author: Alexander Trofast <alex.trofast@ingres.com> 
     16 
     17 
     18 
     19import re 
     20 
     21from trac.core import * 
     22from trac.db.api import IDatabaseConnector 
     23from trac.db.util import ConnectionWrapper, IterableCursor 
     24from types import * 
     25 
     26import ingresdbi 
     27 
     28_like_escape_re = re.compile(r'([/_%])') 
     29 
     30 
     31class IngresCursor(IterableCursor): 
     32 
     33         
     34        #Changes LIMIT to FIRST and moves it 
     35        def _convert_limit(self, query): 
     36                reglim = re.compile(r"SELECT(.+)LIMIT\s+(\d+)", re.I | re.M) 
     37                query = reglim.sub(r"SELECT FIRST \2 \1", query) 
     38                return query 
     39 
     40        # Hide away reserved word session within quotes for transportability 
     41        def _replace_session(self, query): 
     42                regses = re.compile(r"(.+)\s+SESSION\s+(.*)", re.I) 
     43                query = regses.sub(r'\1 t_session \2', query) 
     44                return query 
     45 
     46        #method to fix unicode issues and convert longer strings to binary objects 
     47        def _encode_args(self, args): 
     48                if(isinstance(args, list) or isinstance(args,tuple)): 
     49                        for arg in args: 
     50                                if(isinstance(arg, list) or isinstance(arg, tuple)): 
     51                                        yield list(self._encode_args(arg)) 
     52                                elif(isinstance(arg,unicode)): 
     53                                        yield self._check_length(arg.encode('utf-8')) 
     54                                else: 
     55                                        yield self._check_length(arg) 
     56                elif(isinstance(args, unicode)): 
     57                        yield self._check_length(args.encode('utf-8')) 
     58                else: 
     59                        yield self._check_length(args) 
     60         
     61        def _check_length(self, arg): 
     62                if(isinstance(arg, str) == False and isinstance(arg, unicode) == False): 
     63                        return arg 
     64                if len(arg) > 31999: 
     65                        return ingresdbi.Binary(arg) 
     66                else: 
     67                        return arg 
     68 
     69        def execute(self, sql, args = None): 
     70                sql = self._convert_limit(sql) 
     71                sql = self._replace_session(sql) 
     72                if args: 
     73                        sql = sql.replace('%s', '?') 
     74                        args = list(self._encode_args(args)) 
     75                        return self.cursor.execute(sql, args) 
     76                return self.cursor.execute(sql) 
     77 
     78        def executemany(self, sql, args = None): 
     79                if args: 
     80                        sql = sql.replace('%s', '?') 
     81                        sql = self._convert_limit(sql) 
     82                        sql = self._replace_session(sql) 
     83                        args = list(self._encode_args(args)) 
     84                        return self.cursor.executemany(sql, args) 
     85                return self.cursor.execute(sql) 
     86 
     87        def _convert_row(self, row): 
     88                new_row = [] 
     89                for r in row: 
     90                        if isinstance(r, str): 
     91                                new_row.append(r.decode('utf-8')) 
     92                        else: 
     93                                new_row.append(r) 
     94                return new_row   
     95 
     96        def fetchone(self): 
     97                row = self.cursor.fetchone() 
     98                return row and self._convert_row(row) or None 
     99 
     100        def fetchall(self): 
     101                rows = self.cursor.fetchall() 
     102                return rows != None and [self._convert_row(row) for row in rows] or [] 
     103 
     104        def fetchmany(self, num): 
     105                rows = self.cursor.fetchmany(num) 
     106                return rows != None and [self._convert_row(row) for row in rows] or [] 
     107 
     108 
     109class IngresConnector(Component): 
     110        """Ingres backend database support 
     111        usage: ingres://user:password@vnode/database 
     112        """ 
     113        implements(IDatabaseConnector) 
     114 
     115        #check for whether a field is an index, and convert it to an appropriate data type 
     116        def _is_index(self, name, indices): 
     117                for ind in indices: 
     118                        if name in ind.columns: 
     119                                return True 
     120                else: 
     121                        return False 
     122         
     123        def get_supported_schemes(self): 
     124                return [('ingres', 1)] 
     125 
     126        def get_connection(self, path, user=None, password=None, host=None, port=None, params={}): 
     127                return IngresConnection(path, user, password, host, port, params) 
     128 
     129        def init_db(self, path, user=None, password=None, host=None, port=None, params={}): 
     130                cnx = self.get_connection(path, user, password, host, port, params) 
     131                cursor = cnx.cursor() 
     132                from trac.db_default import schema 
     133                for table in schema: 
     134                        for stmt in self.to_sql(table): 
     135                                #print stmt 
     136                                cursor.execute(stmt) 
     137                cnx.commit() 
     138 
     139        def to_sql(self, table): 
     140                sql = ['CREATE TABLE %s (' % table.name] 
     141                if table.name == 'session': 
     142                        sql = ['CREATE TABLE t_session ('] 
     143                coldefs = [] 
     144                #find number of text keys 
     145                keys = 0 
     146                for clm in table.columns: 
     147                        if (clm.name in table.key or self._is_index(clm.name, table.indices)) and clm.auto_increment == False: 
     148                                keys += 1 
     149                key_length = 1 
     150                if keys: 
     151                        key_length = 1950 / keys 
     152 
     153                #variable used to determine if there is a procedure to create 
     154                auto_inc = False 
     155                proc = [] 
     156                rule = [] 
     157 
     158                for column in table.columns: 
     159                        ctype = column.type 
     160                        if column.auto_increment: 
     161                                ctype = 'int' #can't use a sequence on text 
     162                                yield "CREATE SEQUENCE %s_%s_seq START WITH 1 INCREMENT BY 1;" % (table.name, column.name) 
     163                                proc.append("CREATE PROCEDURE %s_%s_proc AS BEGIN UPDATE %s SET %s = %s_%s_seq.nextval WHERE %s = 0 END;" % (table.name, column.name, table.name, column.name, table.name, column.name, column.name)) 
     164                                rule.append("CREATE RULE %s_%s_rule AFTER INSERT ON %s EXECUTE PROCEDURE %s_%s_proc;" % (table.name, column.name, table.name, table.name, column.name)) 
     165 
     166                                auto_inc = True 
     167                        if ctype == 'text': 
     168                                if column.name in table.key or self._is_index(column.name, table.indices): 
     169                                        ctype = 'varchar(%s)' % key_length 
     170                                        #path can be really long, make sure it has more room 
     171                                        if table.name == 'node_change': 
     172                                                if column.name == 'path': 
     173                                                        ctype = 'varchar(1700)' 
     174                                                elif column.name == 'rev': 
     175                                                        ctype = 'varchar(256)' 
     176                                                elif column.name == 'change_type': 
     177                                                        ctype = 'varchar(5)' 
     178                                else: 
     179                                        ctype = 'varchar(1024)' 
     180                                if column.name == 'description' and (table.name == 'ticket' or table.name =='milestone'): 
     181                                        ctype = 'long varchar' 
     182                                elif column.name == 'text' and table.name == 'wiki': 
     183                                        ctype = 'long varchar' 
     184                        if column.auto_increment: 
     185                                default = " WITH DEFAULT 0" 
     186                        else: 
     187                                default = " " 
     188                        """ appends NOT NULL for keys """ 
     189                        if column.name in table.key: 
     190                                coldefs.append("  %s %s NOT NULL%s" % (column.name, ctype,default)) 
     191                        else: 
     192                                coldefs.append("  %s %s%s" % (column.name, ctype, default)) 
     193                         
     194                if len(table.key) > 0: 
     195                        coldefs.append("  PRIMARY KEY (%s)" % ",".join(table.key)) 
     196#               sql.append(",\n".join(coldefs) + "\n) with page_size = 65536;") 
     197                sql.append(",\n".join(coldefs) + "\n);") 
     198                yield "\n".join(sql) 
     199 
     200                #create procedure and rules here, after the table has been created. 
     201                if auto_inc == True: 
     202                        for itm in proc: 
     203                                yield itm 
     204                        for itm in rule: 
     205                                yield itm 
     206 
     207                for index in table.indices: 
     208                        #Use tblname instead of table.name to hack session -> t_session 
     209                        if table.name == 'session': 
     210                                tblname = 't_session' 
     211                        else: 
     212                                tblname = table.name 
     213 
     214                        yield "  CREATE INDEX %s_%s_idx ON %s (%s);" % (table.name, "_".join(index.columns), tblname, ",".join(index.columns)) 
     215 
     216class IngresConnection(ConnectionWrapper): 
     217        """Ingres Connection Wrapper""" 
     218 
     219        poolable = False 
     220 
     221        def __init__(self, path, user=None, password=None, host=None, port=None, params={}): 
     222         
     223                if path.startswith('/'): 
     224                        path = path[1:] 
     225                if host == None: 
     226                        host = "(local)" 
     227                if user == None: 
     228                        user = '' 
     229                if password == None: 
     230                        password = ''    
     231                cnx = ingresdbi.connect(vnode=host, database=path, uid=user, dbms_pwd=password) 
     232 
     233                ConnectionWrapper.__init__(self, cnx) 
     234                self._is_closed = False 
     235 
     236        def cast(self, column, type): 
     237                return "CAST(%s AS %s)" % (column, type) 
     238 
     239        def concat(self, *args): 
     240                return "concat(%s)" % ",".join(args) 
     241 
     242        def like(self): 
     243                return "LIKE %s ESCAPE '/'" 
     244 
     245        def like_escape(self, text): 
     246                return _like_escape_re.sub(r'/\1', text) 
     247 
     248        def get_last_id(self, cursor, table, column='id'): 
     249                """Hack to get the last inserted ID, will always be max due to procedures.""" 
     250                cursor.execute("SELECT MAX(%s) FROM %s" % (column, table)) 
     251                return cursor.fetchone()[0] 
     252 
     253        def rollback(self): 
     254                self.cnx.rollback() 
     255 
     256        def close(self): 
     257                self.cnx.close() 
     258                self._is_closed = True 
     259 
     260        def cursor(self): 
     261                return IngresCursor(self.cnx.cursor()) 
     262 
  • trac/search/api.py

     
    4747    """ 
    4848    assert columns and terms 
    4949 
    50     likes = ['%s %s' % (i, db.like()) for i in columns] 
     50    #cast i to char for db independence support 
     51    likes = ['%s %s' % (db.cast(i, 'char'), db.like()) for i in columns] 
    5152    c = ' OR '.join(likes) 
    5253    sql = '(' + ') AND ('.join([c] * len(terms)) + ')' 
    5354    args = []