84 lines
1.9 KiB
Go
84 lines
1.9 KiB
Go
|
//go:build !libsqlite3 || sqlite_serialize
|
||
|
// +build !libsqlite3 sqlite_serialize
|
||
|
|
||
|
package sqlite3
|
||
|
|
||
|
/*
|
||
|
#ifndef USE_LIBSQLITE3
|
||
|
#include <sqlite3-binding.h>
|
||
|
#else
|
||
|
#include <sqlite3.h>
|
||
|
#endif
|
||
|
#include <stdlib.h>
|
||
|
#include <stdint.h>
|
||
|
*/
|
||
|
import "C"
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"math"
|
||
|
"reflect"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
// Serialize returns a byte slice that is a serialization of the database.
|
||
|
//
|
||
|
// See https://www.sqlite.org/c3ref/serialize.html
|
||
|
func (c *SQLiteConn) Serialize(schema string) ([]byte, error) {
|
||
|
if schema == "" {
|
||
|
schema = "main"
|
||
|
}
|
||
|
var zSchema *C.char
|
||
|
zSchema = C.CString(schema)
|
||
|
defer C.free(unsafe.Pointer(zSchema))
|
||
|
|
||
|
var sz C.sqlite3_int64
|
||
|
ptr := C.sqlite3_serialize(c.db, zSchema, &sz, 0)
|
||
|
if ptr == nil {
|
||
|
return nil, fmt.Errorf("serialize failed")
|
||
|
}
|
||
|
defer C.sqlite3_free(unsafe.Pointer(ptr))
|
||
|
|
||
|
if sz > C.sqlite3_int64(math.MaxInt) {
|
||
|
return nil, fmt.Errorf("serialized database is too large (%d bytes)", sz)
|
||
|
}
|
||
|
|
||
|
cBuf := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
||
|
Data: uintptr(unsafe.Pointer(ptr)),
|
||
|
Len: int(sz),
|
||
|
Cap: int(sz),
|
||
|
}))
|
||
|
|
||
|
res := make([]byte, int(sz))
|
||
|
copy(res, cBuf)
|
||
|
return res, nil
|
||
|
}
|
||
|
|
||
|
// Deserialize causes the connection to disconnect from the current database and
|
||
|
// then re-open as an in-memory database based on the contents of the byte slice.
|
||
|
//
|
||
|
// See https://www.sqlite.org/c3ref/deserialize.html
|
||
|
func (c *SQLiteConn) Deserialize(b []byte, schema string) error {
|
||
|
if schema == "" {
|
||
|
schema = "main"
|
||
|
}
|
||
|
var zSchema *C.char
|
||
|
zSchema = C.CString(schema)
|
||
|
defer C.free(unsafe.Pointer(zSchema))
|
||
|
|
||
|
tmpBuf := (*C.uchar)(C.sqlite3_malloc64(C.sqlite3_uint64(len(b))))
|
||
|
cBuf := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
||
|
Data: uintptr(unsafe.Pointer(tmpBuf)),
|
||
|
Len: len(b),
|
||
|
Cap: len(b),
|
||
|
}))
|
||
|
copy(cBuf, b)
|
||
|
|
||
|
rc := C.sqlite3_deserialize(c.db, zSchema, tmpBuf, C.sqlite3_int64(len(b)),
|
||
|
C.sqlite3_int64(len(b)), C.SQLITE_DESERIALIZE_FREEONCLOSE)
|
||
|
if rc != C.SQLITE_OK {
|
||
|
return fmt.Errorf("deserialize failed with return %v", rc)
|
||
|
}
|
||
|
return nil
|
||
|
}
|