@@ -71,6 +71,10 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
71
71
var SQLITE_BLOB = 4 ;
72
72
// var - Encodings, used for registering functions.
73
73
var SQLITE_UTF8 = 1 ;
74
+ // var - Authorizer Action Codes used to identify change types in updateHook
75
+ var SQLITE_INSERT = 18 ;
76
+ var SQLITE_UPDATE = 23 ;
77
+ var SQLITE_DELETE = 9 ;
74
78
// var - cwrap function
75
79
var sqlite3_open = cwrap ( "sqlite3_open" , "number" , [ "string" , "number" ] ) ;
76
80
var sqlite3_close_v2 = cwrap ( "sqlite3_close_v2" , "number" , [ "number" ] ) ;
@@ -239,6 +243,12 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
239
243
[ "number" ]
240
244
) ;
241
245
246
+ var sqlite3_update_hook = cwrap (
247
+ "sqlite3_update_hook" ,
248
+ "number" ,
249
+ [ "number" , "number" , "number" ]
250
+ ) ;
251
+
242
252
/**
243
253
* @classdesc
244
254
* Represents a prepared statement.
@@ -1114,6 +1124,12 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
1114
1124
} ) ;
1115
1125
Object . values ( this . functions ) . forEach ( removeFunction ) ;
1116
1126
this . functions = { } ;
1127
+
1128
+ if ( this . updateHookFunctionPtr ) {
1129
+ removeFunction ( this . updateHookFunctionPtr ) ;
1130
+ this . updateHookFunctionPtr = undefined ;
1131
+ }
1132
+
1117
1133
this . handleError ( sqlite3_close_v2 ( this . db ) ) ;
1118
1134
FS . unlink ( "/" + this . filename ) ;
1119
1135
this . db = null ;
@@ -1383,6 +1399,87 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
1383
1399
return this ;
1384
1400
} ;
1385
1401
1402
+ /** Registers the update hook with SQLite
1403
+ @param {function(operation, database, table, rowId) | null } callback
1404
+ executed whenever a row in any rowid table is changed
1405
+
1406
+ For each changed row, the callback is called once with the change
1407
+ ('insert', 'update' or 'delete'), the database name and table name
1408
+ where the change happened and the rowid of the row that has been
1409
+ changed.
1410
+
1411
+ rowid is cast to a plain number, if it exceeds Number.MAX_SAFE_INTEGER
1412
+ an error will be thrown.
1413
+
1414
+ The callback MUST NOT modify the database in any way.
1415
+
1416
+ Only a single callback can be registered. Unregister the callback by
1417
+ passing null.
1418
+
1419
+ Not called for some updates like ON REPLACE CONFLICT and TRUNCATE (a
1420
+ DELETE FROM without a WHERE clause).
1421
+
1422
+ See sqlite docs on sqlite3_update_hook for more details.
1423
+ */
1424
+ Database . prototype [ "updateHook" ] = function updateHook ( callback ) {
1425
+ if ( this . updateHookFunctionPtr ) {
1426
+ // unregister and cleanup a previously registered update hook
1427
+ sqlite3_update_hook ( this . db , 0 , 0 ) ;
1428
+ removeFunction ( this . updateHookFunctionPtr ) ;
1429
+ this . updateHookFunctionPtr = undefined ;
1430
+ }
1431
+
1432
+ if ( ! callback ) {
1433
+ // no new callback to register
1434
+ return ;
1435
+ }
1436
+
1437
+ // void(*)(void *,int ,char const *,char const *,sqlite3_int64)
1438
+ function wrappedCallback (
1439
+ ignored ,
1440
+ operationCode ,
1441
+ databaseNamePtr ,
1442
+ tableNamePtr ,
1443
+ rowIdBigInt
1444
+ ) {
1445
+ var operation ;
1446
+
1447
+ switch ( operationCode ) {
1448
+ case SQLITE_INSERT :
1449
+ operation = "insert" ;
1450
+ break ;
1451
+ case SQLITE_UPDATE :
1452
+ operation = "update" ;
1453
+ break ;
1454
+ case SQLITE_DELETE :
1455
+ operation = "delete" ;
1456
+ break ;
1457
+ default :
1458
+ throw "unknown operationCode in updateHook callback: "
1459
+ + operationCode ;
1460
+ }
1461
+
1462
+ var databaseName = UTF8ToString ( databaseNamePtr ) ;
1463
+ var tableName = UTF8ToString ( tableNamePtr ) ;
1464
+
1465
+ if ( rowIdBigInt > Number . MAX_SAFE_INTEGER ) {
1466
+ throw "rowId too big to fit inside a Number" ;
1467
+ }
1468
+
1469
+ var rowId = Number ( rowIdBigInt ) ;
1470
+
1471
+ callback ( operation , databaseName , tableName , rowId ) ;
1472
+ }
1473
+
1474
+ this . updateHookFunctionPtr = addFunction ( wrappedCallback , "viiiij" ) ;
1475
+
1476
+ sqlite3_update_hook (
1477
+ this . db ,
1478
+ this . updateHookFunctionPtr ,
1479
+ 0 // passed as the first arg to wrappedCallback
1480
+ ) ;
1481
+ } ;
1482
+
1386
1483
// export Database to Module
1387
1484
Module . Database = Database ;
1388
1485
} ;
0 commit comments