Revision 1930
Added by Aaron Marcuse-Kubitza over 12 years ago
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
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.