Skip to content

Commit 98cebcf

Browse files
authored
Use strict tables, any
1 parent 530f062 commit 98cebcf

6 files changed

Lines changed: 29 additions & 112 deletions

File tree

‎crates/core/src/schema/management.rs‎

Lines changed: 5 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ fn update_tables(
141141
let mut create = CreateTableStatement::from(table);
142142
if table.direct {
143143
for column in &table.columns {
144-
create.push_column(&column.name, &column.type_name);
144+
create.push_any_column(&column.name);
145145
}
146146
}
147147

@@ -184,24 +184,20 @@ fn direct_table_migration(
184184

185185
struct ExistingColumn<'a> {
186186
column: &'a Column,
187-
index_in_table: usize,
188187
found_in_old: bool,
189188
}
190189

191190
let mut new_columns: Vec<_> = new
192191
.columns
193192
.iter()
194-
.enumerate()
195-
.map(|(i, column)| ExistingColumn {
193+
.map(|column| ExistingColumn {
196194
column,
197-
index_in_table: i,
198195
found_in_old: false,
199196
})
200197
.collect();
201198
new_columns.sort_by(|a, b| a.column.name.cmp(&b.column.name));
202199

203200
let mut deleted_columns = vec![];
204-
let mut changed_column_types = vec![];
205201

206202
for old_column in &old.columns {
207203
let Ok(new_column_index) =
@@ -214,18 +210,12 @@ fn direct_table_migration(
214210
let new_column = &mut new_columns[new_column_index];
215211
new_column.found_in_old = true;
216212

217-
if !new_column
218-
.column
219-
.type_name
220-
.eq_ignore_ascii_case(&old_column.type_name)
221-
{
222-
changed_column_types.push((new_column.index_in_table, &new_column.column.type_name));
223-
}
213+
// For found columns, the type doesn't matter as we generate ANY types for all of them.
224214
}
225215

226216
new_columns.retain(|c| !c.found_in_old);
227217

228-
if new_columns.is_empty() && deleted_columns.is_empty() && changed_column_types.is_empty() {
218+
if new_columns.is_empty() && deleted_columns.is_empty() {
229219
return Ok(()); // Nothing to migrate.
230220
}
231221

@@ -250,48 +240,11 @@ fn direct_table_migration(
250240
}
251241
}
252242

253-
if !changed_column_types.is_empty() {
254-
// To change column types, we change the CREATE TABLE statement for the table. As long as
255-
// we do this in a way that doesn't alter the order of existing columns, this doesn't
256-
// corrupt data (column types in non-strict tables only affects type affinity for inserts
257-
// and updates). The proper way to run this migration requires copying data, which we want
258-
// to avoid.
259-
let schema_writable_before = db.has_writable_schema();
260-
if !schema_writable_before {
261-
db.set_writable_schema(true)?;
262-
}
263-
264-
let mut new_create_table = CreateTableStatement::from(new);
265-
let mut changed_column_types = changed_column_types.iter().peekable();
266-
267-
for (i, column) in old.columns.iter().enumerate() {
268-
let changed_type = changed_column_types
269-
.next_if(|(index, _)| *index == i)
270-
.map(|(_, type_name)| type_name.as_str());
271-
272-
new_create_table.push_column(&column.name, changed_type.unwrap_or(&column.type_name));
273-
}
274-
275-
let new_create_table = new_create_table.finish();
276-
277-
{
278-
let stmt = db
279-
.prepare_v2("UPDATE sqlite_schema SET sql = ? WHERE type = 'table' AND name = ?")?;
280-
stmt.bind_text(1, &new_create_table.sql, Destructor::STATIC)?;
281-
stmt.bind_text(2, &new.name, Destructor::STATIC)?;
282-
stmt.exec()?;
283-
}
284-
285-
if !schema_writable_before {
286-
db.set_writable_schema(false)?;
287-
}
288-
}
289-
290243
// Add new columns, drop old ones
291244
for new_column in new_columns {
292245
let mut stmt = SqlBuffer::new();
293246
stmt.alter_table(&new.name);
294-
stmt.add_column(new_column.column);
247+
stmt.add_column(&new_column.column.name, "ANY");
295248
db.exec_safe_str(&stmt.sql)?;
296249
}
297250

‎crates/core/src/schema/table_info.rs‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ pub enum PendingStatementValue {
506506

507507
pub struct CreateTableStatement {
508508
create_table: SqlBuffer,
509+
direct: bool,
509510
}
510511

511512
impl From<&Table> for CreateTableStatement {
@@ -526,18 +527,26 @@ impl From<&Table> for CreateTableStatement {
526527
create_table.push_str(", data TEXT");
527528
}
528529

529-
Self { create_table }
530+
Self {
531+
create_table,
532+
direct: value.direct,
533+
}
530534
}
531535
}
532536

533537
impl CreateTableStatement {
534-
pub fn push_column(&mut self, name: &str, type_name: &str) {
538+
pub fn push_any_column(&mut self, name: &str) {
535539
self.create_table.push_char(',');
536-
self.create_table.column_definition(name, type_name);
540+
self.create_table.column_definition(name, "ANY");
537541
}
538542

539543
pub fn finish(mut self) -> SqlBuffer {
540-
self.create_table.push_str(");");
544+
self.create_table.push_char(')');
545+
if self.direct {
546+
self.create_table.push_str(" STRICT");
547+
}
548+
549+
self.create_table.push_char(';');
541550
self.create_table
542551
}
543552
}

‎crates/core/src/utils/database.rs‎

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::ffi::{CStr, c_char, c_int};
1+
use core::ffi::{CStr, c_char};
22

33
use alloc::ffi::CString;
44
use num_traits::FromPrimitive;
@@ -83,37 +83,6 @@ impl Database {
8383
statement.bind_text(1, param, Destructor::STATIC)?;
8484
statement.exec()
8585
}
86-
87-
pub fn has_writable_schema(self) -> bool {
88-
let mut result: c_int = 0;
89-
let _ = sqlite::db_config(
90-
self.sqlite,
91-
sqlite::DBCONFIG_WRITABLE_SCHEMA,
92-
-1, // negative to leave the setting unchanged.
93-
&mut result,
94-
);
95-
result != 0
96-
}
97-
98-
pub fn set_writable_schema(self, enable: bool) -> Result<()> {
99-
let mut result = 0;
100-
let expected_result = if enable { 1 } else { 0 };
101-
102-
let _ = sqlite::db_config(
103-
self.sqlite,
104-
sqlite::DBCONFIG_WRITABLE_SCHEMA,
105-
expected_result,
106-
&mut result,
107-
);
108-
109-
if expected_result != result {
110-
return Err(PowerSyncError::state_error(
111-
"Could not apply writable schema",
112-
));
113-
}
114-
115-
Ok(())
116-
}
11786
}
11887

11988
pub struct Statement {

‎crates/core/src/utils/sql_buffer.rs‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ use core::{
66
use alloc::{format, string::String};
77

88
use crate::{
9-
error::PowerSyncError,
10-
schema::{Column, SchemaTable},
11-
views::table_columns_to_json_object_with_filter,
9+
error::PowerSyncError, schema::SchemaTable, views::table_columns_to_json_object_with_filter,
1210
};
1311

1412
const DOUBLE_QUOTE: char = '"';
@@ -125,9 +123,9 @@ impl SqlBuffer {
125123
let _ = self.identifier().write_str(name);
126124
}
127125

128-
pub fn add_column(&mut self, column: &Column) {
126+
pub fn add_column(&mut self, name: &str, type_name: &str) {
129127
self.push_str("ADD COLUMN ");
130-
self.column_definition(&column.name, &column.type_name);
128+
self.column_definition(name, type_name);
131129
}
132130

133131
pub fn column_definition(&mut self, name: &str, type_name: &str) {

‎crates/sqlite_nostd/src/capi.rs‎

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use alloc::borrow::ToOwned;
77
use alloc::ffi::CString;
88

99
pub use crate::bindings::{
10-
SQLITE_DBCONFIG_WRITABLE_SCHEMA as DBCONFIG_WRITABLE_SCHEMA,
1110
SQLITE_DETERMINISTIC as DETERMINISTIC, SQLITE_DIRECTONLY as DIRECTONLY,
1211
SQLITE_INDEX_CONSTRAINT_EQ as INDEX_CONSTRAINT_EQ,
1312
SQLITE_INDEX_CONSTRAINT_GE as INDEX_CONSTRAINT_GE,
@@ -50,13 +49,12 @@ mod aliased {
5049
sqlite3_column_value as column_value, sqlite3_commit_hook as commit_hook,
5150
sqlite3_context_db_handle as context_db_handle,
5251
sqlite3_create_function_v2 as create_function_v2,
53-
sqlite3_create_module_v2 as create_module_v2, sqlite3_db_config as db_config,
54-
sqlite3_declare_vtab as declare_vtab, sqlite3_errcode as errcode, sqlite3_errmsg as errmsg,
55-
sqlite3_error_offset as error_offset, sqlite3_exec as exec, sqlite3_finalize as finalize,
56-
sqlite3_free as free, sqlite3_get_autocommit as get_autocommit,
57-
sqlite3_get_auxdata as get_auxdata, sqlite3_libversion as libversion,
58-
sqlite3_libversion_number as libversion_number, sqlite3_malloc as malloc,
59-
sqlite3_malloc64 as malloc64, sqlite3_mutex_alloc as mutex_alloc,
52+
sqlite3_create_module_v2 as create_module_v2, sqlite3_declare_vtab as declare_vtab,
53+
sqlite3_errcode as errcode, sqlite3_errmsg as errmsg, sqlite3_error_offset as error_offset,
54+
sqlite3_exec as exec, sqlite3_finalize as finalize, sqlite3_free as free,
55+
sqlite3_get_autocommit as get_autocommit, sqlite3_get_auxdata as get_auxdata,
56+
sqlite3_libversion as libversion, sqlite3_libversion_number as libversion_number,
57+
sqlite3_malloc as malloc, sqlite3_malloc64 as malloc64, sqlite3_mutex_alloc as mutex_alloc,
6058
sqlite3_mutex_enter as mutex_enter, sqlite3_mutex_free as mutex_free,
6159
sqlite3_mutex_leave as mutex_leave, sqlite3_mutex_try as mutex_try,
6260
sqlite3_next_stmt as next_stmt, sqlite3_open as open, sqlite3_prepare_v2 as prepare_v2,
@@ -227,16 +225,6 @@ pub fn close(db: *mut sqlite3) -> c_int {
227225
unsafe { invoke_sqlite!(close, db) }
228226
}
229227

230-
pub extern "C" fn db_config(
231-
db: *mut sqlite3,
232-
op: c_uint,
233-
option: c_int,
234-
result: &mut c_int,
235-
) -> c_int {
236-
let ptr = core::ptr::from_mut(result);
237-
unsafe { invoke_sqlite!(db_config, db, op as c_int, option, ptr) }
238-
}
239-
240228
pub fn vtab_config(db: *mut sqlite3, options: u32) -> c_int {
241229
unsafe { invoke_sqlite!(vtab_config, db, options as i32) }
242230
}

‎dart/test/schema_test.dart‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ END''',
370370
)[0].columnAt(0);
371371
expect(
372372
createTable,
373-
'CREATE TABLE "users"(id TEXT PRIMARY KEY NOT NULL /* ps-managed */,"name" text)',
373+
'CREATE TABLE "users"(id TEXT PRIMARY KEY NOT NULL /* ps-managed */,"name" ANY) STRICT',
374374
);
375375

376376
final triggers = db

0 commit comments

Comments
 (0)