                   where f.fieldName = 'extra' and not i.itemID in (select itemID from deletedItems)"
 
   @pref.prefs.clearUserPref('brace-all')
-  Zotero.DB.query('create table if not exists betterbibtex._version_ (tablename primary key, version not null, unique (tablename, version))')
-  Zotero.DB.query("insert or ignore into betterbibtex._version_ (tablename, version) values ('keys', 0)")
-
-  version = Zotero.DB.valueQuery("select version from betterbibtex._version_ where tablename = 'keys'")
+
+  Zotero.DB.query("create table if not exists betterbibtex.schema (lock primary key default 'schema' check (lock='schema'), version not null)")
+
+  ### migrate '_version_' to 'schema' ###
+  if @SQLColumns('_version_')
+    Zotero.DB.query("insert or replace into betterbibtex.schema (lock, version) select 'schema', version from betterbibtex._version_ order by version desc limit 1")
+    Zotero.DB.query('drop table betterbibtex._version_')
+
+  ### initialize 'schema' ###
+  Zotero.DB.query("insert or ignore into betterbibtex.schema (lock, version) values ('schema', 0)")
+  version = Zotero.DB.valueQuery("select version from betterbibtex.schema")
   @log("Booting BBT, schema: #{version}")
-  if version < 1
-    Zotero.DB.query('create table betterbibtex.keys (itemID primary key, libraryID not null, citekey not null, pinned)')
-
-  if version < 3
-    @pref.set('scan-citekeys', true)
-
-  if version < 4
-    Zotero.DB.query('alter table betterbibtex.keys rename to keys2')
-    Zotero.DB.query('create table betterbibtex.keys (itemID primary key, libraryID not null, citekey not null, citeKeyFormat)')
-    Zotero.DB.query('insert into betterbibtex.keys (itemID, libraryID, citekey, citeKeyFormat)
-               select itemID, libraryID, citekey, case when pinned = 1 then null else ? end from betterbibtex.keys2', [@pref.get('citeKeyFormat')])
-
-  if version < 5
-    Zotero.DB.query('drop table betterbibtex.keys2')
-
-  if version < 6
-    Zotero.DB.query("
-      create table betterbibtex.cache (
-        itemID not null,
-        context not null,
-        citekey not null,
-        entry not null,
-        primary key (itemid, context))
-      ")
-
-  if version < 7
+
+  ### upgrade 'keys' table ###
+  columns = @SQLColumns('keys')
+  if columns?.pinned || columns?.libraryID
     Zotero.DB.query('alter table betterbibtex.keys rename to _keys_')
+  if !columns || columns?.pinned || columns?.libraryID
     Zotero.DB.query('create table betterbibtex.keys (itemID primary key, citekey not null, citeKeyFormat)')
-    Zotero.DB.query('insert into betterbibtex.keys (itemID, citekey, citeKeyFormat) select itemID, citekey, citeKeyFormat from betterbibtex._keys_')
+  switch
+    when columns?.pinned
+      Zotero.DB.query('insert into betterbibtex.keys (itemID, citekey, citeKeyFormat)
+                       select itemID, citekey, case when pinned = 1 then null else ? end from betterbibtex._keys_', [@pref.get('citeKeyFormat')])
+    when columns?.libraryID
+      Zotero.DB.query('insert into betterbibtex.keys (itemID, citekey, citeKeyFormat)
+                       select itemID, citekey, citeKeyFormat from betterbibtex._keys_')
+  if columns?.pinned || columns?.libraryID
     Zotero.DB.query('drop table betterbibtex._keys_')
-    @pref.set('scan-citekeys', true)
-
-  if version < 8
-    Zotero.DB.query("
-      create table if not exists betterbibtex.autoexport (
-        id integer primary key not null,
-        collection_id not null,
-        collection_name not null,
-        path not null,
-        context not null,
-        recursive not null,
-        status not null,
-        unique (collection_id, path, context))
-      ")
-
-  if version < 10
-    Zotero.DB.query('alter table betterbibtex.cache rename to _cache_')
+
+  ### drop 'keys2' table, upgrade leftovers ###
+  Zotero.DB.query('drop table betterbibtex.keys2') if @SQLColumns('keys2')
+
+  ### upgrade 'cache' table ###
+  columns = @SQLColumns('cache')
+  unless columns?.lastaccess
+    if columns
+      Zotero.DB.query('alter table betterbibtex.cache rename to _cache_')
     Zotero.DB.query("
       create table betterbibtex.cache (
         itemID not null,

  throw 'format: no item\n' + (new Error('dummy')).stack if not item.itemType
  return item

require('preferences.coffee')
require('keymanager.coffee')
require('web-endpoints.coffee')


require('Formatter.js')

Zotero.BetterBibTeX = {
  serializer: Components.classes['@mozilla.org/xmlextras/xmlserializer;1'].createInstance(Components.interfaces.nsIDOMSerializer)
  document: Components.classes["@mozilla.org/xul/xul-document;1"].getService(Components.interfaces.nsIDOMDocument)
}

Zotero.BetterBibTeX.inspect = (o) ->
  clone = Object.create(null)
