@@ -12,7 +12,7 @@ use sqlite_nostd::{Connection, Context};
12
12
13
13
use crate :: error:: { PSResult , SQLiteError } ;
14
14
use 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} ;
16
16
17
17
fn powersync_drop_view_impl (
18
18
ctx : * mut sqlite:: context ,
@@ -254,6 +254,61 @@ INSERT INTO ps_migration(id, down_migrations) VALUES(3, json_array(json_object('
254
254
create_auto_tx_function ! ( powersync_init_tx, powersync_init_impl) ;
255
255
create_sqlite_text_fn ! ( powersync_init, powersync_init_tx, "powersync_init" ) ;
256
256
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
+
257
312
pub fn register ( db : * mut sqlite:: sqlite3 ) -> Result < ( ) , ResultCode > {
258
313
// This entire module is just making it easier to edit sqlite_master using queries.
259
314
// The primary interfaces exposed are:
@@ -312,6 +367,18 @@ pub fn register(db: *mut sqlite::sqlite3) -> Result<(), ResultCode> {
312
367
None ,
313
368
) ?;
314
369
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
+
315
382
db. create_function_v2 (
316
383
"powersync_external_table_name" ,
317
384
1 ,
0 commit comments