@@ -12,7 +12,7 @@ use sqlite_nostd::{Connection, Context};
1212
1313use crate :: error:: { PSResult , SQLiteError } ;
1414use crate :: util:: quote_identifier;
15- use crate :: { create_auto_tx_function, create_sqlite_text_fn} ;
15+ use crate :: { create_auto_tx_function, create_sqlite_optional_text_fn , create_sqlite_text_fn} ;
1616
1717fn powersync_drop_view_impl (
1818 ctx : * mut sqlite:: context ,
@@ -254,6 +254,61 @@ INSERT INTO ps_migration(id, down_migrations) VALUES(3, json_array(json_object('
254254create_auto_tx_function ! ( powersync_init_tx, powersync_init_impl) ;
255255create_sqlite_text_fn ! ( powersync_init, powersync_init_tx, "powersync_init" ) ;
256256
257+ fn powersync_clear_impl (
258+ ctx : * mut sqlite:: context ,
259+ args : & [ * mut sqlite:: value ] ,
260+ ) -> Result < String , SQLiteError > {
261+ let local_db = ctx. db_handle ( ) ;
262+
263+ let clear_local = args[ 0 ] . int ( ) ;
264+
265+ // language=SQLite
266+ local_db. exec_safe (
267+ "\
268+ DELETE FROM ps_oplog;
269+ DELETE FROM ps_crud;
270+ DELETE FROM ps_buckets;
271+ DELETE FROM ps_untyped;
272+ DELETE FROM ps_kv WHERE key != 'client_id';
273+ " ,
274+ ) ?;
275+
276+ let table_glob = if clear_local != 0 {
277+ "ps_data_*"
278+ } else {
279+ "ps_data__*"
280+ } ;
281+
282+ let tables_stmt = local_db
283+ . prepare_v2 ( "SELECT name FROM sqlite_master WHERE type='table' AND name GLOB ?1" ) ?;
284+ tables_stmt. bind_text ( 1 , table_glob, sqlite:: Destructor :: STATIC ) ;
285+
286+ let mut tables: Vec < String > = alloc:: vec![ ] ;
287+
288+ while tables_stmt. step ( ) ? == ResultCode :: ROW {
289+ let name = tables_stmt. column_text ( 0 ) ?;
290+ tables. push ( name. to_string ( ) ) ;
291+ }
292+
293+ for name in tables {
294+ let quoted = quote_identifier ( & name) ;
295+ // The first delete statement deletes a single row, to trigger an update notification for the table.
296+ // The second delete statement uses the truncate optimization to delete the remainder of the data.
297+ let delete_sql = format ! (
298+ "\
299+ DELETE FROM {table} WHERE rowid IN (SELECT rowid FROM {table} LIMIT 1);
300+ DELETE FROM {table};" ,
301+ table = quoted
302+ ) ;
303+ local_db. exec_safe ( & delete_sql) ?;
304+ }
305+
306+ Ok ( String :: from ( "" ) )
307+ }
308+
309+ create_auto_tx_function ! ( powersync_clear_tx, powersync_clear_impl) ;
310+ create_sqlite_text_fn ! ( powersync_clear, powersync_clear_tx, "powersync_clear" ) ;
311+
257312pub fn register ( db : * mut sqlite:: sqlite3 ) -> Result < ( ) , ResultCode > {
258313 // This entire module is just making it easier to edit sqlite_master using queries.
259314 // The primary interfaces exposed are:
@@ -312,6 +367,18 @@ pub fn register(db: *mut sqlite::sqlite3) -> Result<(), ResultCode> {
312367 None ,
313368 ) ?;
314369
370+ // Initialize the extension internal tables.
371+ db. create_function_v2 (
372+ "powersync_clear" ,
373+ 1 ,
374+ sqlite:: UTF8 ,
375+ None ,
376+ Some ( powersync_clear) ,
377+ None ,
378+ None ,
379+ None ,
380+ ) ?;
381+
315382 db. create_function_v2 (
316383 "powersync_external_table_name" ,
317384 1 ,
0 commit comments