@@ -176,6 +176,10 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
176
176
var SQLITE_BLOB = 4 ;
177
177
// var - Encodings, used for registering functions.
178
178
var SQLITE_UTF8 = 1 ;
179
+ // var - Authorizer Action Codes used to identify change types in updateHook
180
+ var SQLITE_INSERT = 18 ;
181
+ var SQLITE_UPDATE = 23 ;
182
+ var SQLITE_DELETE = 9 ;
179
183
// var - cwrap function
180
184
var sqlite3_open = cwrap ( "sqlite3_open" , "number" , [ "string" , "number" ] ) ;
181
185
var sqlite3_close_v2 = cwrap ( "sqlite3_close_v2" , "number" , [ "number" ] ) ;
@@ -344,6 +348,12 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
344
348
[ "number" ]
345
349
) ;
346
350
351
+ var sqlite3_update_hook = cwrap (
352
+ "sqlite3_update_hook" ,
353
+ "number" ,
354
+ [ "number" , "number" , "number" ]
355
+ ) ;
356
+
347
357
/**
348
358
* @classdesc
349
359
* Represents a prepared statement.
@@ -1219,6 +1229,12 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
1219
1229
} ) ;
1220
1230
Object . values ( this . functions ) . forEach ( removeFunction ) ;
1221
1231
this . functions = { } ;
1232
+
1233
+ if ( this . updateHookFunctionPtr ) {
1234
+ removeFunction ( this . updateHookFunctionPtr ) ;
1235
+ this . updateHookFunctionPtr = undefined ;
1236
+ }
1237
+
1222
1238
this . handleError ( sqlite3_close_v2 ( this . db ) ) ;
1223
1239
FS . unlink ( "/" + this . filename ) ;
1224
1240
this . db = null ;
@@ -1488,6 +1504,87 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
1488
1504
return this ;
1489
1505
} ;
1490
1506
1507
+ /** Registers the update hook with SQLite
1508
+ @param {function(operation, database, table, rowId) | null } callback
1509
+ executed whenever a row in any rowid table is changed
1510
+
1511
+ For each changed row, the callback is called once with the change
1512
+ ('insert', 'update' or 'delete'), the database name and table name
1513
+ where the change happened and the rowid of the row that has been
1514
+ changed.
1515
+
1516
+ rowid is cast to a plain number, if it exceeds Number.MAX_SAFE_INTEGER
1517
+ an error will be thrown.
1518
+
1519
+ The callback MUST NOT modify the database in any way.
1520
+
1521
+ Only a single callback can be registered. Unregister the callback by
1522
+ passing null.
1523
+
1524
+ Not called for some updates like ON REPLACE CONFLICT and TRUNCATE (a
1525
+ DELETE FROM without a WHERE clause).
1526
+
1527
+ See sqlite docs on sqlite3_update_hook for more details.
1528
+ */
1529
+ Database . prototype [ "updateHook" ] = function updateHook ( callback ) {
1530
+ if ( this . updateHookFunctionPtr ) {
1531
+ // unregister and cleanup a previously registered update hook
1532
+ sqlite3_update_hook ( this . db , 0 , 0 ) ;
1533
+ removeFunction ( this . updateHookFunctionPtr ) ;
1534
+ this . updateHookFunctionPtr = undefined ;
1535
+ }
1536
+
1537
+ if ( ! callback ) {
1538
+ // no new callback to register
1539
+ return ;
1540
+ }
1541
+
1542
+ // void(*)(void *,int ,char const *,char const *,sqlite3_int64)
1543
+ function wrappedCallback (
1544
+ ignored ,
1545
+ operationCode ,
1546
+ databaseNamePtr ,
1547
+ tableNamePtr ,
1548
+ rowIdBigInt
1549
+ ) {
1550
+ var operation ;
1551
+
1552
+ switch ( operationCode ) {
1553
+ case SQLITE_INSERT :
1554
+ operation = "insert" ;
1555
+ break ;
1556
+ case SQLITE_UPDATE :
1557
+ operation = "update" ;
1558
+ break ;
1559
+ case SQLITE_DELETE :
1560
+ operation = "delete" ;
1561
+ break ;
1562
+ default :
1563
+ throw "unknown operationCode in updateHook callback: "
1564
+ + operationCode ;
1565
+ }
1566
+
1567
+ var databaseName = UTF8ToString ( databaseNamePtr ) ;
1568
+ var tableName = UTF8ToString ( tableNamePtr ) ;
1569
+
1570
+ if ( rowIdBigInt > Number . MAX_SAFE_INTEGER ) {
1571
+ throw "rowId too big to fit inside a Number" ;
1572
+ }
1573
+
1574
+ var rowId = Number ( rowIdBigInt ) ;
1575
+
1576
+ callback ( operation , databaseName , tableName , rowId ) ;
1577
+ }
1578
+
1579
+ this . updateHookFunctionPtr = addFunction ( wrappedCallback , "viiiij" ) ;
1580
+
1581
+ sqlite3_update_hook (
1582
+ this . db ,
1583
+ this . updateHookFunctionPtr ,
1584
+ 0 // passed as the first arg to wrappedCallback
1585
+ ) ;
1586
+ } ;
1587
+
1491
1588
// export Database to Module
1492
1589
Module . Database = Database ;
1493
1590
} ;
@@ -6443,6 +6540,7 @@ var _sqlite3_normalized_sql = Module['_sqlite3_normalized_sql'] = createExportWr
6443
6540
var _sqlite3_changes = Module [ '_sqlite3_changes' ] = createExportWrapper ( 'sqlite3_changes' , 1 ) ;
6444
6541
var _sqlite3_close_v2 = Module [ '_sqlite3_close_v2' ] = createExportWrapper ( 'sqlite3_close_v2' , 1 ) ;
6445
6542
var _sqlite3_create_function_v2 = Module [ '_sqlite3_create_function_v2' ] = createExportWrapper ( 'sqlite3_create_function_v2' , 9 ) ;
6543
+ var _sqlite3_update_hook = Module [ '_sqlite3_update_hook' ] = createExportWrapper ( 'sqlite3_update_hook' , 3 ) ;
6446
6544
var _sqlite3_open = Module [ '_sqlite3_open' ] = createExportWrapper ( 'sqlite3_open' , 2 ) ;
6447
6545
var _strerror = createExportWrapper ( 'strerror' , 1 ) ;
6448
6546
var _malloc = Module [ '_malloc' ] = createExportWrapper ( 'malloc' , 1 ) ;
0 commit comments