Project

General

Profile

« Previous | Next » 

Revision 1930

sql.py: pkey(): Fixed bug where results were not being cached because the rows hadn't been explicitly fetched, by having DbConn.DbCursor.execute() fetch all rows if the rowcount is 0 and it's not an insert statement. DbConn.DbCursor: Made _is_insert an attribute rather than a method, which is set as soon as the query is known. Added consume_rows(). Moved Result retrieval section above Database connections because it's used by DbConn.

View differences:

lib/sql.py
43 43

  
44 44
class DbWarning(UserWarning): pass
45 45

  
46
##### Result retrieval
47

  
48
def col_names(cur): return (col[0] for col in cur.description)
49

  
50
def rows(cur): return iter(lambda: cur.fetchone(), None)
51

  
52
def consume_rows(cur):
53
    '''Used to fetch all rows so result will be cached'''
54
    iters.consume_iter(rows(cur))
55

  
56
def next_row(cur): return rows(cur).next()
57

  
58
def row(cur):
59
    row_ = next_row(cur)
60
    consume_rows(cur)
61
    return row_
62

  
63
def next_value(cur): return next_row(cur)[0]
64

  
65
def value(cur): return row(cur)[0]
66

  
67
def values(cur): return iters.func_iter(lambda: next_value(cur))
68

  
69
def value_or_none(cur):
70
    try: return value(cur)
71
    except StopIteration: return None
72

  
46 73
##### Database connections
47 74

  
48 75
db_config_names = ['engine', 'host', 'user', 'password', 'database']
......
115 142
            self.result = []
116 143
        
117 144
        def execute(self, query, params=None):
145
            self._is_insert = query.upper().find('INSERT') >= 0
118 146
            self.query_lookup = _query_lookup(query, params)
119 147
            try: return_value = self.inner.execute(query, params)
120 148
            except Exception, e:
......
122 150
                self._cache_result()
123 151
                raise
124 152
            finally: self.query = get_cur_query(self.inner)
153
            # Fetch all rows so result will be cached
154
            if self.rowcount == 0 and not self._is_insert: consume_rows(self)
125 155
            return return_value
126 156
        
127 157
        def fetchone(self):
......
132 162
            return row
133 163
        
134 164
        def _cache_result(self):
135
            is_insert = self._is_insert()
136 165
            # For inserts, only cache exceptions since inserts are not
137 166
            # idempotent, but an invalid insert will always be invalid
138
            if self.query_results != None and (not is_insert
167
            if self.query_results != None and (not self._is_insert
139 168
                or isinstance(self.result, Exception)):
140 169
                
141 170
                assert self.query_lookup != None
......
143 172
                    util.dict_subset(dicts.AttrsDictView(self),
144 173
                    ['query', 'result', 'rowcount', 'description']))
145 174
        
146
        def _is_insert(self): return self.query.upper().find('INSERT') >= 0
147
        
148 175
        class CacheCursor:
149 176
            def __init__(self, cached_result): self.__dict__ = cached_result
150 177
            
......
237 264
        return with_savepoint(db, run)
238 265
    else: return run() # don't need savepoint if cached
239 266

  
240
##### Result retrieval
241

  
242
def col_names(cur): return (col[0] for col in cur.description)
243

  
244
def rows(cur): return iter(lambda: cur.fetchone(), None)
245

  
246
def next_row(cur): return rows(cur).next()
247

  
248
def row(cur):
249
    row_iter = rows(cur)
250
    row_ = row_iter.next()
251
    iters.consume_iter(row_iter) # fetch all rows so result will be cached
252
    return row_
253

  
254
def next_value(cur): return next_row(cur)[0]
255

  
256
def value(cur): return row(cur)[0]
257

  
258
def values(cur): return iters.func_iter(lambda: next_value(cur))
259

  
260
def value_or_none(cur):
261
    try: return value(cur)
262
    except StopIteration: return None
263

  
264 267
##### Basic queries
265 268

  
266 269
def select(db, table, fields=None, conds=None, limit=None, start=None,

Also available in: Unified diff