2019-08-21 21:04:45 +00:00
|
|
|
// Copyright (C) 2019 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
|
|
|
// Copyright (C) 2018 segment.com <friends@segment.com>
|
2019-11-18 09:03:31 +00:00
|
|
|
//
|
2019-08-21 21:04:45 +00:00
|
|
|
// Use of this source code is governed by an MIT-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// +build sqlite_preupdate_hook
|
|
|
|
|
|
|
|
package sqlite3
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
type preUpdateHookDataForTest struct {
|
|
|
|
databaseName string
|
|
|
|
tableName string
|
|
|
|
count int
|
|
|
|
op int
|
|
|
|
oldRow []interface{}
|
|
|
|
newRow []interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPreUpdateHook(t *testing.T) {
|
|
|
|
var events []preUpdateHookDataForTest
|
|
|
|
|
|
|
|
sql.Register("sqlite3_PreUpdateHook", &SQLiteDriver{
|
|
|
|
ConnectHook: func(conn *SQLiteConn) error {
|
|
|
|
conn.RegisterPreUpdateHook(func(data SQLitePreUpdateData) {
|
|
|
|
eval := -1
|
|
|
|
oldRow := []interface{}{eval}
|
|
|
|
if data.Op != SQLITE_INSERT {
|
|
|
|
err := data.Old(oldRow...)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error calling SQLitePreUpdateData.Old: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
eval2 := -1
|
|
|
|
newRow := []interface{}{eval2}
|
|
|
|
if data.Op != SQLITE_DELETE {
|
|
|
|
err := data.New(newRow...)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error calling SQLitePreUpdateData.New: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// tests dest bound checks in loop
|
|
|
|
var tooSmallRow []interface{}
|
|
|
|
if data.Op != SQLITE_INSERT {
|
|
|
|
err := data.Old(tooSmallRow...)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error calling SQLitePreUpdateData.Old: %v", err)
|
|
|
|
}
|
|
|
|
if len(tooSmallRow) != 0 {
|
|
|
|
t.Errorf("Expected tooSmallRow to be empty, got: %v", tooSmallRow)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
events = append(events, preUpdateHookDataForTest{
|
|
|
|
databaseName: data.DatabaseName,
|
|
|
|
tableName: data.TableName,
|
|
|
|
count: data.Count(),
|
|
|
|
op: data.Op,
|
|
|
|
oldRow: oldRow,
|
|
|
|
newRow: newRow,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
db, err := sql.Open("sqlite3_PreUpdateHook", ":memory:")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal("Failed to open database:", err)
|
|
|
|
}
|
|
|
|
defer db.Close()
|
|
|
|
|
|
|
|
statements := []string{
|
|
|
|
"create table foo (id integer primary key)",
|
|
|
|
"insert into foo values (9)",
|
|
|
|
"update foo set id = 99 where id = 9",
|
|
|
|
"delete from foo where id = 99",
|
|
|
|
}
|
|
|
|
for _, statement := range statements {
|
|
|
|
_, err = db.Exec(statement)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to prepare test data [%v]: %v", statement, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(events) != 3 {
|
|
|
|
t.Errorf("Events should be 3 entries, got: %d", len(events))
|
|
|
|
}
|
|
|
|
|
|
|
|
if events[0].op != SQLITE_INSERT {
|
|
|
|
t.Errorf("Op isn't as expected: %v", events[0].op)
|
|
|
|
}
|
|
|
|
|
|
|
|
if events[1].op != SQLITE_UPDATE {
|
|
|
|
t.Errorf("Op isn't as expected: %v", events[1].op)
|
|
|
|
}
|
|
|
|
|
|
|
|
if events[1].count != 1 {
|
|
|
|
t.Errorf("Expected event row 1 to have 1 column, had: %v", events[1].count)
|
|
|
|
}
|
|
|
|
|
|
|
|
newRow_0_0 := events[0].newRow[0].(int64)
|
|
|
|
if newRow_0_0 != 9 {
|
|
|
|
t.Errorf("Expected event row 0 new column 0 to be == 9, got: %v", newRow_0_0)
|
|
|
|
}
|
|
|
|
|
|
|
|
oldRow_1_0 := events[1].oldRow[0].(int64)
|
|
|
|
if oldRow_1_0 != 9 {
|
|
|
|
t.Errorf("Expected event row 1 old column 0 to be == 9, got: %v", oldRow_1_0)
|
|
|
|
}
|
|
|
|
|
|
|
|
newRow_1_0 := events[1].newRow[0].(int64)
|
|
|
|
if newRow_1_0 != 99 {
|
|
|
|
t.Errorf("Expected event row 1 new column 0 to be == 99, got: %v", newRow_1_0)
|
|
|
|
}
|
|
|
|
|
|
|
|
oldRow_2_0 := events[2].oldRow[0].(int64)
|
|
|
|
if oldRow_2_0 != 99 {
|
|
|
|
t.Errorf("Expected event row 1 new column 0 to be == 99, got: %v", oldRow_2_0)
|
|
|
|
}
|
|
|
|
}
|