source: timingandestimationplugin/branches/trac1.0/timingandestimationplugin/dbhelper.py

Last change on this file was 17249, checked in by Russ Tyndall, 5 years ago

Change db backend import stuff to allow running without all backends installed re #13462

File size: 6.8 KB
Line 
1import trac.db.pool
2SqliteCon, PGCon, MySqlCon = None,None,None
3try:
4    import trac.db.sqlite_backend
5    SqliteCon = trac.db.sqlite_backend.SQLiteConnection
6except:
7    pass
8try:
9    import trac.db.postgres_backend
10    PGCon = trac.db.postgres_backend.PostgreSQLConnection
11except:
12    pass
13try:
14    import trac.db.mysql_backend
15    MySqlCon = trac.db.mysql_backend.MySQLConnection
16except:
17    pass
18
19
20def is_db_type(db, typeToVerify):
21    if not typeToVerify:
22        return False
23    cnx = db.cnx
24    t = type(cnx)
25    if t == trac.db.pool.PooledConnection:
26        t = type(cnx.cnx)
27    return typeToVerify == t
28
29def get_all(env, sql, *params):
30    """Executes the query and returns the (description, data)"""
31    with env.db_query as db:
32        cur = db.cursor()
33        desc = None
34        data = None
35        try:
36            cur.execute(sql, params)
37            data = list(cur.fetchall())
38            desc = cur.description
39        except Exception, e:
40            env.log.exception('There was a problem executing sql:%s \n \
41    with parameters:%s\nException:%s' % (sql, params, e))
42    return (desc, data)
43
44def execute_non_query(env, sql, *params):
45    """Executes the query on the given project"""
46    execute_in_trans(env, (sql, params))
47   
48def get_first_row(env, sql,*params):
49    """ Returns the first row of the query results as a tuple of values (or None)"""
50    data = None
51    with env.db_query as db:
52        cur = db.cursor()
53        try:
54            cur.execute(sql, params)
55            data = cur.fetchone();
56        except Exception, e:
57            env.log.exception('There was a problem executing sql:%s \n \
58            with parameters:%s\nException:%s' % (sql, params, e))
59    return data
60
61def get_scalar(env, sql, col=0, *params):
62    """ Gets a single value (in the specified column) from the result set of the query"""
63    data = get_first_row(env, sql, *params);
64    if data:
65        return data[col]
66    else:
67        return None;
68
69def execute_in_trans(env, *args):
70    result = True
71    c_sql =[None]
72    c_params = [None]
73    try:
74        with env.db_transaction as db:
75            cur = db.cursor()
76            for sql, params in args:
77                c_sql[0] = sql
78                c_params[0] = params
79                cur.execute(sql, params)
80    except Exception, e :
81        env.log.exception('There was a problem executing sql:%s \n \
82    with parameters:%s\nException:%s' % (c_sql[0], c_params[0], e));
83        raise e
84    return result
85
86def execute_in_nested_trans(env, name, *args):
87    result = True
88    c_sql =[None]
89    c_params = [None]
90    with self.env.db_transaction as db:
91        cur = None
92        try:
93            cur = db.cursor()
94            cur.execute("SAVEPOINT %s" % name)
95            for sql, params in args:
96                c_sql[0] = sql
97                c_params[0] = params
98                cur.execute(sql, params)
99            cur.execute("RELEASE SAVEPOINT %s" % name)
100        except Exception, e :
101            cur.execute("ROLLBACK TO SAVEPOINT %s" % name)
102            env.log.exception('There was a problem executing sql:%s \n \
103    with parameters:%s\nException:%s'%(c_sql[0], c_params[0], e));
104            raise e
105    return result
106
107def current_schema (env):
108    with env.db_query as db:
109        if is_db_type(db, SqliteCon):
110            return None
111        elif is_db_type(db, MySqlCon):
112            return get_scalar(env, 'SELECT schema();')
113        elif is_db_type(db, PGCon):
114            return get_scalar(env, 'SHOW search_path;')
115
116def _prep_schema(s):
117    #remove double quotes, escape single quotes
118    if not s: return "'<NOT VALID>'"
119    return ','.join(("'"+i.replace('"','').replace("'","''")+"'"
120                     for i in s.split(',')))
121
122def db_table_exists(env,  table):
123    cnt = 0
124    with env.db_query as db:
125        if is_db_type(db, SqliteCon):
126            sql = "select count(*) from sqlite_master where type = 'table' and name = %s"
127            cnt = get_scalar(env, sql, 0, table)
128        else:
129            sql = """SELECT count(*) FROM information_schema.tables
130                     WHERE table_name = %%s and table_schema in (%s)
131                  """ % _prep_schema(current_schema(env))
132            cnt = get_scalar(env, sql, 0, table)
133    return cnt
134
135def get_column_as_list(env, sql, col=0, *params):
136    data = get_all(env, sql, *params)[1] or ()
137    return [valueList[col] for valueList in data]
138
139def get_system_value(env, key):
140    return get_scalar(env, "SELECT value FROM system WHERE name=%s", 0, key)
141
142def set_system_value(env, key, value):
143    if get_system_value(env, key):
144        execute_non_query(env, "UPDATE system SET value=%s WHERE name=%s", value, key)       
145    else:
146        execute_non_query(env, "INSERT INTO system (value, name) VALUES (%s, %s)",
147            value, key)
148
149
150def get_result_set(env, sql, *params):
151    """Executes the query and returns a Result Set"""
152    tpl = get_all(env, sql, *params);
153    if tpl and tpl[0] and tpl[1]:
154        return ResultSet(tpl)
155    else:
156        return None
157
158
159class ResultSet:
160    """ the result of calling getResultSet """
161    def __init__ (self, (columnDescription, rows)):
162        self.columnDescription, self.rows = columnDescription, rows
163        self.columnMap = self.get_column_map()
164
165    def get_column_map ( self ):
166        """This function will take the result set from getAll and will
167        return a hash of the column names to their index """
168        h = {}
169        i = 0
170        if self.columnDescription:
171            for col in self.columnDescription:
172                h[ col[0] ] = i
173                i+=1
174        return h;
175   
176    def value(self, col, row ):
177        """ given a row(list or idx) and a column( name or idx ), retrieve the appropriate value"""
178        tcol = type(col)
179        trow = type(row)
180        if tcol == str:
181            if(trow == list or trow == tuple):
182                return row[self.columnMap[col]]
183            elif(trow == int):
184                return self.rows[row][self.columnMap[col]]
185            else:
186                print ("rs.value Type Failed col:%s  row:%s" % (type(col), type(row)))
187        elif tcol == int:
188            if(trow == list or trow == tuple):
189                return row[col]
190            elif(trow == int):
191                return self.rows[row][col]
192            else:
193                print ("rs.value Type Failed col:%s  row:%s" % (type(col), type(row)))
194        else:
195            print ("rs.value Type Failed col:%s  row:%s" % (type(col), type(row)))
196   
197    def json_out(self):
198        json = "[%s]" % ',\r\n'. join(
199            [("{%s}" % ','.join(
200            ["'%s':'%s'" %
201             (key, unicode(self.value(val, row)).
202              replace("'","\\'").
203              replace('"','\\"').
204              replace('\r','\\r').
205              replace('\n','\\n'))
206             for (key, val) in self.columnMap.items()]))
207             for row in self.rows])
208        #mylog.debug('serializing to json : %s'% json)
209        return json
Note: See TracBrowser for help on using the repository browser.