Project

General

Profile

« Previous | Next » 

Revision 1894

run_*query(): Fixed bug where INSERTs, etc. were cached by making callers (such as select()) explicitly turn on caching. DbConn.run_query(): Fixed bug where cur.mogrify() was not supported under MySQL by making the cache key a tuple of the unmogrified query and its params instead of the mogrified string query. CacheCursor: Store attributes of the original cursor that we use, such as query and rowcount.

View differences:

lib/sql.py
75 75
def db_config_str(db_config):
76 76
    return db_config['engine']+' database '+db_config['database']
77 77

  
78
def _query_lookup(query, params): return (query, util.cast(tuple, params))
79

  
78 80
class DbConn:
79 81
    def __init__(self, db_config, serializable=True, debug=False):
80 82
        self.db_config = db_config
......
120 122
        def __init__(self, outer):
121 123
            Proxy.__init__(self, outer.db.cursor())
122 124
            self.outer = outer
125
            self.query_lookup = None
123 126
            self.result = []
124 127
        
128
        def execute(self, query, params=None):
129
            self.query_lookup = _query_lookup(query, params)
130
            return_value = self.inner.execute(query, params)
131
            self.query = get_cur_query(self.inner)
132
            return return_value
133
        
125 134
        def fetchone(self):
126 135
            row = self.inner.fetchone()
127 136
            if row == None: # fetched all rows
128
                self.outer.query_results[self.inner.query] = self.result
137
                assert self.query_lookup != None
138
                pass #self.outer.query_results[self.query_lookup] = (self.query,
139
                    #self.result)
129 140
            else: self.result.append(row)
130 141
            return row
131 142
    
132 143
    class CacheCursor:
133
        def __init__(self, result): self.iter = iter(result)
144
        def __init__(self, query, result):
145
            self.query = query
146
            self.rowcount = len(result)
147
            self.iter = iter(result)
134 148
        
135 149
        def fetchone(self):
136 150
            try: return self.iter.next()
137 151
            except StopIteration: return None
138 152
    
139
    def run_query(self, query, params=None):
140
        cur = self.DbCursor(self)
141
        query = cur.mogrify(query, params)
142
        try: return self.CacheCursor(self.query_results[query])
153
    def run_query(self, query, params=None, cacheable=False):
154
        query_lookup = _query_lookup(query, params)
155
        try: actual_query, result = self.query_results[query_lookup]
143 156
        except KeyError:
144
            try: cur.execute(query)
157
            cur = self.DbCursor(self)
158
            try: cur.execute(query, params)
145 159
            except Exception, e:
146 160
                _add_cursor_info(e, cur)
147 161
                raise
148 162
            if self.debug:
149 163
                sys.stderr.write(strings.one_line(get_cur_query(cur))+'\n')
150 164
            return cur
165
        else: return self.CacheCursor(actual_query, result)
151 166

  
152 167
connect = DbConn
153 168

  
154 169
##### Querying
155 170

  
156
def run_raw_query(db, query, params=None): return db.run_query(query, params)
171
def run_raw_query(db, *args, **kw_args):
172
    '''For args, see DbConn.run_query()'''
173
    return db.run_query(*args, **kw_args)
157 174

  
158 175
##### Recoverable querying
159 176

  
......
168 185
        run_raw_query(db, 'RELEASE SAVEPOINT '+savepoint)
169 186
        return return_val
170 187

  
171
def run_query(db, query, params=None, recover=None):
188
def run_query(db, query, params=None, recover=None, cacheable=False):
172 189
    if recover == None: recover = False
173 190
    
174
    def run(): return run_raw_query(db, query, params)
191
    def run(): return run_raw_query(db, query, params, cacheable)
175 192
    if recover: return with_savepoint(db, run)
176 193
    else: return run()
177 194

  
......
202 219
##### Basic queries
203 220

  
204 221
def select(db, table, fields=None, conds=None, limit=None, start=None,
205
    recover=None):
222
    recover=None, cacheable=True):
206 223
    '''@param fields Use None to select all fields in the table'''
207 224
    if conds == None: conds = {}
208 225
    assert limit == None or type(limit) == int
......
234 251
    if missing: warnings.warn(DbWarning(
235 252
        'SELECT statement missing a WHERE, LIMIT, or OFFSET clause: '+query))
236 253
    
237
    return run_query(db, query, conds.values(), recover)
254
    return run_query(db, query, conds.values(), cacheable, recover)
238 255

  
239 256
def insert(db, table, row, returning=None, recover=None):
240 257
    '''@param returning str|None An inserted column (such as pkey) to return'''

Also available in: Unified diff