sqlite3_opt_serialize.go raw

   1  //go:build !libsqlite3 || sqlite_serialize
   2  // +build !libsqlite3 sqlite_serialize
   3  
   4  package sqlite3
   5  
   6  /*
   7  #ifndef USE_LIBSQLITE3
   8  #include <sqlite3-binding.h>
   9  #else
  10  #include <sqlite3.h>
  11  #endif
  12  #include <stdlib.h>
  13  #include <stdint.h>
  14  */
  15  import "C"
  16  
  17  import (
  18  	"fmt"
  19  	"math"
  20  	"reflect"
  21  	"unsafe"
  22  )
  23  
  24  // Serialize returns a byte slice that is a serialization of the database.
  25  //
  26  // See https://www.sqlite.org/c3ref/serialize.html
  27  func (c *SQLiteConn) Serialize(schema string) ([]byte, error) {
  28  	if schema == "" {
  29  		schema = "main"
  30  	}
  31  	var zSchema *C.char
  32  	zSchema = C.CString(schema)
  33  	defer C.free(unsafe.Pointer(zSchema))
  34  
  35  	var sz C.sqlite3_int64
  36  	ptr := C.sqlite3_serialize(c.db, zSchema, &sz, 0)
  37  	if ptr == nil {
  38  		return nil, fmt.Errorf("serialize failed")
  39  	}
  40  	defer C.sqlite3_free(unsafe.Pointer(ptr))
  41  
  42  	if sz > C.sqlite3_int64(math.MaxInt) {
  43  		return nil, fmt.Errorf("serialized database is too large (%d bytes)", sz)
  44  	}
  45  
  46  	cBuf := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
  47  		Data: uintptr(unsafe.Pointer(ptr)),
  48  		Len:  int(sz),
  49  		Cap:  int(sz),
  50  	}))
  51  
  52  	res := make([]byte, int(sz))
  53  	copy(res, cBuf)
  54  	return res, nil
  55  }
  56  
  57  // Deserialize causes the connection to disconnect from the current database and
  58  // then re-open as an in-memory database based on the contents of the byte slice.
  59  //
  60  // See https://www.sqlite.org/c3ref/deserialize.html
  61  func (c *SQLiteConn) Deserialize(b []byte, schema string) error {
  62  	if schema == "" {
  63  		schema = "main"
  64  	}
  65  	var zSchema *C.char
  66  	zSchema = C.CString(schema)
  67  	defer C.free(unsafe.Pointer(zSchema))
  68  
  69  	tmpBuf := (*C.uchar)(C.sqlite3_malloc64(C.sqlite3_uint64(len(b))))
  70  	cBuf := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
  71  		Data: uintptr(unsafe.Pointer(tmpBuf)),
  72  		Len:  len(b),
  73  		Cap:  len(b),
  74  	}))
  75  	copy(cBuf, b)
  76  
  77  	rc := C.sqlite3_deserialize(c.db, zSchema, tmpBuf, C.sqlite3_int64(len(b)),
  78  		C.sqlite3_int64(len(b)), C.SQLITE_DESERIALIZE_FREEONCLOSE)
  79  	if rc != C.SQLITE_OK {
  80  		return fmt.Errorf("deserialize failed with return %v", rc)
  81  	}
  82  	return nil
  83  }
  84