uqa_storage/sqlite/catalog/migration/
registry.rs1use super::super::{
10 params, Catalog, ManagedConnection, OptionalExtension, Result, SQLiteError,
11 CURRENT_SCHEMA_VERSION,
12};
13use super::steps::{MigrationAction, MIGRATIONS};
14
15impl Catalog {
16 pub fn open(conn: ManagedConnection) -> Result<Self> {
18 let mut cat = Self {
19 conn,
20 fts_storage_was_reset: false,
21 };
22 cat.fts_storage_was_reset = cat.run_migrations()?;
23 Ok(cat)
24 }
25
26 pub fn connection(&self) -> ManagedConnection {
27 self.conn.clone()
28 }
29
30 pub(super) fn run_migrations(&self) -> Result<bool> {
31 self.conn.with_mut(|conn| {
32 let legacy_meta_only: bool = conn
36 .query_row(
37 "SELECT \
38 (SELECT COUNT(*) FROM sqlite_master \
39 WHERE type='table' AND name='_meta') > 0 \
40 AND (SELECT COUNT(*) FROM sqlite_master \
41 WHERE type='table' AND name='_metadata') = 0",
42 [],
43 |r| r.get::<_, i64>(0),
44 )
45 .optional()?
46 .is_some_and(|n| n != 0);
47 if legacy_meta_only {
48 conn.execute("ALTER TABLE _meta RENAME TO _metadata", [])?;
49 }
50 conn.execute(
51 "CREATE TABLE IF NOT EXISTS _metadata (
52 key TEXT PRIMARY KEY,
53 value TEXT NOT NULL
54 )",
55 [],
56 )?;
57 let current = conn
58 .query_row(
59 "SELECT value FROM _metadata WHERE key = 'schema_version'",
60 [],
61 |r| r.get::<_, String>(0),
62 )
63 .optional()?;
64 let current = match current {
65 Some(version) => version
66 .parse::<u32>()
67 .map_err(|_| SQLiteError::InvalidSchemaVersion(version))?,
68 None => 0,
69 };
70 if current > CURRENT_SCHEMA_VERSION {
71 return Err(SQLiteError::UnsupportedSchemaVersion {
72 found: current,
73 supported: CURRENT_SCHEMA_VERSION,
74 });
75 }
76
77 debug_assert_eq!(
78 MIGRATIONS.last().map(|migration| migration.version),
79 Some(CURRENT_SCHEMA_VERSION)
80 );
81 for migration in &MIGRATIONS {
82 if migration.version > current {
83 let tx = conn.transaction()?;
84 match migration.action {
85 MigrationAction::Sql(sql) => tx.execute_batch(sql)?,
86 MigrationAction::Custom(migrate) => migrate(&tx)?,
87 }
88 tx.execute(
89 "INSERT OR REPLACE INTO _metadata (key, value) \
90 VALUES ('schema_version', ?1)",
91 params![migration.version.to_string()],
92 )?;
93 tx.commit()?;
94 }
95 }
96 let repair = conn.savepoint()?;
97 let schema_before_repair: i64 =
98 repair.pragma_query_value(None, "schema_version", |row| row.get(0))?;
99 Self::ensure_column_stats_shape(&repair)?;
100 let fts_storage_was_reset = Self::ensure_fts_storage_shape(&repair)?;
101 let schema_after_repair: i64 =
102 repair.pragma_query_value(None, "schema_version", |row| row.get(0))?;
103 if schema_before_repair != schema_after_repair {
104 Self::install_cache_revision_tracking(&repair)?;
105 }
106 repair.commit()?;
107 Ok(fts_storage_was_reset)
108 })
109 }
110}