diff --git a/sqlite3.go b/sqlite3.go index ce985ec8..811587ed 100644 --- a/sqlite3.go +++ b/sqlite3.go @@ -1876,6 +1876,9 @@ func (c *SQLiteConn) SetLimit(id int, newVal int) int { // This method is not thread-safe as the returned error code can be changed by // another call if invoked concurrently. // +// Use SetFileControlInt64 instead if the argument for the opcode is documented +// as a pointer to a sqlite3_int64. +// // See: sqlite3_file_control, https://www.sqlite.org/c3ref/file_control.html func (c *SQLiteConn) SetFileControlInt(dbName string, op int, arg int) error { if dbName == "" { @@ -1893,6 +1896,34 @@ func (c *SQLiteConn) SetFileControlInt(dbName string, op int, arg int) error { return nil } +// SetFileControlInt64 invokes the xFileControl method on a given database. The +// dbName is the name of the database. It will default to "main" if left blank. +// The op is one of the opcodes prefixed by "SQLITE_FCNTL_". The arg argument +// and return code are both opcode-specific. Please see the SQLite documentation. +// +// This method is not thread-safe as the returned error code can be changed by +// another call if invoked concurrently. +// +// Only use this method if the argument for the opcode is documented as a pointer +// to a sqlite3_int64. +// +// See: sqlite3_file_control, https://www.sqlite.org/c3ref/file_control.html +func (c *SQLiteConn) SetFileControlInt64(dbName string, op int, arg int64) error { + if dbName == "" { + dbName = "main" + } + + cDBName := C.CString(dbName) + defer C.free(unsafe.Pointer(cDBName)) + + cArg := C.sqlite3_int64(arg) + rv := C.sqlite3_file_control(c.db, cDBName, C.int(op), unsafe.Pointer(&cArg)) + if rv != C.SQLITE_OK { + return c.lastError() + } + return nil +} + // Close the statement. func (s *SQLiteStmt) Close() error { s.mu.Lock() diff --git a/sqlite3_test.go b/sqlite3_test.go index 63c939d3..522f49c5 100644 --- a/sqlite3_test.go +++ b/sqlite3_test.go @@ -1864,6 +1864,32 @@ func TestSetFileControlInt(t *testing.T) { }) } +func TestSetFileControlInt64(t *testing.T) { + const GiB = 1024 * 1024 * 1024 + + t.Run("", func(t *testing.T) { + + sql.Register("sqlite3_FCNTL_SIZE_LIMIT", &SQLiteDriver{ + ConnectHook: func(conn *SQLiteConn) error { + if err := conn.SetFileControlInt64("", SQLITE_FCNTL_SIZE_LIMIT, 4*GiB); err != nil { + return fmt.Errorf("Unexpected error from SetFileControlInt64(): %w", err) + } + return nil + }, + }) + + db, err := sql.Open("sqlite3", "file:/dbname?vfs=memdb") + if err != nil { + t.Fatal("Failed to open database:", err) + } + err = db.Ping() + if err != nil { + t.Fatal("Failed to ping", err) + } + db.Close() + }) +} + func TestNonColumnString(t *testing.T) { db, err := sql.Open("sqlite3", ":memory:") if err != nil {