|
1 | | -# $Id: back_sqlite.py,v 1.15 2004-03-12 04:08:59 richard Exp $ |
| 1 | +# $Id: back_sqlite.py,v 1.16 2004-03-15 05:50:20 richard Exp $ |
2 | 2 | '''Implements a backend for SQLite. |
3 | 3 |
|
4 | 4 | See https://pysqlite.sourceforge.net/ for pysqlite info |
@@ -48,6 +48,97 @@ def create_version_2_tables(self): |
48 | 48 | 's_last_use varchar, s_user varchar)') |
49 | 49 | self.cursor.execute('create index sessions_key_idx on sessions(s_key)') |
50 | 50 |
|
| 51 | + def add_actor_column(self): |
| 52 | + # update existing tables to have the new actor column |
| 53 | + tables = self.database_schema['tables'] |
| 54 | + for classname, spec in self.classes.items(): |
| 55 | + if tables.has_key(classname): |
| 56 | + dbspec = tables[classname] |
| 57 | + self.update_class(spec, dbspec, force=1, adding_actor=1) |
| 58 | + |
| 59 | + def update_class(self, spec, old_spec, force=0, adding_actor=0): |
| 60 | + ''' Determine the differences between the current spec and the |
| 61 | + database version of the spec, and update where necessary. |
| 62 | +
|
| 63 | + If 'force' is true, update the database anyway. |
| 64 | +
|
| 65 | + SQLite doesn't have ALTER TABLE, so we have to copy and |
| 66 | + regenerate the tables with the new schema. |
| 67 | + ''' |
| 68 | + new_has = spec.properties.has_key |
| 69 | + new_spec = spec.schema() |
| 70 | + new_spec[1].sort() |
| 71 | + old_spec[1].sort() |
| 72 | + if not force and new_spec == old_spec: |
| 73 | + # no changes |
| 74 | + return 0 |
| 75 | + |
| 76 | + if __debug__: |
| 77 | + print >>hyperdb.DEBUG, 'update_class FIRING' |
| 78 | + |
| 79 | + # detect multilinks that have been removed, and drop their table |
| 80 | + old_has = {} |
| 81 | + for name,prop in old_spec[1]: |
| 82 | + old_has[name] = 1 |
| 83 | + if new_has(name) or not isinstance(prop, hyperdb.Multilink): |
| 84 | + continue |
| 85 | + # it's a multilink, and it's been removed - drop the old |
| 86 | + # table. First drop indexes. |
| 87 | + self.drop_multilink_table_indexes(spec.classname, ml) |
| 88 | + sql = 'drop table %s_%s'%(spec.classname, prop) |
| 89 | + if __debug__: |
| 90 | + print >>hyperdb.DEBUG, 'update_class', (self, sql) |
| 91 | + self.cursor.execute(sql) |
| 92 | + old_has = old_has.has_key |
| 93 | + |
| 94 | + # now figure how we populate the new table |
| 95 | + if adding_actor: |
| 96 | + fetch = ['_activity', '_creation', '_creator'] |
| 97 | + else: |
| 98 | + fetch = ['_actor', '_activity', '_creation', '_creator'] |
| 99 | + properties = spec.getprops() |
| 100 | + for propname,x in new_spec[1]: |
| 101 | + prop = properties[propname] |
| 102 | + if isinstance(prop, hyperdb.Multilink): |
| 103 | + if force or not old_has(propname): |
| 104 | + # we need to create the new table |
| 105 | + self.create_multilink_table(spec, propname) |
| 106 | + elif old_has(propname): |
| 107 | + # we copy this col over from the old table |
| 108 | + fetch.append('_'+propname) |
| 109 | + |
| 110 | + # select the data out of the old table |
| 111 | + fetch.append('id') |
| 112 | + fetch.append('__retired__') |
| 113 | + fetchcols = ','.join(fetch) |
| 114 | + cn = spec.classname |
| 115 | + sql = 'select %s from _%s'%(fetchcols, cn) |
| 116 | + if __debug__: |
| 117 | + print >>hyperdb.DEBUG, 'update_class', (self, sql) |
| 118 | + self.cursor.execute(sql) |
| 119 | + olddata = self.cursor.fetchall() |
| 120 | + |
| 121 | + # TODO: update all the other index dropping code |
| 122 | + self.drop_class_table_indexes(cn, old_spec[0]) |
| 123 | + |
| 124 | + # drop the old table |
| 125 | + self.cursor.execute('drop table _%s'%cn) |
| 126 | + |
| 127 | + # create the new table |
| 128 | + self.create_class_table(spec) |
| 129 | + |
| 130 | + if olddata: |
| 131 | + # do the insert of the old data - the new columns will have |
| 132 | + # NULL values |
| 133 | + args = ','.join([self.arg for x in fetch]) |
| 134 | + sql = 'insert into _%s (%s) values (%s)'%(cn, fetchcols, args) |
| 135 | + if __debug__: |
| 136 | + print >>hyperdb.DEBUG, 'update_class', (self, sql, olddata[0]) |
| 137 | + for entry in olddata: |
| 138 | + self.cursor.execute(sql, tuple(entry)) |
| 139 | + |
| 140 | + return 1 |
| 141 | + |
51 | 142 | def sql_close(self): |
52 | 143 | ''' Squash any error caused by us already having closed the |
53 | 144 | connection. |
|
0 commit comments