@@ -5,23 +5,21 @@ use alloc::rc::Rc;
55use core:: ffi:: { c_char, c_int, c_void} ;
66
77use powersync_sqlite_nostd as sqlite;
8- use sqlite:: { Connection , ResultCode , Value } ;
8+ use sqlite:: { Connection , ResultCode } ;
99
10- use crate :: operations:: {
11- clear_remove_ops, delete_bucket, delete_pending_buckets, insert_operation,
12- } ;
1310use crate :: state:: DatabaseState ;
14- use crate :: sync_local:: sync_local;
1511use crate :: vtab_util:: * ;
1612
13+ /// A virtual table hack to implement a "pre-close hook" for databases.
14+ ///
15+ /// When `sqlite3_close` is called, SQLite invokes the disconnect callback of virtual tables
16+ /// attached to the connection. This gives us an opportunity to call
17+ /// [DatabaseState::release_resources], allowing us to close active sync clients and associated
18+ /// prepared statements. Without this, our internal statements might lease resources.
1719#[ repr( C ) ]
1820struct VirtualTable {
1921 base : sqlite:: vtab ,
20- db : * mut sqlite:: sqlite3 ,
2122 state : Rc < DatabaseState > ,
22-
23- target_applied : bool ,
24- target_validated : bool ,
2523}
2624
2725extern "C" fn connect (
@@ -32,9 +30,7 @@ extern "C" fn connect(
3230 vtab : * mut * mut sqlite:: vtab ,
3331 _err : * mut * mut c_char ,
3432) -> c_int {
35- if let Err ( rc) =
36- sqlite:: declare_vtab ( db, "CREATE TABLE powersync_operations(op TEXT, data TEXT);" )
37- {
33+ if let Err ( rc) = sqlite:: declare_vtab ( db, "CREATE TABLE powersync_internal_close(_ TEXT);" ) {
3834 return rc as c_int ;
3935 }
4036
@@ -45,10 +41,7 @@ extern "C" fn connect(
4541 pModule : core:: ptr:: null ( ) ,
4642 zErrMsg : core:: ptr:: null_mut ( ) ,
4743 } ,
48- db,
4944 state : DatabaseState :: clone_from ( aux) ,
50- target_validated : false ,
51- target_applied : false ,
5245 } ) ) ;
5346 * vtab = tab. cast :: < sqlite:: vtab > ( ) ;
5447 let _ = sqlite:: vtab_config ( db, 0 ) ;
@@ -69,57 +62,12 @@ extern "C" fn disconnect(vtab: *mut sqlite::vtab) -> c_int {
6962}
7063
7164extern "C" fn update (
72- vtab : * mut sqlite:: vtab ,
73- argc : c_int ,
74- argv : * mut * mut sqlite:: value ,
75- p_row_id : * mut sqlite:: int64 ,
65+ _vtab : * mut sqlite:: vtab ,
66+ _argc : c_int ,
67+ _argv : * mut * mut sqlite:: value ,
68+ _p_row_id : * mut sqlite:: int64 ,
7669) -> c_int {
77- let args = sqlite:: args!( argc, argv) ;
78-
79- let rowid = args[ 0 ] ;
80-
81- return if args. len ( ) == 1 {
82- // DELETE
83- ResultCode :: MISUSE as c_int
84- } else if rowid. value_type ( ) == sqlite:: ColumnType :: Null {
85- // INSERT
86- let op = args[ 2 ] . text ( ) ;
87-
88- let tab = unsafe { & mut * vtab. cast :: < VirtualTable > ( ) } ;
89- let db = tab. db ;
90-
91- if op == "save" {
92- let result = insert_operation ( db, args[ 3 ] . text ( ) ) ;
93- vtab_result ( vtab, result)
94- } else if op == "sync_local" {
95- let result = sync_local ( & tab. state , db, & args[ 3 ] ) ;
96- if let Ok ( result_row) = result {
97- unsafe {
98- * p_row_id = result_row;
99- }
100- }
101- vtab_result ( vtab, result)
102- } else if op == "clear_remove_ops" {
103- let result = clear_remove_ops ( db, args[ 3 ] . text ( ) ) ;
104- vtab_result ( vtab, result)
105- } else if op == "delete_pending_buckets" {
106- let result = delete_pending_buckets ( db, args[ 3 ] . text ( ) ) ;
107- vtab_result ( vtab, result)
108- } else if op == "delete_bucket" {
109- let result = delete_bucket ( db, args[ 3 ] . text ( ) ) ;
110- vtab_result ( vtab, result)
111- } else if op == "noop" {
112- // We call this to ensure the table is added to an active database, ensuring that
113- // the disconnect callback runs before the database is closed (allowing us to free
114- // resources from the client state).
115- ResultCode :: OK as c_int
116- } else {
117- ResultCode :: MISUSE as c_int
118- }
119- } else {
120- // UPDATE - not supported
121- ResultCode :: MISUSE as c_int
122- } as c_int ;
70+ 0
12371}
12472
12573// Insert-only virtual table.
@@ -155,7 +103,7 @@ static MODULE: sqlite::module = sqlite::module {
155103
156104pub fn register ( db : * mut sqlite:: sqlite3 , state : Rc < DatabaseState > ) -> Result < ( ) , ResultCode > {
157105 db. create_module_v2 (
158- "powersync_operations " ,
106+ "powersync_internal_close " ,
159107 & MODULE ,
160108 Some ( Rc :: into_raw ( state) as * mut c_void ) ,
161109 Some ( DatabaseState :: destroy_rc) ,
0 commit comments