fix(db): fix migration failures when upgrading from 0.8.0 schema
Migration 1: remove idx_sessions_token_hash from _SCHEMA_STATEMENTS. The legacy schema has sessions.token (not token_hash). The IF NOT EXISTS guard only prevents duplicate index names — it still requires the column to exist. Migration 2 drops and rebuilds sessions with token_hash anyway, so creating the index in migration 1 was redundant. Migration 3: replace ALTER TABLE ADD COLUMN with a table rebuild. SQLite rejects ALTER TABLE ADD COLUMN NOT NULL DEFAULT <expression> when the table already contains rows. The old DB has ~181k geo_cache rows, so the ALTER always failed. Rebuild copies existing rows with last_seen set to cached_at as a reasonable approximation of last-seen time.
This commit is contained in:
@@ -102,10 +102,15 @@ CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||
"""
|
||||
|
||||
# Ordered list of DDL statements to execute on initialisation.
|
||||
# NOTE: _CREATE_SESSIONS_TOKEN_INDEX is intentionally omitted here.
|
||||
# The old 0.8.0 schema has a `sessions.token` column (not `token_hash`), so
|
||||
# running CREATE INDEX … ON sessions (token_hash) in migration 1 would fail
|
||||
# with "no such column: token_hash" on legacy databases. Migration 2 drops
|
||||
# and recreates the sessions table with token_hash and also creates the index,
|
||||
# so there is no need to create it in migration 1.
|
||||
_SCHEMA_STATEMENTS: list[str] = [
|
||||
_CREATE_SETTINGS,
|
||||
_CREATE_SESSIONS,
|
||||
_CREATE_SESSIONS_TOKEN_INDEX,
|
||||
_CREATE_BLOCKLIST_SOURCES,
|
||||
_CREATE_IMPORT_LOG,
|
||||
_CREATE_GEO_CACHE,
|
||||
@@ -133,8 +138,24 @@ CREATE UNIQUE INDEX idx_sessions_token_hash ON sessions (token_hash);
|
||||
3: """
|
||||
-- Migration 3: Add last_seen timestamp to geo_cache for retention policy.
|
||||
-- Tracks when each IP was last referenced to enable purging of stale entries.
|
||||
-- Default to current timestamp for existing rows.
|
||||
ALTER TABLE geo_cache ADD COLUMN last_seen TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
|
||||
-- SQLite rejects ALTER TABLE ADD COLUMN with a non-constant NOT NULL default
|
||||
-- when the table already contains rows, so we rebuild the table instead.
|
||||
-- Existing rows receive last_seen = cached_at as a reasonable approximation
|
||||
-- (the IP was at least seen when it was first cached).
|
||||
DROP TABLE IF EXISTS geo_cache_new;
|
||||
CREATE TABLE geo_cache_new (
|
||||
ip TEXT PRIMARY KEY,
|
||||
country_code TEXT,
|
||||
country_name TEXT,
|
||||
asn TEXT,
|
||||
org TEXT,
|
||||
cached_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
||||
last_seen TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
||||
);
|
||||
INSERT INTO geo_cache_new (ip, country_code, country_name, asn, org, cached_at, last_seen)
|
||||
SELECT ip, country_code, country_name, asn, org, cached_at, cached_at FROM geo_cache;
|
||||
DROP TABLE geo_cache;
|
||||
ALTER TABLE geo_cache_new RENAME TO geo_cache;
|
||||
""",
|
||||
4: """
|
||||
-- Migration 4: Add scheduler_lock table for multi-worker safety.
|
||||
|
||||
Reference in New Issue
Block a user