1 | """ |
---|
2 | SQLite3 utilities. |
---|
3 | |
---|
4 | Test coverage currently provided by test_backupdb.py. |
---|
5 | |
---|
6 | Ported to Python 3. |
---|
7 | """ |
---|
8 | |
---|
9 | import os, sys |
---|
10 | |
---|
11 | import sqlite3 |
---|
12 | |
---|
13 | |
---|
14 | class DBError(Exception): |
---|
15 | pass |
---|
16 | |
---|
17 | |
---|
18 | def get_db(dbfile, stderr=sys.stderr, |
---|
19 | create_version=(None, None), updaters=None, just_create=False, dbname="db", |
---|
20 | ): |
---|
21 | """Open or create the given db file. The parent directory must exist. |
---|
22 | create_version=(SCHEMA, VERNUM), and SCHEMA must have a 'version' table. |
---|
23 | Updaters is a {newver: commands} mapping, where e.g. updaters[2] is used |
---|
24 | to get from ver=1 to ver=2. Returns a (sqlite3,db) tuple, or raises |
---|
25 | DBError. |
---|
26 | """ |
---|
27 | if updaters is None: |
---|
28 | updaters = {} |
---|
29 | must_create = not os.path.exists(dbfile) |
---|
30 | try: |
---|
31 | db = sqlite3.connect(dbfile) |
---|
32 | except (EnvironmentError, sqlite3.OperationalError) as e: |
---|
33 | raise DBError("Unable to create/open %s file %s: %s" % (dbname, dbfile, e)) |
---|
34 | |
---|
35 | schema, target_version = create_version |
---|
36 | c = db.cursor() |
---|
37 | |
---|
38 | # Enabling foreign keys allows stricter integrity checking. |
---|
39 | # The default is unspecified according to <http://www.sqlite.org/foreignkeys.html#fk_enable>. |
---|
40 | c.execute("PRAGMA foreign_keys = ON;") |
---|
41 | |
---|
42 | if must_create: |
---|
43 | c.executescript(schema) |
---|
44 | c.execute("INSERT INTO version (version) VALUES (?)", (target_version,)) |
---|
45 | db.commit() |
---|
46 | |
---|
47 | try: |
---|
48 | c.execute("SELECT version FROM version") |
---|
49 | version = c.fetchone()[0] |
---|
50 | except sqlite3.DatabaseError as e: |
---|
51 | # this indicates that the file is not a compatible database format. |
---|
52 | # Perhaps it was created with an old version, or it might be junk. |
---|
53 | raise DBError("%s file is unusable: %s" % (dbname, e)) |
---|
54 | |
---|
55 | if just_create: # for tests |
---|
56 | return (sqlite3, db) |
---|
57 | |
---|
58 | while version < target_version and version+1 in updaters: |
---|
59 | c.executescript(updaters[version+1]) |
---|
60 | db.commit() |
---|
61 | version = version+1 |
---|
62 | if version != target_version: |
---|
63 | raise DBError("Unable to handle %s version %s" % (dbname, version)) |
---|
64 | |
---|
65 | return (sqlite3, db) |
---|
66 | |
---|
67 | |
---|