[Question] How to register update hook?
I have tried to register the update hook with sqlite3.Xsqlite3_update_hook, but no luck. Can you tell me what I did wrong?
I am using "github.com/glebarez/sqlite" for GORM driver, access the *conn with sql.Conn.Raw(), see code:
import (
sqlite3 "modernc.org/sqlite/lib"
"github.com/glebarez/sqlite"
"modernc.org/libc"
)
//...
serverDsn := filepath.Join(serverDBPath, SERVER_DB_NAME+".db") + ""
if svDB, err := gorm.Open(sqlite.Open(serverDsn), &gorm.Config{SkipDefaultTransaction: true, PrepareStmt: true}); err == nil {
//Now run migrations
if err := svDB.AutoMigrate(ALL_MODELS...); err != nil {
return fmt.Errorf("failed auto migration for server database, %v", err)
}
//Register the update hook callback
sqlDB, _ := svDB.DB()
sqlDBConn, _ := sqlDB.Conn(context.Background())
if err := sqlDBConn.Raw(func(driverConn any) error { //`driverConn` is a type of `*sqlite3.conn`
dcVal := reflect.ValueOf(driverConn).Elem()
//
var db uintptr
var tls *libc.TLS
if dcField := dcVal.FieldByName("db"); dcField.IsValid() {
db = uintptr(dcField.UnsafeAddr())
} else {
return fmt.Errorf("failed to get [db] field value")
}
if dcField := dcVal.FieldByName("tls"); dcField.IsValid() {
tls = *(**libc.TLS)(unsafe.Pointer(dcField.UnsafeAddr()))
} else {
return fmt.Errorf("failed to get [tls] field value")
}
//
if rc := sqlite3.Xsqlite3_update_hook(tls, db, *(*uintptr)(unsafe.Pointer(&struct {
f func(unsafe.Pointer, int, *byte, *byte, int64)
}{updateHookCallback})), 0); rc != sqlite3.SQLITE_OK {
return fmt.Errorf("failed to register update hook callback in [sqlite3_update_hook], return code %v", rc)
}
//
return nil
}); err != nil {
return fmt.Errorf("failed to register callbacks for the database, %v", err)
}
// Define a callback function to be invoked on database updates
func updateHookCallback(userData unsafe.Pointer, operation int, dbName, tableName *byte, rowID int64) {
//Convert the table name from C string to Go string
tableNameStr := ut.CStringToString(tableName)
//Determine the operation type
var operationStr string
switch operation {
case sqlite3.SQLITE_INSERT:
operationStr = "INSERT"
case sqlite3.SQLITE_DELETE:
operationStr = "DELETE"
case sqlite3.SQLITE_UPDATE:
operationStr = "UPDATE"
}
// Print the callback message
fmt.Printf("Row %d in table %s was %s\n", rowID, tableNameStr, operationStr)
}
Edited by KiddoV