mirror of https://github.com/docker/docs.git
bump godeps
This commit is contained in:
parent
b858e939a3
commit
97e83d3238
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
183
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/codec/aes-hmac.go
generated
vendored
183
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/codec/aes-hmac.go
generated
vendored
|
@ -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:]
|
||||
}
|
|
@ -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
|
||||
}
|
128
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/codec/codec_test.go
generated
vendored
128
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/codec/codec_test.go
generated
vendored
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
105
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/codec/hexdump.go
generated
vendored
105
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/codec/hexdump.go
generated
vendored
|
@ -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"))
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
141343
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/lib/sqlite3.c
generated
vendored
141343
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/lib/sqlite3.c
generated
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
@ -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"
|
1307
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/sqlite3_test.go
generated
vendored
1307
Godeps/_workspace/src/code.google.com/p/go-sqlite/go1/sqlite3/sqlite3_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
|
@ -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))
|
||||
}
|
498
Godeps/_workspace/src/code.google.com/p/gosqlite/sqlite3/driver.go
generated
vendored
Normal file
498
Godeps/_workspace/src/code.google.com/p/gosqlite/sqlite3/driver.go
generated
vendored
Normal 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
|
||||
}
|
Loading…
Reference in New Issue