comparison roundup/backends/back_sqlite.py @ 4076:59d02edfaa9c

Uniformly use """...""" instead of '''...''' for comments.
author Stefan Seefeld <stefan@seefeld.name>
date Tue, 24 Feb 2009 03:15:57 +0000
parents bb30bbfc7cdd
children 09e79cbeb827
comparison
equal deleted inserted replaced
4075:b87d022a2f40 4076:59d02edfaa9c
1 # $Id: back_sqlite.py,v 1.51 2007-06-21 07:35:50 schlatterbeck Exp $ 1 """Implements a backend for SQLite.
2 '''Implements a backend for SQLite.
3 2
4 See https://pysqlite.sourceforge.net/ for pysqlite info 3 See https://pysqlite.sourceforge.net/ for pysqlite info
5 4
6 5
7 NOTE: we use the rdbms_common table creation methods which define datatypes 6 NOTE: we use the rdbms_common table creation methods which define datatypes
8 for the columns, but sqlite IGNORES these specifications. 7 for the columns, but sqlite IGNORES these specifications.
9 ''' 8 """
10 __docformat__ = 'restructuredtext' 9 __docformat__ = 'restructuredtext'
11 10
12 import os, base64, marshal, shutil, time, logging 11 import os, base64, marshal, shutil, time, logging
13 12
14 from roundup import hyperdb, date, password 13 from roundup import hyperdb, date, password
88 time_to_sleep = 0.01 * (2 << min(5, count)) 87 time_to_sleep = 0.01 * (2 << min(5, count))
89 time.sleep(time_to_sleep) 88 time.sleep(time_to_sleep)
90 return 1 89 return 1
91 90
92 def sql_open_connection(self): 91 def sql_open_connection(self):
93 '''Open a standard, non-autocommitting connection. 92 """Open a standard, non-autocommitting connection.
94 93
95 pysqlite will automatically BEGIN TRANSACTION for us. 94 pysqlite will automatically BEGIN TRANSACTION for us.
96 ''' 95 """
97 # make sure the database directory exists 96 # make sure the database directory exists
98 # database itself will be created by sqlite if needed 97 # database itself will be created by sqlite if needed
99 if not os.path.isdir(self.config.DATABASE): 98 if not os.path.isdir(self.config.DATABASE):
100 os.makedirs(self.config.DATABASE) 99 os.makedirs(self.config.DATABASE)
101 100
163 def fix_version_3_tables(self): 162 def fix_version_3_tables(self):
164 # NOOP - no restriction on column length here 163 # NOOP - no restriction on column length here
165 pass 164 pass
166 165
167 def update_class(self, spec, old_spec, force=0, adding_v2=0): 166 def update_class(self, spec, old_spec, force=0, adding_v2=0):
168 ''' Determine the differences between the current spec and the 167 """ Determine the differences between the current spec and the
169 database version of the spec, and update where necessary. 168 database version of the spec, and update where necessary.
170 169
171 If 'force' is true, update the database anyway. 170 If 'force' is true, update the database anyway.
172 171
173 SQLite doesn't have ALTER TABLE, so we have to copy and 172 SQLite doesn't have ALTER TABLE, so we have to copy and
174 regenerate the tables with the new schema. 173 regenerate the tables with the new schema.
175 ''' 174 """
176 new_has = spec.properties.has_key 175 new_has = spec.properties.has_key
177 new_spec = spec.schema() 176 new_spec = spec.schema()
178 new_spec[1].sort() 177 new_spec[1].sort()
179 old_spec[1].sort() 178 old_spec[1].sort()
180 if not force and new_spec == old_spec: 179 if not force and new_spec == old_spec:
220 sql = 'drop table %s'%tn 219 sql = 'drop table %s'%tn
221 self.sql(sql) 220 self.sql(sql)
222 221
223 # re-create and populate the new table 222 # re-create and populate the new table
224 self.create_multilink_table(spec, propname) 223 self.create_multilink_table(spec, propname)
225 sql = '''insert into %s (linkid, nodeid) values 224 sql = """insert into %s (linkid, nodeid) values
226 (%s, %s)'''%(tn, self.arg, self.arg) 225 (%s, %s)"""%(tn, self.arg, self.arg)
227 for linkid, nodeid in rows: 226 for linkid, nodeid in rows:
228 self.sql(sql, (int(linkid), int(nodeid))) 227 self.sql(sql, (int(linkid), int(nodeid)))
229 elif old_has(propname): 228 elif old_has(propname):
230 # we copy this col over from the old table 229 # we copy this col over from the old table
231 fetch.append('_'+propname) 230 fetch.append('_'+propname)
294 self.sql(sql, tuple(d)) 293 self.sql(sql, tuple(d))
295 294
296 return 1 295 return 1
297 296
298 def sql_close(self): 297 def sql_close(self):
299 ''' Squash any error caused by us already having closed the 298 """ Squash any error caused by us already having closed the
300 connection. 299 connection.
301 ''' 300 """
302 try: 301 try:
303 self.conn.close() 302 self.conn.close()
304 except sqlite.ProgrammingError, value: 303 except sqlite.ProgrammingError, value:
305 if str(value) != 'close failed - Connection is closed.': 304 if str(value) != 'close failed - Connection is closed.':
306 raise 305 raise
307 306
308 def sql_rollback(self): 307 def sql_rollback(self):
309 ''' Squash any error caused by us having closed the connection (and 308 """ Squash any error caused by us having closed the connection (and
310 therefore not having anything to roll back) 309 therefore not having anything to roll back)
311 ''' 310 """
312 try: 311 try:
313 self.conn.rollback() 312 self.conn.rollback()
314 except sqlite.ProgrammingError, value: 313 except sqlite.ProgrammingError, value:
315 if str(value) != 'rollback failed - Connection is closed.': 314 if str(value) != 'rollback failed - Connection is closed.':
316 raise 315 raise
317 316
318 def __repr__(self): 317 def __repr__(self):
319 return '<roundlite 0x%x>'%id(self) 318 return '<roundlite 0x%x>'%id(self)
320 319
321 def sql_commit(self, fail_ok=False): 320 def sql_commit(self, fail_ok=False):
322 ''' Actually commit to the database. 321 """ Actually commit to the database.
323 322
324 Ignore errors if there's nothing to commit. 323 Ignore errors if there's nothing to commit.
325 ''' 324 """
326 try: 325 try:
327 self.conn.commit() 326 self.conn.commit()
328 except sqlite.DatabaseError, error: 327 except sqlite.DatabaseError, error:
329 if str(error) != 'cannot commit - no transaction is active': 328 if str(error) != 'cannot commit - no transaction is active':
330 raise 329 raise
338 return 1 337 return 1
339 return 0 338 return 0
340 339
341 # old-skool id generation 340 # old-skool id generation
342 def newid(self, classname): 341 def newid(self, classname):
343 ''' Generate a new id for the given class 342 """ Generate a new id for the given class
344 ''' 343 """
345 # get the next ID 344 # get the next ID
346 sql = 'select num from ids where name=%s'%self.arg 345 sql = 'select num from ids where name=%s'%self.arg
347 self.sql(sql, (classname, )) 346 self.sql(sql, (classname, ))
348 newid = int(self.cursor.fetchone()[0]) 347 newid = int(self.cursor.fetchone()[0])
349 348
354 353
355 # return as string 354 # return as string
356 return str(newid) 355 return str(newid)
357 356
358 def setid(self, classname, setid): 357 def setid(self, classname, setid):
359 ''' Set the id counter: used during import of database 358 """ Set the id counter: used during import of database
360 359
361 We add one to make it behave like the sequences in postgres. 360 We add one to make it behave like the sequences in postgres.
362 ''' 361 """
363 sql = 'update ids set num=%s where name=%s'%(self.arg, self.arg) 362 sql = 'update ids set num=%s where name=%s'%(self.arg, self.arg)
364 vals = (int(setid)+1, classname) 363 vals = (int(setid)+1, classname)
365 self.sql(sql, vals) 364 self.sql(sql, vals)
366 365
367 def clear(self): 366 def clear(self):
376 vals = (spec.classname, 1) 375 vals = (spec.classname, 1)
377 self.sql(sql, vals) 376 self.sql(sql, vals)
378 377
379 if sqlite_version in (2,3): 378 if sqlite_version in (2,3):
380 def load_journal(self, classname, cols, nodeid): 379 def load_journal(self, classname, cols, nodeid):
381 '''We need to turn the sqlite3.Row into a tuple so it can be 380 """We need to turn the sqlite3.Row into a tuple so it can be
382 unpacked''' 381 unpacked"""
383 l = rdbms_common.Database.load_journal(self, 382 l = rdbms_common.Database.load_journal(self,
384 classname, cols, nodeid) 383 classname, cols, nodeid)
385 cols = range(5) 384 cols = range(5)
386 return [[row[col] for col in cols] for row in l] 385 return [[row[col] for col in cols] for row in l]
387 386
388 class sqliteClass: 387 class sqliteClass:
389 def filter(self, search_matches, filterspec, sort=(None,None), 388 def filter(self, search_matches, filterspec, sort=(None,None),
390 group=(None,None)): 389 group=(None,None)):
391 ''' If there's NO matches to a fetch, sqlite returns NULL 390 """ If there's NO matches to a fetch, sqlite returns NULL
392 instead of nothing 391 instead of nothing
393 ''' 392 """
394 return filter(None, rdbms_common.Class.filter(self, search_matches, 393 return filter(None, rdbms_common.Class.filter(self, search_matches,
395 filterspec, sort=sort, group=group)) 394 filterspec, sort=sort, group=group))
396 395
397 class Class(sqliteClass, rdbms_common.Class): 396 class Class(sqliteClass, rdbms_common.Class):
398 pass 397 pass

Roundup Issue Tracker: http://roundup-tracker.org/