bump godeps

This commit is contained in:
Nathan McCauley 2015-04-28 17:01:39 -07:00
parent b858e939a3
commit 97e83d3238
22 changed files with 501 additions and 153304 deletions

6
Godeps/Godeps.json generated
View File

@ -6,9 +6,9 @@
],
"Deps": [
{
"ImportPath": "code.google.com/p/go-sqlite/go1/sqlite3",
"Comment": "null-50",
"Rev": "6e75c20f8fc4b936bccab88336915333ae165754"
"ImportPath": "code.google.com/p/gosqlite/sqlite3",
"Comment": "null-16",
"Rev": "74691fb6f83716190870cde1b658538dd4b18eb0"
},
{
"ImportPath": "github.com/agl/ed25519",

View File

@ -1,92 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sqlite3
/*
#include "sqlite3.h"
*/
import "C"
import (
"io"
"runtime"
)
// Backup is a handle to an online backup operation between two databases.
// [http://www.sqlite.org/c3ref/backup.html]
type Backup struct {
src *Conn
dst *Conn
bkup *C.sqlite3_backup
}
// newBackup initializes an online backup operation from src.srcName to
// dst.dstName.
func newBackup(src *Conn, srcName string, dst *Conn, dstName string) (*Backup, error) {
srcName += "\x00"
dstName += "\x00"
bkup := C.sqlite3_backup_init(dst.db, cStr(dstName), src.db, cStr(srcName))
if bkup == nil {
return nil, libErr(C.sqlite3_errcode(dst.db), dst.db)
}
b := &Backup{src, dst, bkup}
runtime.SetFinalizer(b, (*Backup).Close)
return b, nil
}
// Close releases all resources associated with the backup operation. It is safe
// to call this method prior to backup completion to abort the operation.
// [http://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish]
func (b *Backup) Close() error {
if bkup := b.bkup; bkup != nil {
b.bkup = nil
runtime.SetFinalizer(b, nil)
if rc := C.sqlite3_backup_finish(bkup); rc != OK {
return libErr(rc, b.dst.db)
}
}
return nil
}
// Conn returns the source and destination connections that are used by this
// backup operation. The destination connection must not be used until the
// backup operation is closed.
func (b *Backup) Conn() (src, dst *Conn) {
return b.src, b.dst
}
// Step copies up to n pages to the destination database. If n is negative, all
// remaining pages are copied. io.EOF is returned upon successful backup
// completion.
// [http://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupstep]
func (b *Backup) Step(n int) error {
if b.bkup == nil {
return ErrBadBackup
}
if rc := C.sqlite3_backup_step(b.bkup, C.int(n)); rc != OK {
// Do not close automatically since that clears the progress info
if rc == DONE {
return io.EOF
}
return libErr(rc, b.dst.db)
}
return nil
}
// Progress returns the number of pages that still need to be backed up and the
// total number of pages in the source database. The values are updated after
// each call to Step and are reset to 0 after the backup is closed. The total
// number of pages may change if the source database is modified during the
// backup operation.
// [http://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining]
func (b *Backup) Progress() (remaining, total int) {
if b.bkup != nil {
remaining = int(C.sqlite3_backup_remaining(b.bkup))
total = int(C.sqlite3_backup_pagecount(b.bkup))
}
return
}

View File

@ -1,214 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sqlite3
/*
#include "sqlite3.h"
#include "lib/codec.h"
*/
import "C"
import (
"bytes"
"sync"
"unsafe"
)
// CodecFunc is a codec initialization function registered for a specific key
// prefix via RegisterCodec. It is called when a key with a matching prefix is
// specified for an attached database. It returns the Codec implementation that
// should be used to encode and decode all database and journal pages. Returning
// (nil, nil) disables the codec.
type CodecFunc func(ctx *CodecCtx, key []byte) (Codec, *Error)
// CodecCtx describes the database to which a codec is being attached.
type CodecCtx struct {
Path string // Full path to the database file
Name string // Database name as it is known to SQLite (e.g. "main")
PageSize int // Current page size in bytes
Reserve int // Current number of bytes reserved in each page
Fixed bool // True if the PageSize and Reserve values cannot be changed
}
// newCodecCtx converts the C CodecCtx struct into its Go representation.
func newCodecCtx(ctx *C.CodecCtx) *CodecCtx {
return &CodecCtx{
Path: C.GoString(ctx.zPath),
Name: C.GoString(ctx.zName),
PageSize: int(ctx.nBuf),
Reserve: int(ctx.nRes),
Fixed: ctx.fixed != 0,
}
}
// Codec is the interface used to encode/decode database and journal pages as
// they are written to and read from the disk.
//
// The op value passed to Encode and Decode methods identifies the operation
// being performed. It is undocumented and changed meanings over time since the
// codec API was first introduced in 2004. It is believed to be a bitmask of the
// following values:
//
// 1 = journal page, not set for WAL, always set when decoding
// 2 = disk I/O, always set
// 4 = encode
//
// In the current implementation, op is always 3 when decoding, 6 when encoding
// for the database file or the WAL, and 7 when encoding for the journal. Search
// lib/sqlite3.c for "CODEC1" and "CODEC2" for more information.
type Codec interface {
// Reserve returns the number of bytes that should be reserved for the codec
// at the end of each page. The upper limit is 255 (32 if the page size is
// 512). Returning -1 leaves the current value unchanged.
Reserve() int
// Resize is called when the codec is first attached to the pager and for
// all subsequent page size changes. It can be used to allocate the encode
// buffer.
Resize(pageSize, reserve int)
// Encode returns an encoded copy of a page. The data outside of the reserve
// area in the original page must not be modified. The codec can either copy
// this data into a buffer for encoding or return the original page without
// making any changes. Bytes 16 through 23 of page 1 cannot be encoded. Any
// non-nil error will be interpreted by SQLite as a NOMEM condition. This is
// a limitation of underlying C API.
Encode(page []byte, pageNum uint32, op int) ([]byte, *Error)
// Decode decodes the page in-place, but it may use the encode buffer as
// scratch space. Bytes 16 through 23 of page 1 must be left at their
// original values. Any non-nil error will be interpreted by SQLite as a
// NOMEM condition. This is a limitation of underlying C API.
Decode(page []byte, pageNum uint32, op int) *Error
// Key returns the original key that was used to initialize the codec. Some
// implementations may be better off returning nil or a fake value. Search
// lib/sqlite3.c for "sqlite3CodecGetKey" to see how the key is used.
Key() []byte
// Free releases codec resources when the pager is destroyed or when the
// codec attachment fails.
Free()
}
// Codec registry and state reference maps.
var (
codecReg map[string]CodecFunc
codecState map[*codec]struct{}
codecMu sync.Mutex
)
// RegisterCodec adds a new codec to the internal registry. Function f will be
// called when a key in the format "<name>:<...>" is provided to an attached
// database.
func RegisterCodec(name string, f CodecFunc) {
codecMu.Lock()
defer codecMu.Unlock()
if f == nil {
delete(codecReg, name)
return
}
if codecReg == nil {
codecReg = make(map[string]CodecFunc, 8)
}
codecReg[name] = f
}
// getCodec returns the CodecFunc for the given key.
func getCodec(key []byte) CodecFunc {
i := bytes.IndexByte(key, ':')
if i == -1 {
i = len(key)
}
codecMu.Lock()
defer codecMu.Unlock()
if codecReg == nil {
return nil
}
return codecReg[bstr(key[:i])]
}
// codec is a wrapper around the actual Codec interface. It keeps track of the
// current page size in order to convert page pointers into byte slices.
type codec struct {
Codec
pageSize C.int
}
//export go_codec_init
func go_codec_init(ctx *C.CodecCtx, pCodec *unsafe.Pointer, pzErrMsg **C.char) C.int {
cf := getCodec(goBytes(ctx.pKey, ctx.nKey))
if cf == nil {
*pzErrMsg = C.CString("codec not found")
return ERROR
}
ci, err := cf(newCodecCtx(ctx), C.GoBytes(ctx.pKey, ctx.nKey))
if err != nil && err.rc != OK {
if ci != nil {
ci.Free()
}
if err.msg != "" {
*pzErrMsg = C.CString(err.msg)
}
return C.int(err.rc)
}
if ci != nil {
cs := &codec{ci, ctx.nBuf}
*pCodec = unsafe.Pointer(cs)
codecMu.Lock()
defer codecMu.Unlock()
if codecState == nil {
codecState = make(map[*codec]struct{}, 8)
}
codecState[cs] = struct{}{}
}
return OK
}
//export go_codec_reserve
func go_codec_reserve(pCodec unsafe.Pointer) C.int {
return C.int((*codec)(pCodec).Reserve())
}
//export go_codec_resize
func go_codec_resize(pCodec unsafe.Pointer, nBuf, nRes C.int) {
cs := (*codec)(pCodec)
cs.pageSize = nBuf
cs.Resize(int(nBuf), int(nRes))
}
//export go_codec_exec
func go_codec_exec(pCodec, pData unsafe.Pointer, pgno uint32, op C.int) unsafe.Pointer {
cs := (*codec)(pCodec)
page := goBytes(pData, cs.pageSize)
var err *Error
if op&4 == 0 {
err = cs.Decode(page, pgno, int(op))
} else {
page, err = cs.Encode(page, pgno, int(op))
}
if err == nil {
return cBytes(page)
}
return nil // Can't do anything with the error at the moment
}
//export go_codec_get_key
func go_codec_get_key(pCodec unsafe.Pointer, pKey *unsafe.Pointer, nKey *C.int) {
if key := (*codec)(pCodec).Key(); len(key) > 0 {
*pKey = cBytes(key)
*nKey = C.int(len(key))
}
}
//export go_codec_free
func go_codec_free(pCodec unsafe.Pointer) {
cs := (*codec)(pCodec)
codecMu.Lock()
delete(codecState, cs)
codecMu.Unlock()
cs.Free()
cs.Codec = nil
}

View File

@ -1,183 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package codec
import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"hash"
. "code.google.com/p/go-sqlite/go1/sqlite3"
)
type aesHmac struct {
key []byte // Key provided to newAesHmac with the master key removed
buf []byte // Page encryption buffer
hdr [4]byte // Header included in each HMAC calculation (page number)
tLen int // Tag length in bytes (HMAC truncation)
// Hash function and chaining mode constructors
hash func() hash.Hash
mode func(block cipher.Block, iv []byte) cipher.Stream
// Block cipher and HMAC initialized from the master key
block cipher.Block
hmac hash.Hash
}
func newAesHmac(ctx *CodecCtx, key []byte) (Codec, *Error) {
name, opts, mk := parseKey(key)
if len(mk) == 0 {
return nil, keyErr
}
defer wipe(mk)
// Configure the codec
c := &aesHmac{
key: key[:len(key)-len(mk)],
tLen: 16,
hash: sha1.New,
mode: cipher.NewCTR,
}
suite := suiteId{
Cipher: "aes",
KeySize: "128",
Mode: "ctr",
MAC: "hmac",
Hash: "sha1",
Trunc: "128",
}
kLen := 16
if err := c.config(opts, &suite, &kLen); err != nil {
return nil, err
}
// Derive encryption and authentication keys
hLen := c.hash().Size()
salt := make([]byte, hLen)
copy(salt, name)
dk := hkdf(mk, salt, kLen+hLen, c.hash)(suite.Id())
defer wipe(dk)
// Initialize the block cipher and HMAC
var err error
if c.block, err = aes.NewCipher(dk[:kLen]); err != nil {
return nil, NewError(MISUSE, err.Error())
}
c.hmac = hmac.New(c.hash, dk[kLen:])
return c, nil
}
func (c *aesHmac) Reserve() int {
return aes.BlockSize + c.tLen
}
func (c *aesHmac) Resize(pageSize, reserve int) {
if reserve != c.Reserve() {
panic("sqlite3: codec reserve value mismatch")
}
hLen := c.hash().Size()
c.buf = make([]byte, pageSize, pageSize-c.tLen+hLen)
}
func (c *aesHmac) Encode(p []byte, n uint32, op int) ([]byte, *Error) {
iv := c.pIV(c.buf)
if !rnd(iv) {
return nil, prngErr
}
c.mode(c.block, iv).XORKeyStream(c.buf, c.pText(p))
if n == 1 {
copy(c.buf[16:], p[16:24])
}
c.auth(c.buf, n, false)
return c.buf, nil
}
func (c *aesHmac) Decode(p []byte, n uint32, op int) *Error {
if !c.auth(p, n, true) {
return codecErr
}
if n == 1 {
copy(c.buf, p[16:24])
}
c.mode(c.block, c.pIV(p)).XORKeyStream(p, c.pText(p))
if n == 1 {
copy(p[16:24], c.buf)
}
return nil
}
func (c *aesHmac) Key() []byte {
return c.key
}
func (c *aesHmac) Free() {
c.buf = nil
c.block = nil
c.hmac = nil
}
// config applies the codec options that were provided in the key.
func (c *aesHmac) config(opts map[string]string, s *suiteId, kLen *int) *Error {
for k := range opts {
switch k {
case "192":
s.KeySize = k
*kLen = 24
case "256":
s.KeySize = k
*kLen = 32
case "ofb":
s.Mode = k
c.mode = cipher.NewOFB
case "sha256":
s.Hash = k
c.hash = sha256.New
default:
return NewError(MISUSE, "invalid codec option: "+k)
}
}
return nil
}
// auth calculates and verifies the HMAC tag for page p. It returns true iff the
// tag is successfully verified.
func (c *aesHmac) auth(p []byte, n uint32, verify bool) bool {
c.hdr[0] = byte(n >> 24)
c.hdr[1] = byte(n >> 16)
c.hdr[2] = byte(n >> 8)
c.hdr[3] = byte(n)
tag := c.pTag(c.buf)
c.hmac.Reset()
c.hmac.Write(c.hdr[:])
c.hmac.Write(c.pAuth(p))
c.hmac.Sum(tag[:0])
return verify && hmac.Equal(tag, c.pTag(p))
}
// pAuth returns the page subslice that gets authenticated.
func (c *aesHmac) pAuth(p []byte) []byte {
return p[:len(p)-c.tLen]
}
// pText returns the page subslice that gets encrypted.
func (c *aesHmac) pText(p []byte) []byte {
return p[:len(p)-c.tLen-aes.BlockSize]
}
// pIV returns the page initialization vector.
func (c *aesHmac) pIV(p []byte) []byte {
return p[len(p)-c.tLen-aes.BlockSize : len(p)-c.tLen]
}
// pTag returns the page authentication tag.
func (c *aesHmac) pTag(p []byte) []byte {
return p[len(p)-c.tLen:]
}

View File

@ -1,130 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package codec
import (
"bytes"
"crypto/hmac"
"crypto/rand"
"hash"
"io"
"strings"
. "code.google.com/p/go-sqlite/go1/sqlite3"
)
func init() {
RegisterCodec("aes-hmac", newAesHmac)
RegisterCodec("hexdump", newHexDump)
}
// Errors returned by codec implementations.
var (
codecErr = NewError(ERROR, "unspecified codec error")
prngErr = NewError(ERROR, "csprng not available")
keyErr = NewError(MISUSE, "invalid codec key format")
)
// parseKey extracts the codec name, options, and anything left over from a key
// in the format "<name>:<options>:<tail...>".
func parseKey(key []byte) (name string, opts map[string]string, tail []byte) {
k := bytes.SplitN(key, []byte{':'}, 3)
name = string(k[0])
opts = make(map[string]string)
if len(k) > 1 && len(k[1]) > 0 {
for _, opt := range strings.Split(string(k[1]), ",") {
if i := strings.Index(opt, "="); i > 0 {
opts[opt[:i]] = opt[i+1:]
} else {
opts[opt] = ""
}
}
}
if len(k) > 2 && len(k[2]) > 0 {
tail = k[2]
}
return
}
// hkdf implements the HMAC-based Key Derivation Function, as described in RFC
// 5869. The extract step is skipped if salt == nil. It is the caller's
// responsibility to set salt "to a string of HashLen zeros," if such behavior
// is desired. It returns the function that performs the expand step using the
// provided info value, which must be appendable. The derived key is valid until
// the next expansion.
func hkdf(ikm, salt []byte, dkLen int, h func() hash.Hash) func(info []byte) []byte {
if salt != nil {
prf := hmac.New(h, salt)
prf.Write(ikm)
ikm = prf.Sum(nil)
}
prf := hmac.New(h, ikm)
hLen := prf.Size()
n := (dkLen + hLen - 1) / hLen
dk := make([]byte, dkLen, n*hLen)
return func(info []byte) []byte {
info = append(info, 0)
ctr := &info[len(info)-1]
for i, t := 1, dk[:0]; i <= n; i++ {
*ctr = byte(i)
prf.Reset()
prf.Write(t)
prf.Write(info)
t = prf.Sum(t[len(t):])
}
return dk
}
}
// rnd fills b with bytes from a CSPRNG.
func rnd(b []byte) bool {
_, err := io.ReadFull(rand.Reader, b)
return err == nil
}
// wipe overwrites b with zeros.
func wipe(b []byte) {
for i := range b {
b[i] = 0
}
}
// suiteId constructs a canonical cipher suite identifier.
type suiteId struct {
Cipher string
KeySize string
Mode string
MAC string
Hash string
Trunc string
}
func (s *suiteId) Id() []byte {
id := make([]byte, 0, 64)
section := func(parts ...string) {
for i, p := range parts {
if p != "" {
parts = parts[i:]
goto write
}
}
return
write:
if len(id) > 0 {
id = append(id, ',')
}
id = append(id, parts[0]...)
for _, p := range parts[1:] {
if p != "" {
id = append(id, '-')
id = append(id, p...)
}
}
}
section(s.Cipher, s.KeySize, s.Mode)
section(s.MAC, s.Hash, s.Trunc)
return id
}

View File

@ -1,128 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package codec
import (
"crypto/sha1"
"crypto/sha256"
"encoding/hex"
"hash"
"testing"
)
func TestHKDF(t *testing.T) {
tests := []struct {
ikm string
salt string
info string
dkLen int
h func() hash.Hash
out string
}{
// RFC 5869 Test Vectors
{
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"000102030405060708090a0b0c",
"f0f1f2f3f4f5f6f7f8f9",
42,
sha256.New,
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
}, {
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
82,
sha256.New,
"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
}, {
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"",
"",
42,
sha256.New,
"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8",
}, {
"0b0b0b0b0b0b0b0b0b0b0b",
"000102030405060708090a0b0c",
"f0f1f2f3f4f5f6f7f8f9",
42,
sha1.New,
"085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896",
}, {
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
82,
sha1.New,
"0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4",
}, {
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"",
"",
42,
sha1.New,
"0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918",
}, {
"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
"0000000000000000000000000000000000000000",
"",
42,
sha1.New,
"2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48",
},
}
for i, test := range tests {
ikm, _ := hex.DecodeString(test.ikm)
salt, _ := hex.DecodeString(test.salt)
info, _ := hex.DecodeString(test.info)
dk := hkdf(ikm, salt, test.dkLen, test.h)(info)
if out := hex.EncodeToString(dk); out != test.out {
t.Errorf("hkdf(%d) expected %q; got %q", i, test.out, out)
}
}
}
func TestSuiteId(t *testing.T) {
tests := []struct {
suite suiteId
out string
}{
{suiteId{},
""},
{suiteId{Cipher: "aes"},
"aes"},
{suiteId{KeySize: "128"},
"128"},
{suiteId{Cipher: "aes", KeySize: "128"},
"aes-128"},
{suiteId{Cipher: "aes", Mode: "ctr"},
"aes-ctr"},
{suiteId{Cipher: "aes", KeySize: "128", Mode: "ctr"},
"aes-128-ctr"},
{suiteId{MAC: "hmac"},
"hmac"},
{suiteId{MAC: "hmac", Hash: "sha1"},
"hmac-sha1"},
{suiteId{MAC: "hmac", Hash: "sha1", Trunc: "128"},
"hmac-sha1-128"},
{suiteId{Cipher: "aes", MAC: "hmac"},
"aes,hmac"},
{suiteId{Cipher: "aes", Hash: "sha1"},
"aes,sha1"},
{suiteId{Mode: "ctr", Hash: "sha1"},
"ctr,sha1"},
{suiteId{Cipher: "aes", KeySize: "128", MAC: "hmac", Hash: "sha256"},
"aes-128,hmac-sha256"},
{suiteId{Cipher: "aes", Mode: "ctr", Hash: "sha256", Trunc: "128"},
"aes-ctr,sha256-128"},
{suiteId{Cipher: "aes", KeySize: "256", Mode: "ctr", MAC: "hmac", Hash: "sha256", Trunc: "128"},
"aes-256-ctr,hmac-sha256-128"},
}
for _, test := range tests {
if out := string(test.suite.Id()); out != test.out {
t.Errorf("%#v expected %q; got %q", test.suite, test.out, out)
}
}
}

View File

@ -1,110 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package codec provides authenticated encryption and other codecs for the sqlite3
package.
This package has no public interface and should be imported with the blank
identifier to register the codecs. Use Conn.Key after opening a new connection,
or the KEY clause in an ATTACH statement, to use one of the codecs:
c, _ := sqlite3.Open("file1.db")
c.Key("main", []byte("aes-hmac::secretkey1"))
c.Exec("ATTACH DATABASE 'file2.db' AS two KEY 'aes-hmac::secretkey2'")
If the KEY clause is omitted, SQLite uses the key from the main database, which
may no longer be valid depending on how the codec is implemented (e.g. aes-hmac
destroys the master key after initialization). Specify an empty string as the
key to disable this behavior.
Codec Operation
Each SQLite database and journal file consists of one or more pages of identical
size. Each page may have extra space reserved at the end, which SQLite will not
use in any way. The exact number of bytes reserved is stored at offset 20 of the
database file header, so the value is between 0 and 255. SQLite requires each
page to have at least 480 usable bytes, so the value cannot exceed 32 bytes with
a page size of 512. This extra space may be used by a codec to store per-page
Initialization Vectors (IVs), Message Authentication Codes (MACs), or any other
information.
CodecFunc is called to initialize a registered codec when a key with a matching
prefix is provided. If it returns a non-nil Codec implementation, Codec.Reserve
is called to determine how much space this codec needs reserved in each page for
correct operation. Codec.Resize is called to provide the current page size and
reserve values, and for all subsequent changes. The page size may be changed
before the database file is created. Once the first CREATE TABLE statement is
executed, the page size and reserve values are fixed.
Codec.Encode is called when a page is about to be written to the disk.
Codec.Decode is called when a page was just read from the disk. This happens for
both the main database file and the journal/WAL, so the pages are always encoded
on the disk and decoded in memory. Codec.Free is called to free all codec
resources when the database is detached.
AES-HMAC
The aes-hmac codec provides authenticated encryption using the Advanced
Encryption Standard (AES) cipher and the Hash-based Message Authentication Code
(HMAC) in Encrypt-then-MAC mode. Each page has an independent, pseudorandom IV,
which is regenerated every time the page is encrypted, and an authentication
tag, which is verified before the page is decrypted. The codec requires 32 bytes
per page to store this information.
The key format is "aes-hmac:<options>:<master-key>", where <options> is a
comma-separated list of codec options described below, and <master-key> is the
key from which separate encryption and authentication keys are derived.
SECURITY WARNING: The master key is called a "key" and not a "password" for a
reason. It is not passed through pbkdf2, bcrypt, scrypt, or any other key
stretching function. The application is expected to ensure that this key is
sufficiently resistant to brute-force attacks. Ideally, it should be obtained
from a cryptographically secure pseudorandom number generator (CSPRNG), such as
the one provided by the crypto/rand package.
The encryption and authentication keys are derived from the master key using the
HMAC-based Key Derivation Function (HKDF), as described in RFC 5869. The salt is
the codec name ("aes-hmac") extended with NULLs to HashLen bytes, and info is
the codec configuration string (e.g. "aes-128-ctr,hmac-sha1-128"). This is done
to obtain two keys of the required lengths, which are also bound to the codec
configuration.
The default configuration is AES-128-CTR cipher and HMAC-SHA1-128 authentication
(HMAC output is truncated to 128 bits). The following options may be used to
change the defaults:
192
AES-192 block cipher.
256
AES-256 block cipher.
ofb
Output feedback mode of operation.
sha256
SHA-256 hash function used by HKDF and HMAC.
For example, "aes-hmac:256,ofb,sha256:<master-key>" will use the AES-256-OFB
cipher and HMAC-SHA256-128 authentication.
HEXDUMP
The hexdump codec logs all method calls and dumps the page content for each
encode/decode operation to a file. It is intended to be used as an aid when
writing your own codecs.
The key format is "hexdump:<options>:<file>", where <options> is a
comma-separated list of codec options described below, and <file> is the output
destination. The default destination is stderr. Dash ("-") means stdout. For
obvious reasons, this codec cannot be used with an encrypted database except to
see the first Codec.Decode call for page 1.
The following options are supported:
quiet
Do not output a hex dump of each page.
reserve=N
Reserve N bytes in each page. The default is -1, which means don't
change the current reserve value.
*/
package codec

View File

@ -1,105 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package codec
import (
"encoding/hex"
"fmt"
"os"
"strconv"
. "code.google.com/p/go-sqlite/go1/sqlite3"
)
type hexDump struct {
key []byte
out *os.File
quiet bool
res int
}
func newHexDump(ctx *CodecCtx, key []byte) (Codec, *Error) {
_, opts, tail := parseKey(key)
c := &hexDump{key, os.Stderr, false, -1}
// Set options
for k, v := range opts {
switch k {
case "quiet":
c.quiet = true
case "reserve":
if n, err := strconv.ParseUint(v, 10, 8); err == nil {
c.res = int(n)
}
default:
return nil, NewError(MISUSE, "invalid codec option: "+k)
}
}
// Open output file
switch file := string(tail); file {
case "":
case "-":
c.out = os.Stdout
default:
var err error
c.out, err = os.OpenFile(file, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
return nil, NewError(ERROR, err.Error())
}
}
fmt.Fprintf(c.out, "Init (\n"+
" Path=%s\n"+
" Name=%s\n"+
" PageSize=%d\n"+
" Reserve=%d\n"+
" Fixed=%t\n"+
")\n",
ctx.Path, ctx.Name, ctx.PageSize, ctx.Reserve, ctx.Fixed)
return c, nil
}
func (c *hexDump) Reserve() int {
fmt.Fprintf(c.out, "Reserve\n")
return c.res
}
func (c *hexDump) Resize(pageSize, reserve int) {
fmt.Fprintf(c.out, "Resize (pageSize=%d, reserve=%d)\n", pageSize, reserve)
}
func (c *hexDump) Encode(page []byte, pageNum uint32, op int) ([]byte, *Error) {
fmt.Fprintf(c.out, "Encode (pageNum=%d, op=%d)\n", pageNum, op)
c.dump(page)
return page, nil
}
func (c *hexDump) Decode(page []byte, pageNum uint32, op int) *Error {
fmt.Fprintf(c.out, "Decode (pageNum=%d, op=%d)\n", pageNum, op)
c.dump(page)
return nil
}
func (c *hexDump) Key() []byte {
fmt.Fprintf(c.out, "Key\n")
return c.key
}
func (c *hexDump) Free() {
fmt.Fprintf(c.out, "Free\n")
if c.out != os.Stdout && c.out != os.Stderr {
c.out.Close()
}
}
func (c *hexDump) dump(b []byte) {
if !c.quiet {
hd := hex.Dumper(c.out)
hd.Write(b)
hd.Close()
c.out.Write([]byte("\n"))
}
}

View File

@ -1,208 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sqlite3
/*
#include "sqlite3.h"
*/
import "C"
// Fundamental SQLite data types. These are returned by Stmt.DataTypes method.
// [http://www.sqlite.org/c3ref/c_blob.html]
const (
INTEGER = C.SQLITE_INTEGER // 1
FLOAT = C.SQLITE_FLOAT // 2
TEXT = C.SQLITE_TEXT // 3
BLOB = C.SQLITE_BLOB // 4
NULL = C.SQLITE_NULL // 5
)
// General result codes returned by the SQLite API. When converted to an error,
// OK and ROW become nil, and DONE becomes either nil or io.EOF, depending on
// the context in which the statement is executed. All other codes are returned
// via the Error struct.
// [http://www.sqlite.org/c3ref/c_abort.html]
const (
OK = C.SQLITE_OK // 0 = Successful result
ERROR = C.SQLITE_ERROR // 1 = SQL error or missing database
INTERNAL = C.SQLITE_INTERNAL // 2 = Internal logic error in SQLite
PERM = C.SQLITE_PERM // 3 = Access permission denied
ABORT = C.SQLITE_ABORT // 4 = Callback routine requested an abort
BUSY = C.SQLITE_BUSY // 5 = The database file is locked
LOCKED = C.SQLITE_LOCKED // 6 = A table in the database is locked
NOMEM = C.SQLITE_NOMEM // 7 = A malloc() failed
READONLY = C.SQLITE_READONLY // 8 = Attempt to write a readonly database
INTERRUPT = C.SQLITE_INTERRUPT // 9 = Operation terminated by sqlite3_interrupt()
IOERR = C.SQLITE_IOERR // 10 = Some kind of disk I/O error occurred
CORRUPT = C.SQLITE_CORRUPT // 11 = The database disk image is malformed
NOTFOUND = C.SQLITE_NOTFOUND // 12 = Unknown opcode in sqlite3_file_control()
FULL = C.SQLITE_FULL // 13 = Insertion failed because database is full
CANTOPEN = C.SQLITE_CANTOPEN // 14 = Unable to open the database file
PROTOCOL = C.SQLITE_PROTOCOL // 15 = Database lock protocol error
EMPTY = C.SQLITE_EMPTY // 16 = Database is empty
SCHEMA = C.SQLITE_SCHEMA // 17 = The database schema changed
TOOBIG = C.SQLITE_TOOBIG // 18 = String or BLOB exceeds size limit
CONSTRAINT = C.SQLITE_CONSTRAINT // 19 = Abort due to constraint violation
MISMATCH = C.SQLITE_MISMATCH // 20 = Data type mismatch
MISUSE = C.SQLITE_MISUSE // 21 = Library used incorrectly
NOLFS = C.SQLITE_NOLFS // 22 = Uses OS features not supported on host
AUTH = C.SQLITE_AUTH // 23 = Authorization denied
FORMAT = C.SQLITE_FORMAT // 24 = Auxiliary database format error
RANGE = C.SQLITE_RANGE // 25 = 2nd parameter to sqlite3_bind out of range
NOTADB = C.SQLITE_NOTADB // 26 = File opened that is not a database file
NOTICE = C.SQLITE_NOTICE // 27 = Notifications from sqlite3_log()
WARNING = C.SQLITE_WARNING // 28 = Warnings from sqlite3_log()
ROW = C.SQLITE_ROW // 100 = sqlite3_step() has another row ready
DONE = C.SQLITE_DONE // 101 = sqlite3_step() has finished executing
)
// Extended result codes returned by the SQLite API. Extended result codes are
// enabled by default for all new Conn objects. Use Error.Code()&0xFF to convert
// an extended code to a general one.
// [http://www.sqlite.org/c3ref/c_abort_rollback.html]
const (
IOERR_READ = C.SQLITE_IOERR_READ // (SQLITE_IOERR | (1<<8))
IOERR_SHORT_READ = C.SQLITE_IOERR_SHORT_READ // (SQLITE_IOERR | (2<<8))
IOERR_WRITE = C.SQLITE_IOERR_WRITE // (SQLITE_IOERR | (3<<8))
IOERR_FSYNC = C.SQLITE_IOERR_FSYNC // (SQLITE_IOERR | (4<<8))
IOERR_DIR_FSYNC = C.SQLITE_IOERR_DIR_FSYNC // (SQLITE_IOERR | (5<<8))
IOERR_TRUNCATE = C.SQLITE_IOERR_TRUNCATE // (SQLITE_IOERR | (6<<8))
IOERR_FSTAT = C.SQLITE_IOERR_FSTAT // (SQLITE_IOERR | (7<<8))
IOERR_UNLOCK = C.SQLITE_IOERR_UNLOCK // (SQLITE_IOERR | (8<<8))
IOERR_RDLOCK = C.SQLITE_IOERR_RDLOCK // (SQLITE_IOERR | (9<<8))
IOERR_DELETE = C.SQLITE_IOERR_DELETE // (SQLITE_IOERR | (10<<8))
IOERR_BLOCKED = C.SQLITE_IOERR_BLOCKED // (SQLITE_IOERR | (11<<8))
IOERR_NOMEM = C.SQLITE_IOERR_NOMEM // (SQLITE_IOERR | (12<<8))
IOERR_ACCESS = C.SQLITE_IOERR_ACCESS // (SQLITE_IOERR | (13<<8))
IOERR_CHECKRESERVEDLOCK = C.SQLITE_IOERR_CHECKRESERVEDLOCK // (SQLITE_IOERR | (14<<8))
IOERR_LOCK = C.SQLITE_IOERR_LOCK // (SQLITE_IOERR | (15<<8))
IOERR_CLOSE = C.SQLITE_IOERR_CLOSE // (SQLITE_IOERR | (16<<8))
IOERR_DIR_CLOSE = C.SQLITE_IOERR_DIR_CLOSE // (SQLITE_IOERR | (17<<8))
IOERR_SHMOPEN = C.SQLITE_IOERR_SHMOPEN // (SQLITE_IOERR | (18<<8))
IOERR_SHMSIZE = C.SQLITE_IOERR_SHMSIZE // (SQLITE_IOERR | (19<<8))
IOERR_SHMLOCK = C.SQLITE_IOERR_SHMLOCK // (SQLITE_IOERR | (20<<8))
IOERR_SHMMAP = C.SQLITE_IOERR_SHMMAP // (SQLITE_IOERR | (21<<8))
IOERR_SEEK = C.SQLITE_IOERR_SEEK // (SQLITE_IOERR | (22<<8))
IOERR_DELETE_NOENT = C.SQLITE_IOERR_DELETE_NOENT // (SQLITE_IOERR | (23<<8))
IOERR_MMAP = C.SQLITE_IOERR_MMAP // (SQLITE_IOERR | (24<<8))
IOERR_GETTEMPPATH = C.SQLITE_IOERR_GETTEMPPATH // (SQLITE_IOERR | (25<<8))
LOCKED_SHAREDCACHE = C.SQLITE_LOCKED_SHAREDCACHE // (SQLITE_LOCKED | (1<<8))
BUSY_RECOVERY = C.SQLITE_BUSY_RECOVERY // (SQLITE_BUSY | (1<<8))
BUSY_SNAPSHOT = C.SQLITE_BUSY_SNAPSHOT // (SQLITE_BUSY | (2<<8))
CANTOPEN_NOTEMPDIR = C.SQLITE_CANTOPEN_NOTEMPDIR // (SQLITE_CANTOPEN | (1<<8))
CANTOPEN_ISDIR = C.SQLITE_CANTOPEN_ISDIR // (SQLITE_CANTOPEN | (2<<8))
CANTOPEN_FULLPATH = C.SQLITE_CANTOPEN_FULLPATH // (SQLITE_CANTOPEN | (3<<8))
CORRUPT_VTAB = C.SQLITE_CORRUPT_VTAB // (SQLITE_CORRUPT | (1<<8))
READONLY_RECOVERY = C.SQLITE_READONLY_RECOVERY // (SQLITE_READONLY | (1<<8))
READONLY_CANTLOCK = C.SQLITE_READONLY_CANTLOCK // (SQLITE_READONLY | (2<<8))
READONLY_ROLLBACK = C.SQLITE_READONLY_ROLLBACK // (SQLITE_READONLY | (3<<8))
ABORT_ROLLBACK = C.SQLITE_ABORT_ROLLBACK // (SQLITE_ABORT | (2<<8))
CONSTRAINT_CHECK = C.SQLITE_CONSTRAINT_CHECK // (SQLITE_CONSTRAINT | (1<<8))
CONSTRAINT_COMMITHOOK = C.SQLITE_CONSTRAINT_COMMITHOOK // (SQLITE_CONSTRAINT | (2<<8))
CONSTRAINT_FOREIGNKEY = C.SQLITE_CONSTRAINT_FOREIGNKEY // (SQLITE_CONSTRAINT | (3<<8))
CONSTRAINT_FUNCTION = C.SQLITE_CONSTRAINT_FUNCTION // (SQLITE_CONSTRAINT | (4<<8))
CONSTRAINT_NOTNULL = C.SQLITE_CONSTRAINT_NOTNULL // (SQLITE_CONSTRAINT | (5<<8))
CONSTRAINT_PRIMARYKEY = C.SQLITE_CONSTRAINT_PRIMARYKEY // (SQLITE_CONSTRAINT | (6<<8))
CONSTRAINT_TRIGGER = C.SQLITE_CONSTRAINT_TRIGGER // (SQLITE_CONSTRAINT | (7<<8))
CONSTRAINT_UNIQUE = C.SQLITE_CONSTRAINT_UNIQUE // (SQLITE_CONSTRAINT | (8<<8))
CONSTRAINT_VTAB = C.SQLITE_CONSTRAINT_VTAB // (SQLITE_CONSTRAINT | (9<<8))
NOTICE_RECOVER_WAL = C.SQLITE_NOTICE_RECOVER_WAL // (SQLITE_NOTICE | (1<<8))
NOTICE_RECOVER_ROLLBACK = C.SQLITE_NOTICE_RECOVER_ROLLBACK // (SQLITE_NOTICE | (2<<8))
WARNING_AUTOINDEX = C.SQLITE_WARNING_AUTOINDEX // (SQLITE_WARNING | (1<<8))
)
// Codes used by SQLite to indicate the operation type when invoking authorizer
// and row update callbacks.
// [http://www.sqlite.org/c3ref/c_alter_table.html]
const (
CREATE_INDEX = C.SQLITE_CREATE_INDEX // 1
CREATE_TABLE = C.SQLITE_CREATE_TABLE // 2
CREATE_TEMP_INDEX = C.SQLITE_CREATE_TEMP_INDEX // 3
CREATE_TEMP_TABLE = C.SQLITE_CREATE_TEMP_TABLE // 4
CREATE_TEMP_TRIGGER = C.SQLITE_CREATE_TEMP_TRIGGER // 5
CREATE_TEMP_VIEW = C.SQLITE_CREATE_TEMP_VIEW // 6
CREATE_TRIGGER = C.SQLITE_CREATE_TRIGGER // 7
CREATE_VIEW = C.SQLITE_CREATE_VIEW // 8
DELETE = C.SQLITE_DELETE // 9
DROP_INDEX = C.SQLITE_DROP_INDEX // 10
DROP_TABLE = C.SQLITE_DROP_TABLE // 11
DROP_TEMP_INDEX = C.SQLITE_DROP_TEMP_INDEX // 12
DROP_TEMP_TABLE = C.SQLITE_DROP_TEMP_TABLE // 13
DROP_TEMP_TRIGGER = C.SQLITE_DROP_TEMP_TRIGGER // 14
DROP_TEMP_VIEW = C.SQLITE_DROP_TEMP_VIEW // 15
DROP_TRIGGER = C.SQLITE_DROP_TRIGGER // 16
DROP_VIEW = C.SQLITE_DROP_VIEW // 17
INSERT = C.SQLITE_INSERT // 18
PRAGMA = C.SQLITE_PRAGMA // 19
READ = C.SQLITE_READ // 20
SELECT = C.SQLITE_SELECT // 21
TRANSACTION = C.SQLITE_TRANSACTION // 22
UPDATE = C.SQLITE_UPDATE // 23
ATTACH = C.SQLITE_ATTACH // 24
DETACH = C.SQLITE_DETACH // 25
ALTER_TABLE = C.SQLITE_ALTER_TABLE // 26
REINDEX = C.SQLITE_REINDEX // 27
ANALYZE = C.SQLITE_ANALYZE // 28
CREATE_VTABLE = C.SQLITE_CREATE_VTABLE // 29
DROP_VTABLE = C.SQLITE_DROP_VTABLE // 30
FUNCTION = C.SQLITE_FUNCTION // 31
SAVEPOINT = C.SQLITE_SAVEPOINT // 32
)
// Core SQLite performance counters that can be queried with Status.
// [http://www.sqlite.org/c3ref/c_status_malloc_count.html]
const (
STATUS_MEMORY_USED = C.SQLITE_STATUS_MEMORY_USED // 0
STATUS_PAGECACHE_USED = C.SQLITE_STATUS_PAGECACHE_USED // 1
STATUS_PAGECACHE_OVERFLOW = C.SQLITE_STATUS_PAGECACHE_OVERFLOW // 2
STATUS_SCRATCH_USED = C.SQLITE_STATUS_SCRATCH_USED // 3
STATUS_SCRATCH_OVERFLOW = C.SQLITE_STATUS_SCRATCH_OVERFLOW // 4
STATUS_MALLOC_SIZE = C.SQLITE_STATUS_MALLOC_SIZE // 5
STATUS_PARSER_STACK = C.SQLITE_STATUS_PARSER_STACK // 6
STATUS_PAGECACHE_SIZE = C.SQLITE_STATUS_PAGECACHE_SIZE // 7
STATUS_SCRATCH_SIZE = C.SQLITE_STATUS_SCRATCH_SIZE // 8
STATUS_MALLOC_COUNT = C.SQLITE_STATUS_MALLOC_COUNT // 9
)
// Connection performance counters that can be queried with Conn.Status.
// [http://www.sqlite.org/c3ref/c_dbstatus_options.html]
const (
DBSTATUS_LOOKASIDE_USED = C.SQLITE_DBSTATUS_LOOKASIDE_USED // 0
DBSTATUS_CACHE_USED = C.SQLITE_DBSTATUS_CACHE_USED // 1
DBSTATUS_SCHEMA_USED = C.SQLITE_DBSTATUS_SCHEMA_USED // 2
DBSTATUS_STMT_USED = C.SQLITE_DBSTATUS_STMT_USED // 3
DBSTATUS_LOOKASIDE_HIT = C.SQLITE_DBSTATUS_LOOKASIDE_HIT // 4
DBSTATUS_LOOKASIDE_MISS_SIZE = C.SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE // 5
DBSTATUS_LOOKASIDE_MISS_FULL = C.SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL // 6
DBSTATUS_CACHE_HIT = C.SQLITE_DBSTATUS_CACHE_HIT // 7
DBSTATUS_CACHE_MISS = C.SQLITE_DBSTATUS_CACHE_MISS // 8
DBSTATUS_CACHE_WRITE = C.SQLITE_DBSTATUS_CACHE_WRITE // 9
DBSTATUS_DEFERRED_FKS = C.SQLITE_DBSTATUS_DEFERRED_FKS // 10
)
// Statement performance counters that can be queried with Stmt.Status.
// [http://www.sqlite.org/c3ref/c_stmtstatus_counter.html]
const (
STMTSTATUS_FULLSCAN_STEP = C.SQLITE_STMTSTATUS_FULLSCAN_STEP // 1
STMTSTATUS_SORT = C.SQLITE_STMTSTATUS_SORT // 2
STMTSTATUS_AUTOINDEX = C.SQLITE_STMTSTATUS_AUTOINDEX // 3
STMTSTATUS_VM_STEP = C.SQLITE_STMTSTATUS_VM_STEP // 4
)
// Per-connection limits that can be queried and changed with Conn.Limit.
// [http://www.sqlite.org/c3ref/c_limit_attached.html]
const (
LIMIT_LENGTH = C.SQLITE_LIMIT_LENGTH // 0
LIMIT_SQL_LENGTH = C.SQLITE_LIMIT_SQL_LENGTH // 1
LIMIT_COLUMN = C.SQLITE_LIMIT_COLUMN // 2
LIMIT_EXPR_DEPTH = C.SQLITE_LIMIT_EXPR_DEPTH // 3
LIMIT_COMPOUND_SELECT = C.SQLITE_LIMIT_COMPOUND_SELECT // 4
LIMIT_VDBE_OP = C.SQLITE_LIMIT_VDBE_OP // 5
LIMIT_FUNCTION_ARG = C.SQLITE_LIMIT_FUNCTION_ARG // 6
LIMIT_ATTACHED = C.SQLITE_LIMIT_ATTACHED // 7
LIMIT_LIKE_PATTERN_LENGTH = C.SQLITE_LIMIT_LIKE_PATTERN_LENGTH // 8
LIMIT_VARIABLE_NUMBER = C.SQLITE_LIMIT_VARIABLE_NUMBER // 9
LIMIT_TRIGGER_DEPTH = C.SQLITE_LIMIT_TRIGGER_DEPTH // 10
)

View File

@ -1,176 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package sqlite3 provides an interface to SQLite version 3 databases.
Database connections are created either by using this package directly or with
the "sqlite3" database/sql driver. The direct interface, which is described
below, exposes SQLite-specific features, such as incremental I/O and online
backups. The driver is recommended when your application has to support multiple
database engines.
Installation
Minimum requirements are Go 1.1+ with CGO enabled and GCC/MinGW C compiler. The
SQLite amalgamation version 3.8.0.2 (2013-09-03) is compiled as part of the
package (see http://www.sqlite.org/amalgamation.html). Compilation options are
defined at the top of sqlite3.go (#cgo CFLAGS). Dynamic linking with a shared
SQLite library is not supported.
Windows users should install mingw-w64 (http://mingw-w64.sourceforge.net/),
TDM64-GCC (http://tdm-gcc.tdragon.net/), or another MinGW distribution, and make
sure that gcc.exe is available from the %PATH%. MSYS is not required.
Run 'go get code.google.com/p/go-sqlite/go1/sqlite3' to download, build, and
install the package.
Concurrency
A single connection instance and all of its derived objects (prepared
statements, backup operations, etc.) may NOT be used concurrently from multiple
goroutines without external synchronization. The only exception is
Conn.Interrupt(), which may be called from another goroutine to abort a
long-running operation. It is safe to use separate connection instances
concurrently, even if they are accessing the same database file. For example:
// ERROR (without any extra synchronization)
c, _ := sqlite3.Open("sqlite.db")
go use(c)
go use(c)
// OK
c1, _ := sqlite3.Open("sqlite.db")
c2, _ := sqlite3.Open("sqlite.db")
go use(c1)
go use(c2)
Maps
Use NamedArgs map to bind values to named statement parameters (see
http://www.sqlite.org/lang_expr.html#varparam). Use RowMap to retrieve the
current row as a map of column/value pairs. Here is a short example with the
error-handling code omitted for brevity:
c, _ := sqlite3.Open(":memory:")
c.Exec("CREATE TABLE x(a, b, c)")
args := sqlite3.NamedArgs{"$a": 1, "$b": "demo"}
c.Exec("INSERT INTO x VALUES($a, $b, $c)", args) // $c will be NULL
sql := "SELECT rowid, * FROM x"
row := make(sqlite3.RowMap)
for s, err := c.Query(sql); err == nil; err = s.Next() {
var rowid int64
s.Scan(&rowid, row) // Assigns 1st column to rowid, the rest to row
fmt.Println(rowid, row) // Prints "1 map[a:1 b:demo c:<nil>]"
}
Data Types
See http://www.sqlite.org/datatype3.html for a description of the SQLite data
type system. The following Go data types are supported as arguments to prepared
statements and may be used in NamedArgs:
Go Type SQLite Type Notes
--------- ----------- ----------------------------------------------------
<nil> NULL Unbound parameters are NULL by default.
int INTEGER
int64 INTEGER
float64 FLOAT
bool INTEGER Converted as false = 0, true = 1.
string TEXT SQLite makes a private copy when the value is bound.
[]byte BLOB SQLite makes a private copy when the value is bound.
time.Time INTEGER Converted by calling Unix().
RawString TEXT SQLite uses the value directly without copying. The
caller must keep a reference to the value for the
duration of the query to prevent garbage collection.
RawBytes BLOB Same as RawString. The value must not be modified
for the duration of the query.
ZeroBlob BLOB Allocates a zero-filled BLOB of the specified length
(e.g. ZeroBlob(4096) allocates 4KB).
Note that the table above describes how the value is bound to the statement. The
final storage class is determined according to the column affinity rules.
See http://www.sqlite.org/c3ref/column_blob.html for a description of how column
values are retrieved from the results of a query. The following static Go data
types are supported for retrieving column values:
Go Type Req. Type Notes
---------- --------- ---------------------------------------------------
*int INTEGER
*int64 INTEGER
*float64 FLOAT
*bool INTEGER Converted as 0 = false, otherwise true.
*string TEXT The caller receives a copy of the value.
*[]byte BLOB The caller receives a copy of the value.
*time.Time INTEGER Converted by calling time.Unix(). Text values are not
supported, but the conversion can be performed with
the date and time SQL functions.
*RawString TEXT The value is used directly without copying and
remains valid until the next Stmt method call.
*RawBytes BLOB Same as *RawString. The value must not be modified.
Re-slicing is ok, but be careful with append().
io.Writer BLOB The value is written out directly into the writer.
For *interface{} and RowMap arguments, the Go data type is dynamically selected
based on the SQLite storage class and column declaration prefix:
SQLite Type Col. Decl. Go Type Notes
----------- ---------- --------- ----------------------------------------
NULL <nil>
INTEGER "DATE..." time.Time Converted by calling time.Unix().
INTEGER "TIME..." time.Time Converted by calling time.Unix().
INTEGER "BOOL..." bool Converted as 0 = false, otherwise true.
INTEGER int64
FLOAT float64
TEXT string
BLOB []byte
Database Names
Methods that require a database name as one of the arguments (e.g. Conn.Path())
expect the symbolic name by which the database is known to the connection, not a
path to a file. Valid database names are "main", "temp", or a name specified
after the AS clause in an ATTACH statement.
Callbacks
SQLite can execute callbacks for various internal events. The package provides
types and methods for registering callback handlers. Unless stated otherwise in
SQLite documentation, callback handlers are not reentrant and must not do
anything to modify the associated database connection. This includes
preparing/running any other SQL statements. The safest bet is to avoid all
interactions with Conn, Stmt, and other related objects within the handler.
Codecs and Encryption
SQLite has an undocumented codec API, which operates between the pager and VFS
layers, and is used by the SQLite Encryption Extension (SEE) to encrypt database
and journal contents. Consider purchasing a SEE license if you require
production-quality encryption support (http://www.hwaci.com/sw/sqlite/see.html).
This package has an experimental API (read: unstable, may eat your data) for
writing codecs in Go. The "codec" subpackage provides additional documentation
and several existing codec implementations.
Codecs are registered via the RegisterCodec function for a specific key prefix.
For example, the "aes-hmac" codec is initialized when a key in the format
"aes-hmac:<...>" is provided to an attached database. The key format after the
first colon is codec-specific. See CodecFunc for more information.
The codec API has several limitations. Codecs cannot be used for in-memory or
temporary databases. Once a database is created, the page size and the amount of
reserved space at the end of each page cannot be changed (i.e. "PRAGMA
page_size=N; VACUUM;" will not work). Online backups will fail unless the
destination database has the same page size and reserve values. Bytes 16 through
23 of page 1 (the database header, see http://www.sqlite.org/fileformat2.html)
cannot be altered, so it is always possible to identify encrypted SQLite
databases.
The rekey function is currently not implemented. The key can only be changed via
the backup API or by dumping and restoring the database contents.
*/
package sqlite3

View File

@ -1,161 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sqlite3
import "C"
import (
"database/sql"
"database/sql/driver"
"io"
"reflect"
"time"
"unsafe"
)
// Driver implements the interface required by database/sql.
type Driver string
func register(name string) {
defer func() { recover() }()
sql.Register(name, Driver(name))
}
func (Driver) Open(name string) (driver.Conn, error) {
c, err := Open(name)
if err != nil {
return nil, err
}
c.BusyTimeout(5 * time.Second)
return &conn{c}, nil
}
// conn implements driver.Conn.
type conn struct {
*Conn
}
func (c *conn) Prepare(query string) (driver.Stmt, error) {
if c.Conn.db == nil {
return nil, driver.ErrBadConn
}
s, err := c.Conn.Prepare(query)
if err != nil {
return nil, err
}
return &stmt{s, false}, nil
}
func (c *conn) Begin() (driver.Tx, error) {
if c.Conn.db == nil {
return nil, driver.ErrBadConn
}
if err := c.Conn.Begin(); err != nil {
return nil, err
}
return c.Conn, nil
}
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
if c.Conn.db == nil {
return nil, driver.ErrBadConn
}
if err := c.Conn.Exec(query, vtoi(args)...); err != nil {
return nil, err
}
// TODO: Do the driver.Result values need to be cached?
return result{c.Conn}, nil
}
// stmt implements driver.Stmt.
type stmt struct {
*Stmt
closed bool
}
func (s *stmt) Close() error {
if !s.closed {
s.closed = true
if !s.Stmt.Busy() {
return s.Stmt.Close()
}
}
return nil
}
func (s *stmt) NumInput() int {
return s.Stmt.NumParams()
}
func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
if err := s.Stmt.Exec(vtoi(args)...); err != nil {
return nil, err
}
return result{s.Stmt.Conn()}, nil
}
func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
if err := s.Stmt.Query(vtoi(args)...); err != nil && err != io.EOF {
return nil, err
}
return &rows{s, true}, nil
}
// result implements driver.Result.
type result struct {
*Conn
}
func (r result) LastInsertId() (int64, error) {
return int64(r.Conn.LastInsertId()), nil
}
func (r result) RowsAffected() (int64, error) {
return int64(r.Conn.RowsAffected()), nil
}
// rows implements driver.Rows.
type rows struct {
*stmt
first bool
}
func (r *rows) Close() error {
if r.stmt.closed {
return r.stmt.Stmt.Close()
}
r.stmt.Stmt.Reset()
return nil
}
func (r *rows) Next(dest []driver.Value) error {
if r.first {
r.first = false
if !r.stmt.Stmt.Busy() {
return io.EOF
}
} else if err := r.stmt.Stmt.Next(); err != nil {
return err
}
for i := range dest {
v := (*interface{})(&dest[i])
err := r.stmt.Stmt.scanDynamic(C.int(i), v, true)
if err != nil {
return err
}
}
return nil
}
// vtoi converts []driver.Value to []interface{} without copying the contents.
func vtoi(v []driver.Value) (i []interface{}) {
if len(v) > 0 {
h := (*reflect.SliceHeader)(unsafe.Pointer(&i))
h.Data = uintptr(unsafe.Pointer(&v[0]))
h.Len = len(v)
h.Cap = cap(v)
}
return
}

View File

@ -1,182 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sqlite3
/*
#include "sqlite3.h"
*/
import "C"
import (
"io"
"runtime"
)
// ErrBlobFull is returned by BlobIO.Write when there isn't enough space left to
// write the provided bytes.
var ErrBlobFull = &Error{ERROR, "incremental write failed, no space left"}
// BlobIO is a handle to a single BLOB (binary large object) or TEXT value
// opened for incremental I/O. This allows the value to be treated as a file for
// reading and writing. The value length cannot be changed using this API; use
// an UPDATE statement for that. The recommended way of allocating space for a
// BLOB is to use the ZeroBlob type or the zeroblob() SQL function.
// [http://www.sqlite.org/c3ref/blob.html]
type BlobIO struct {
conn *Conn
blob *C.sqlite3_blob
row int64 // ROWID of the row containing the BLOB/TEXT value
len int // Value length in bytes
off int // Current read/write offset
}
// newBlobIO initializes an incremental I/O operation.
func newBlobIO(c *Conn, db, tbl, col string, row int64, rw bool) (*BlobIO, error) {
db += "\x00"
tbl += "\x00"
col += "\x00"
var blob *C.sqlite3_blob
rc := C.sqlite3_blob_open(c.db, cStr(db), cStr(tbl), cStr(col),
C.sqlite3_int64(row), cBool(rw), &blob)
if rc != OK {
return nil, libErr(rc, c.db)
}
b := &BlobIO{
conn: c,
blob: blob,
row: row,
len: int(C.sqlite3_blob_bytes(blob)),
}
runtime.SetFinalizer(b, (*BlobIO).Close)
return b, nil
}
// Close releases all resources associated with the incremental I/O operation.
// It is important to check the error returned by this method, since disk I/O
// and other types of errors may not be reported until the changes are actually
// committed to the database.
// [http://www.sqlite.org/c3ref/blob_close.html]
func (b *BlobIO) Close() error {
if blob := b.blob; blob != nil {
b.blob = nil
b.len = 0
b.off = 0
runtime.SetFinalizer(b, nil)
if rc := C.sqlite3_blob_close(blob); rc != OK {
return libErr(rc, b.conn.db)
}
}
return nil
}
// Conn returns the connection that that created this incremental I/O operation.
func (b *BlobIO) Conn() *Conn {
return b.conn
}
// Row returns the ROWID of the row containing the BLOB/TEXT value.
func (b *BlobIO) Row() int64 {
return b.row
}
// Len returns the length of the BLOB/TEXT value in bytes. It is not possible to
// read/write/seek beyond this length. The length changes to 0 if the I/O handle
// expires due to an update of any column in the same row. This condition is
// indicated by an ABORT error code returned from Read or Write. An expired
// handle is closed automatically and cannot be reopened. Any writes that
// occurred before the abort are not rolled back.
// [http://www.sqlite.org/c3ref/blob_bytes.html]
func (b *BlobIO) Len() int {
return b.len
}
// Read implements the io.Reader interface.
// [http://www.sqlite.org/c3ref/blob_read.html]
func (b *BlobIO) Read(p []byte) (n int, err error) {
if b.blob == nil {
return 0, ErrBadIO
}
if b.off >= b.len {
return 0, io.EOF
}
if n = b.len - b.off; len(p) < n {
n = len(p)
}
rc := C.sqlite3_blob_read(b.blob, cBytes(p), C.int(n), C.int(b.off))
return b.io(rc, n)
}
// Write implements the io.Writer interface. The number of bytes written is
// always either 0 or len(p). ErrBlobFull is returned if there isn't enough
// space left to write all of p.
// [http://www.sqlite.org/c3ref/blob_write.html]
func (b *BlobIO) Write(p []byte) (n int, err error) {
if b.blob == nil {
return 0, ErrBadIO
}
if n = len(p); b.off+n > b.len {
// Doesn't make sense to do a partial write. Better to return quickly
// and let the caller reallocate the BLOB.
return 0, ErrBlobFull
}
rc := C.sqlite3_blob_write(b.blob, cBytes(p), C.int(n), C.int(b.off))
return b.io(rc, n)
}
// Seek implements the io.Seeker interface.
func (b *BlobIO) Seek(offset int64, whence int) (ret int64, err error) {
if b.blob == nil {
return 0, ErrBadIO
}
switch whence {
case 0:
case 1:
offset += int64(b.off)
case 2:
offset += int64(b.len)
default:
return 0, pkgErr(MISUSE, "invalid whence for BlobIO.Seek (%d)", whence)
}
if offset < 0 || offset > int64(b.len) {
return 0, pkgErr(MISUSE, "invalid offset for BlobIO.Seek (%d)", offset)
}
b.off = int(offset)
return offset, nil
}
// Reopen closes the current value and opens another one in the same column,
// specified by its ROWID. If an error is encountered, the I/O handle becomes
// unusable and is automatically closed.
// [http://www.sqlite.org/c3ref/blob_reopen.html]
func (b *BlobIO) Reopen(row int64) error {
if b.blob == nil {
return ErrBadIO
}
if rc := C.sqlite3_blob_reopen(b.blob, C.sqlite3_int64(row)); rc != OK {
err := libErr(rc, b.conn.db)
b.Close()
return err
}
b.row = row
b.len = int(C.sqlite3_blob_bytes(b.blob))
b.off = 0
return nil
}
// io handles the completion of a single Read/Write call.
func (b *BlobIO) io(rc C.int, n int) (int, error) {
if rc == OK {
b.off += n
return n, nil
}
err := libErr(rc, b.conn.db)
if rc == ABORT {
b.Close()
}
return 0, err
}

View File

@ -1,117 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#if defined(SQLITE_AMALGAMATION) && defined(SQLITE_HAS_CODEC)
#include "codec.h"
// codec.go exports.
int go_codec_init(const CodecCtx*,void**,char**);
int go_codec_reserve(void*);
void go_codec_resize(void*,int,int);
void *go_codec_exec(void*,void*,u32,int);
void go_codec_get_key(void*,void**,int*);
void go_codec_free(void*);
// sqlite3_key sets the codec key for the main database.
SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
return sqlite3_key_v2(db, 0, pKey, nKey);
}
// sqlite3_key_v2 sets the codec key for the specified database.
SQLITE_API int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
int iDb = 0;
int rc;
sqlite3_mutex_enter(db->mutex);
if (zDb && zDb[0]) {
iDb = sqlite3FindDbName(db, zDb);
}
if (iDb < 0) {
rc = SQLITE_ERROR;
sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
} else {
rc = sqlite3CodecAttach(db, iDb, pKey, nKey);
}
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
// sqlite3_rekey changes the codec key for the main database.
SQLITE_API int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
return sqlite3_rekey_v2(db, 0, pKey, nKey);
}
// sqlite3_rekey_v2 changes the codec key for the specified database.
SQLITE_API int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
int iDb = 0;
int rc;
sqlite3_mutex_enter(db->mutex);
rc = SQLITE_ERROR;
sqlite3Error(db, SQLITE_ERROR, "rekey is not implemented");
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
// sqlite3_activate_see isn't used by Go codecs, but it needs to be linked in.
SQLITE_API void sqlite3_activate_see(const char *zPassPhrase) {}
// sqlite3CodecAttach initializes the codec, reserves space at the end of each
// page, and attaches the codec to the specified database.
int sqlite3CodecAttach(sqlite3 *db, int iDb, const void *pKey, int nKey) {
Btree *pBt = db->aDb[iDb].pBt;
Pager *pPager = sqlite3BtreePager(pBt);
CodecCtx ctx;
void *pCodec = 0;
char *zErrMsg = 0;
int rc;
// An empty KEY clause in an ATTACH statement disables the codec and SQLite
// doesn't support codecs for in-memory databases.
if (nKey <= 0 || pPager->memDb) return SQLITE_OK;
ctx.db = db;
ctx.zPath = sqlite3BtreeGetFilename(pBt);
ctx.zName = db->aDb[iDb].zName;
ctx.nBuf = sqlite3BtreeGetPageSize(pBt);
ctx.nRes = sqlite3BtreeGetReserve(pBt);
ctx.pKey = pKey;
ctx.nKey = nKey;
sqlite3BtreeEnter(pBt);
ctx.fixed = (pBt->pBt->btsFlags & BTS_PAGESIZE_FIXED) != 0;
sqlite3BtreeLeave(pBt);
if ((rc=go_codec_init(&ctx, &pCodec, &zErrMsg)) != SQLITE_OK) {
sqlite3Error(db, rc, (zErrMsg ? "%s" : 0), zErrMsg);
free(zErrMsg);
} else if (pCodec) {
int nRes = go_codec_reserve(pCodec);
if (nRes != ctx.nRes && nRes >= 0) {
rc = sqlite3BtreeSetPageSize(pBt, -1, nRes, 0);
}
if (rc != SQLITE_OK) {
go_codec_free(pCodec);
sqlite3Error(db, rc, "unable to reserve page space for the codec");
} else {
sqlite3PagerSetCodec(pPager, go_codec_exec, go_codec_resize, go_codec_free, pCodec);
}
}
return rc;
}
// sqlite3CodecGetKey returns the codec key for the specified database.
void sqlite3CodecGetKey(sqlite3 *db, int iDb, void **pKey, int *nKey) {
void *pCodec = sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[iDb].pBt));
*pKey = 0;
*nKey = 0;
if (pCodec) {
go_codec_get_key(pCodec, pKey, nKey);
}
}
#endif

View File

@ -1,24 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#ifndef _CODEC_H_
#define _CODEC_H_
// Codec initialization context.
typedef struct {
sqlite3 *db;
const char *zPath;
const char *zName;
int nBuf;
int nRes;
int fixed;
const void *pKey;
int nKey;
} CodecCtx;
// SQLite codec hooks.
int sqlite3CodecAttach(sqlite3*,int,const void*,int);
void sqlite3CodecGetKey(sqlite3*,int,void**,int*);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "lib/sqlite3.c"
#include "lib/codec.c"

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "lib/sqlite3.h"
#include "lib/codec.h"

File diff suppressed because it is too large Load Diff

View File

@ -1,375 +0,0 @@
// Copyright 2013 The Go-SQLite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sqlite3
/*
#include "sqlite3.h"
*/
import "C"
import (
"bytes"
"fmt"
"reflect"
"unsafe"
)
// NamedArgs is a name/value map of arguments passed to a prepared statement
// that uses ?NNN, :AAA, @AAA, and/or $AAA parameter formats. Name matching is
// case-sensitive and the prefix character (one of [?:@$]) must be included in
// the name. Names that are missing from the map are treated as NULL. Names that
// are not used in the prepared statement are ignored.
//
// It is not possible to mix named and anonymous ("?") parameters in the same
// statement.
// [http://www.sqlite.org/lang_expr.html#varparam]
type NamedArgs map[string]interface{}
// RowMap may be passed as the last (or only) argument to Stmt.Scan to create a
// map of all remaining column/value pairs in the current row. The map is not
// cleared before being populated with new column values. Assignment is
// performed in left-to-right column order, and values may be overwritten if the
// query returns two or more columns with identical names.
type RowMap map[string]interface{}
// RawString and RawBytes are special string and []byte types that may be used
// for database input and output without the cost of an extra copy operation.
//
// When used as an argument to a statement, the contents are bound using
// SQLITE_STATIC instead of SQLITE_TRANSIENT flag. This requires the contents to
// remain valid and unmodified until the end of statement execution. In
// particular, the caller must keep a reference to the value to prevent it from
// being garbage collected.
//
// When used for retrieving query output, the internal string/[]byte pointer is
// set to reference memory belonging to SQLite. The memory remains valid until
// another method is called on the Stmt object and should not be modified.
type (
RawString string
RawBytes []byte
)
// Copy returns a Go-managed copy of s.
func (s RawString) Copy() string {
if s == "" {
return ""
}
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
return C.GoStringN((*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len))
}
// Copy returns a Go-managed copy of b.
func (b RawBytes) Copy() []byte {
if len(b) == 0 {
if b == nil {
return nil
}
return []byte("")
}
h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
return C.GoBytes(unsafe.Pointer(h.Data), C.int(h.Len))
}
// ZeroBlob is a special argument type used to allocate a zero-filled BLOB of
// the specified length. The BLOB can then be opened for incremental I/O to
// efficiently transfer a large amount of data. The maximum BLOB size can be
// queried with Conn.Limit(LIMIT_LENGTH, -1).
type ZeroBlob int
// BusyFunc is a callback function invoked by SQLite when it is unable to
// acquire a lock on a table. Count is the number of times that the callback has
// been invoked for this locking event so far. If the function returns false,
// then the operation is aborted. Otherwise, the function should block for a
// while before returning true and letting SQLite make another locking attempt.
type BusyFunc func(count int) (retry bool)
// CommitFunc is a callback function invoked by SQLite before a transaction is
// committed. If the function returns true, the transaction is rolled back.
type CommitFunc func() (abort bool)
// RollbackFunc is a callback function invoked by SQLite when a transaction is
// rolled back.
type RollbackFunc func()
// UpdateFunc is a callback function invoked by SQLite when a row is updated,
// inserted, or deleted.
type UpdateFunc func(op int, db, tbl RawString, row int64)
// Error is returned for all SQLite API result codes other than OK, ROW, and
// DONE.
type Error struct {
rc int
msg string
}
// NewError creates a new Error instance using the specified SQLite result code
// and error message.
func NewError(rc int, msg string) *Error {
return &Error{rc, msg}
}
// libErr reports an error originating in SQLite. The error message is obtained
// from the database connection when possible, which may include some additional
// information. Otherwise, the result code is translated to a generic message.
func libErr(rc C.int, db *C.sqlite3) error {
if db != nil && rc == C.sqlite3_errcode(db) {
return &Error{int(rc), C.GoString(C.sqlite3_errmsg(db))}
}
return &Error{int(rc), C.GoString(C.sqlite3_errstr(rc))}
}
// pkgErr reports an error originating in this package.
func pkgErr(rc int, msg string, v ...interface{}) error {
if len(v) == 0 {
return &Error{rc, msg}
}
return &Error{rc, fmt.Sprintf(msg, v...)}
}
// Code returns the SQLite extended result code.
func (err *Error) Code() int {
return err.rc
}
// Error implements the error interface.
func (err *Error) Error() string {
return fmt.Sprintf("sqlite3: %s [%d]", err.msg, err.rc)
}
// Errors returned for access attempts to closed or invalid objects.
var (
ErrBadConn = &Error{MISUSE, "closed or invalid connection"}
ErrBadStmt = &Error{MISUSE, "closed or invalid statement"}
ErrBadIO = &Error{MISUSE, "closed or invalid incremental I/O operation"}
ErrBadBackup = &Error{MISUSE, "closed or invalid backup operation"}
)
// Complete returns true if sql appears to contain a complete statement that is
// ready to be parsed. This does not validate the statement syntax.
// [http://www.sqlite.org/c3ref/complete.html]
func Complete(sql string) bool {
if initErr != nil {
return false
}
sql += "\x00"
return C.sqlite3_complete(cStr(sql)) == 1
}
// ReleaseMemory attempts to free n bytes of heap memory by deallocating
// non-essential memory held by the SQLite library. It returns the number of
// bytes actually freed.
//
// This function is currently a no-op because SQLite is not compiled with the
// SQLITE_ENABLE_MEMORY_MANAGEMENT option.
// [http://www.sqlite.org/c3ref/release_memory.html]
func ReleaseMemory(n int) int {
if initErr != nil {
return 0
}
return int(C.sqlite3_release_memory(C.int(n)))
}
// SingleThread returns true if the SQLite library was compiled with
// -DSQLITE_THREADSAFE=0. In this threading mode all mutex code is omitted and
// the package becomes unsafe for concurrent access, even to separate database
// connections.
//
// The SQLite source that's part of this package is compiled with
// -DSQLITE_THREADSAFE=2, so this function should always return false. It is
// kept for backward compatibility when dynamic linking was supported in Go 1.0.
// [http://www.sqlite.org/threadsafe.html]
func SingleThread() bool {
return initErr == nil && C.sqlite3_threadsafe() == 0
}
// SoftHeapLimit sets and/or queries the soft limit on the amount of heap memory
// that may be allocated by SQLite. A negative value for n keeps the current
// limit, while 0 removes the limit. The previous limit value is returned, with
// negative values indicating an error.
// [http://www.sqlite.org/c3ref/soft_heap_limit64.html]
func SoftHeapLimit(n int64) int64 {
if initErr != nil {
return -1
}
return int64(C.sqlite3_soft_heap_limit64(C.sqlite3_int64(n)))
}
// SourceId returns the check-in identifier of SQLite within its configuration
// management system.
// [http://www.sqlite.org/c3ref/c_source_id.html]
func SourceId() string {
if initErr != nil {
return ""
}
return C.GoString(C.sqlite3_sourceid())
}
// Status returns the current and peak values of a core performance
// counter, specified by one of the STATUS constants. If reset is true, the peak
// value is reset back down to the current value after retrieval.
// [http://www.sqlite.org/c3ref/status.html]
func Status(op int, reset bool) (cur, peak int, err error) {
if initErr != nil {
return 0, 0, initErr
}
var cCur, cPeak C.int
rc := C.sqlite3_status(C.int(op), &cCur, &cPeak, cBool(reset))
if rc != OK {
return 0, 0, pkgErr(MISUSE, "invalid status op (%d)", op)
}
return int(cCur), int(cPeak), nil
}
// Version returns the SQLite version as a string in the format "X.Y.Z[.N]".
// [http://www.sqlite.org/c3ref/libversion.html]
func Version() string {
if initErr != nil {
return ""
}
return goStr(C.sqlite3_libversion())
}
// VersionNum returns the SQLite version as an integer in the format X*1000000 +
// Y*1000 + Z, where X is the major version, Y is the minor version, and Z is
// the release number.
func VersionNum() int {
if initErr != nil {
return 0
}
return int(C.sqlite3_libversion_number())
}
// Print prints out all rows returned by a query. This function is intended as a
// debugging aid and may be removed or altered in the future. Do not use it in
// production applications.
func Print(s *Stmt) error {
if s == nil || s.NumColumns() == 0 {
return nil
}
var err error
if !s.Busy() {
if err = s.Query(); err != nil {
return err
}
}
cols := s.Columns()
buf := bytes.NewBuffer(make([]byte, 0, len(cols)*10))
row := make(RowMap, len(cols))
buf.WriteByte('~')
for _, col := range cols {
fmt.Fprintf(buf, " %s ~", col)
}
fmt.Println(buf)
for ; err == nil; err = s.Next() {
if err = s.Scan(row); err != nil {
return err
}
buf.Reset()
buf.WriteByte('|')
for _, col := range cols {
fmt.Fprintf(buf, " %*v |", len(col), row[col])
}
fmt.Println(buf)
}
return err
}
// raw casts s to a RawString.
func raw(s string) RawString {
return RawString(s)
}
// cStr returns a pointer to the first byte in s.
func cStr(s string) *C.char {
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
return (*C.char)(unsafe.Pointer(h.Data))
}
// cStrOffset returns the offset of p in s or -1 if p doesn't point into s.
func cStrOffset(s string, p *C.char) int {
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
if off := uintptr(unsafe.Pointer(p)) - h.Data; off < uintptr(h.Len) {
return int(off)
}
return -1
}
// cBytes returns a pointer to the first byte in b.
func cBytes(b []byte) unsafe.Pointer {
return unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data)
}
// cBool returns a C representation of a Go bool (false = 0, true = 1).
func cBool(b bool) C.int {
if b {
return 1
}
return 0
}
// goStr returns a Go representation of a null-terminated C string.
func goStr(p *C.char) (s string) {
if p != nil && *p != 0 {
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
h.Data = uintptr(unsafe.Pointer(p))
for *p != 0 {
p = (*C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1)) // p++
}
h.Len = int(uintptr(unsafe.Pointer(p)) - h.Data)
}
return
}
// goStrN returns a Go representation of an n-byte C string.
func goStrN(p *C.char, n C.int) (s string) {
if n > 0 {
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
h.Data = uintptr(unsafe.Pointer(p))
h.Len = int(n)
}
return
}
// goBytes returns a Go representation of an n-byte C array.
func goBytes(p unsafe.Pointer, n C.int) (b []byte) {
if n > 0 {
h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
h.Data = uintptr(p)
h.Len = int(n)
h.Cap = int(n)
}
return
}
// bstr returns a string pointing into the byte slice b.
func bstr(b []byte) (s string) {
if len(b) > 0 {
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
h.Data = uintptr(unsafe.Pointer(&b[0]))
h.Len = len(b)
}
return
}
//export go_busy_handler
func go_busy_handler(c unsafe.Pointer, count C.int) (retry C.int) {
return cBool((*Conn)(c).busy(int(count)))
}
//export go_commit_hook
func go_commit_hook(c unsafe.Pointer) (abort C.int) {
return cBool((*Conn)(c).commit())
}
//export go_rollback_hook
func go_rollback_hook(c unsafe.Pointer) {
(*Conn)(c).rollback()
}
//export go_update_hook
func go_update_hook(c unsafe.Pointer, op C.int, db, tbl *C.char, row C.sqlite3_int64) {
(*Conn)(c).update(int(op), raw(goStr(db)), raw(goStr(tbl)), int64(row))
}

View File

@ -0,0 +1,498 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package sqlite3 provides access to the SQLite library, version 3.
//
// The package has no exported API.
// It registers a driver for the standard Go database/sql package.
//
// import _ "code.google.com/p/gosqlite/sqlite3"
//
// (For an alternate, earlier API, see the code.google.com/p/gosqlite/sqlite package.)
package sqlite
/*
#cgo LDFLAGS: -lsqlite3
#include <sqlite3.h>
#include <stdlib.h>
// These wrappers are necessary because SQLITE_TRANSIENT
// is a pointer constant, and cgo doesn't translate them correctly.
// The definition in sqlite3.h is:
//
// typedef void (*sqlite3_destructor_type)(void*);
// #define SQLITE_STATIC ((sqlite3_destructor_type)0)
// #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
static int my_bind_text(sqlite3_stmt *stmt, int n, char *p, int np) {
return sqlite3_bind_text(stmt, n, p, np, SQLITE_TRANSIENT);
}
static int my_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) {
return sqlite3_bind_blob(stmt, n, p, np, SQLITE_TRANSIENT);
}
*/
import "C"
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"io"
"strings"
"time"
"unsafe"
)
func init() {
sql.Register("sqlite3", impl{})
}
type errno int
func (e errno) Error() string {
s := errText[e]
if s == "" {
return fmt.Sprintf("errno %d", int(e))
}
return s
}
var (
errError error = errno(1) // /* SQL error or missing database */
errInternal error = errno(2) // /* Internal logic error in SQLite */
errPerm error = errno(3) // /* Access permission denied */
errAbort error = errno(4) // /* Callback routine requested an abort */
errBusy error = errno(5) // /* The database file is locked */
errLocked error = errno(6) // /* A table in the database is locked */
errNoMem error = errno(7) // /* A malloc() failed */
errReadOnly error = errno(8) // /* Attempt to write a readonly database */
errInterrupt error = errno(9) // /* Operation terminated by sqlite3_interrupt()*/
errIOErr error = errno(10) // /* Some kind of disk I/O error occurred */
errCorrupt error = errno(11) // /* The database disk image is malformed */
errFull error = errno(13) // /* Insertion failed because database is full */
errCantOpen error = errno(14) // /* Unable to open the database file */
errEmpty error = errno(16) // /* Database is empty */
errSchema error = errno(17) // /* The database schema changed */
errTooBig error = errno(18) // /* String or BLOB exceeds size limit */
errConstraint error = errno(19) // /* Abort due to constraint violation */
errMismatch error = errno(20) // /* Data type mismatch */
errMisuse error = errno(21) // /* Library used incorrectly */
errNolfs error = errno(22) // /* Uses OS features not supported on host */
errAuth error = errno(23) // /* Authorization denied */
errFormat error = errno(24) // /* Auxiliary database format error */
errRange error = errno(25) // /* 2nd parameter to sqlite3_bind out of range */
errNotDB error = errno(26) // /* File opened that is not a database file */
stepRow = errno(100) // /* sqlite3_step() has another row ready */
stepDone = errno(101) // /* sqlite3_step() has finished executing */
)
var errText = map[errno]string{
1: "SQL error or missing database",
2: "Internal logic error in SQLite",
3: "Access permission denied",
4: "Callback routine requested an abort",
5: "The database file is locked",
6: "A table in the database is locked",
7: "A malloc() failed",
8: "Attempt to write a readonly database",
9: "Operation terminated by sqlite3_interrupt()*/",
10: "Some kind of disk I/O error occurred",
11: "The database disk image is malformed",
12: "NOT USED. Table or record not found",
13: "Insertion failed because database is full",
14: "Unable to open the database file",
15: "NOT USED. Database lock protocol error",
16: "Database is empty",
17: "The database schema changed",
18: "String or BLOB exceeds size limit",
19: "Abort due to constraint violation",
20: "Data type mismatch",
21: "Library used incorrectly",
22: "Uses OS features not supported on host",
23: "Authorization denied",
24: "Auxiliary database format error",
25: "2nd parameter to sqlite3_bind out of range",
26: "File opened that is not a database file",
100: "sqlite3_step() has another row ready",
101: "sqlite3_step() has finished executing",
}
type impl struct{}
func (impl) Open(name string) (driver.Conn, error) {
if C.sqlite3_threadsafe() == 0 {
return nil, errors.New("sqlite library was not compiled for thread-safe operation")
}
var db *C.sqlite3
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
rv := C.sqlite3_open_v2(cname, &db,
C.SQLITE_OPEN_FULLMUTEX|
C.SQLITE_OPEN_READWRITE|
C.SQLITE_OPEN_CREATE,
nil)
if rv != 0 {
return nil, errno(rv)
}
if db == nil {
return nil, errors.New("sqlite succeeded without returning a database")
}
return &conn{db: db}, nil
}
type conn struct {
db *C.sqlite3
closed bool
tx bool
}
func (c *conn) error(rv C.int) error {
if rv == 0 {
return nil
}
if rv == 21 || c.closed {
return errno(rv)
}
return errors.New(errno(rv).Error() + ": " + C.GoString(C.sqlite3_errmsg(c.db)))
}
func (c *conn) Prepare(cmd string) (driver.Stmt, error) {
if c.closed {
panic("database/sql/driver: misuse of sqlite driver: Prepare after Close")
}
cmdstr := C.CString(cmd)
defer C.free(unsafe.Pointer(cmdstr))
var s *C.sqlite3_stmt
var tail *C.char
rv := C.sqlite3_prepare_v2(c.db, cmdstr, C.int(len(cmd)+1), &s, &tail)
if rv != 0 {
return nil, c.error(rv)
}
return &stmt{c: c, stmt: s, sql: cmd, t0: time.Now()}, nil
}
func (c *conn) Close() error {
if c.closed {
panic("database/sql/driver: misuse of sqlite driver: multiple Close")
}
c.closed = true
rv := C.sqlite3_close(c.db)
c.db = nil
return c.error(rv)
}
func (c *conn) exec(cmd string) error {
cstring := C.CString(cmd)
defer C.free(unsafe.Pointer(cstring))
rv := C.sqlite3_exec(c.db, cstring, nil, nil, nil)
return c.error(rv)
}
func (c *conn) Begin() (driver.Tx, error) {
if c.tx {
panic("database/sql/driver: misuse of sqlite driver: multiple Tx")
}
if err := c.exec("BEGIN TRANSACTION"); err != nil {
return nil, err
}
c.tx = true
return &tx{c}, nil
}
type tx struct {
c *conn
}
func (t *tx) Commit() error {
if t.c == nil || !t.c.tx {
panic("database/sql/driver: misuse of sqlite driver: extra Commit")
}
t.c.tx = false
err := t.c.exec("COMMIT TRANSACTION")
t.c = nil
return err
}
func (t *tx) Rollback() error {
if t.c == nil || !t.c.tx {
panic("database/sql/driver: misuse of sqlite driver: extra Rollback")
}
t.c.tx = false
err := t.c.exec("ROLLBACK")
t.c = nil
return err
}
type stmt struct {
c *conn
stmt *C.sqlite3_stmt
err error
t0 time.Time
sql string
args string
closed bool
rows bool
colnames []string
coltypes []string
}
func (s *stmt) Close() error {
if s.rows {
panic("database/sql/driver: misuse of sqlite driver: Close with active Rows")
}
if s.closed {
panic("database/sql/driver: misuse of sqlite driver: double Close of Stmt")
}
s.closed = true
rv := C.sqlite3_finalize(s.stmt)
if rv != 0 {
return s.c.error(rv)
}
return nil
}
func (s *stmt) NumInput() int {
if s.closed {
panic("database/sql/driver: misuse of sqlite driver: NumInput after Close")
}
return int(C.sqlite3_bind_parameter_count(s.stmt))
}
func (s *stmt) reset() error {
return s.c.error(C.sqlite3_reset(s.stmt))
}
func (s *stmt) start(args []driver.Value) error {
if err := s.reset(); err != nil {
return err
}
n := int(C.sqlite3_bind_parameter_count(s.stmt))
if n != len(args) {
return fmt.Errorf("incorrect argument count for command: have %d want %d", len(args), n)
}
for i, v := range args {
var str string
switch v := v.(type) {
case nil:
if rv := C.sqlite3_bind_null(s.stmt, C.int(i+1)); rv != 0 {
return s.c.error(rv)
}
continue
case float64:
if rv := C.sqlite3_bind_double(s.stmt, C.int(i+1), C.double(v)); rv != 0 {
return s.c.error(rv)
}
continue
case int64:
if rv := C.sqlite3_bind_int64(s.stmt, C.int(i+1), C.sqlite3_int64(v)); rv != 0 {
return s.c.error(rv)
}
continue
case []byte:
var p *byte
if len(v) > 0 {
p = &v[0]
}
if rv := C.my_bind_blob(s.stmt, C.int(i+1), unsafe.Pointer(p), C.int(len(v))); rv != 0 {
return s.c.error(rv)
}
continue
case bool:
var vi int64
if v {
vi = 1
}
if rv := C.sqlite3_bind_int64(s.stmt, C.int(i+1), C.sqlite3_int64(vi)); rv != 0 {
return s.c.error(rv)
}
continue
case time.Time:
str = v.UTC().Format(timefmt[0])
case string:
str = v
default:
str = fmt.Sprint(v)
}
cstr := C.CString(str)
rv := C.my_bind_text(s.stmt, C.int(i+1), cstr, C.int(len(str)))
C.free(unsafe.Pointer(cstr))
if rv != 0 {
return s.c.error(rv)
}
}
return nil
}
func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
if s.closed {
panic("database/sql/driver: misuse of sqlite driver: Exec after Close")
}
if s.rows {
panic("database/sql/driver: misuse of sqlite driver: Exec with active Rows")
}
err := s.start(args)
if err != nil {
return nil, err
}
rv := C.sqlite3_step(s.stmt)
if errno(rv) != stepDone {
if rv == 0 {
rv = 21 // errMisuse
}
return nil, s.c.error(rv)
}
id := int64(C.sqlite3_last_insert_rowid(s.c.db))
rows := int64(C.sqlite3_changes(s.c.db))
return &result{id, rows}, nil
}
func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
if s.closed {
panic("database/sql/driver: misuse of sqlite driver: Query after Close")
}
if s.rows {
panic("database/sql/driver: misuse of sqlite driver: Query with active Rows")
}
err := s.start(args)
if err != nil {
return nil, err
}
s.rows = true
if s.colnames == nil {
n := int64(C.sqlite3_column_count(s.stmt))
s.colnames = make([]string, n)
s.coltypes = make([]string, n)
for i := range s.colnames {
s.colnames[i] = C.GoString(C.sqlite3_column_name(s.stmt, C.int(i)))
s.coltypes[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(s.stmt, C.int(i))))
}
}
return &rows{s}, nil
}
type rows struct {
s *stmt
}
func (r *rows) Columns() []string {
if r.s == nil {
panic("database/sql/driver: misuse of sqlite driver: Columns of closed Rows")
}
return r.s.colnames
}
const maxslice = 1<<31 - 1
var timefmt = []string{
"2006-01-02 15:04:05.999999999",
"2006-01-02T15:04:05.999999999",
"2006-01-02 15:04:05",
"2006-01-02T15:04:05",
"2006-01-02 15:04",
"2006-01-02T15:04",
"2006-01-02",
}
func (r *rows) Next(dst []driver.Value) error {
if r.s == nil {
panic("database/sql/driver: misuse of sqlite driver: Next of closed Rows")
}
rv := C.sqlite3_step(r.s.stmt)
if errno(rv) != stepRow {
if errno(rv) == stepDone {
return io.EOF
}
if rv == 0 {
rv = 21
}
return r.s.c.error(rv)
}
for i := range dst {
switch typ := C.sqlite3_column_type(r.s.stmt, C.int(i)); typ {
default:
return fmt.Errorf("unexpected sqlite3 column type %d", typ)
case C.SQLITE_INTEGER:
val := int64(C.sqlite3_column_int64(r.s.stmt, C.int(i)))
switch r.s.coltypes[i] {
case "timestamp", "datetime":
dst[i] = time.Unix(val, 0).UTC()
case "boolean":
dst[i] = val > 0
default:
dst[i] = val
}
case C.SQLITE_FLOAT:
dst[i] = float64(C.sqlite3_column_double(r.s.stmt, C.int(i)))
case C.SQLITE_BLOB, C.SQLITE_TEXT:
n := int(C.sqlite3_column_bytes(r.s.stmt, C.int(i)))
var b []byte
if n > 0 {
p := C.sqlite3_column_blob(r.s.stmt, C.int(i))
b = (*[maxslice]byte)(unsafe.Pointer(p))[:n]
}
dst[i] = b
switch r.s.coltypes[i] {
case "timestamp", "datetime":
dst[i] = time.Time{}
s := string(b)
for _, f := range timefmt {
if t, err := time.Parse(f, s); err == nil {
dst[i] = t
break
}
}
}
case C.SQLITE_NULL:
dst[i] = nil
}
}
return nil
}
func (r *rows) Close() error {
if r.s == nil {
panic("database/sql/driver: misuse of sqlite driver: Close of closed Rows")
}
r.s.rows = false
r.s = nil
return nil
}
type result struct {
id int64
rows int64
}
func (r *result) LastInsertId() (int64, error) {
return r.id, nil
}
func (r *result) RowsAffected() (int64, error) {
return r.rows, nil
}