mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
fix(go16): fixed hang with go 1.6 by updating sqlite3, fixes #4367
This commit is contained in:
parent
0c5abc491d
commit
72b324c95b
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -1,7 +1,6 @@
|
||||
{
|
||||
"ImportPath": "github.com/grafana/grafana",
|
||||
"GoVersion": "go1.5.1",
|
||||
"GodepVersion": "v60",
|
||||
"Packages": [
|
||||
"./pkg/..."
|
||||
],
|
||||
@ -276,7 +275,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-sqlite3",
|
||||
"Rev": "e28cd440fabdd39b9520344bc26829f61db40ece"
|
||||
"Comment": "v1.1.0-67-g7204887",
|
||||
"Rev": "7204887cf3a42df1cfaa5505dc3a3427f6dded8b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rainycape/unidecode",
|
||||
|
8
Godeps/_workspace/src/github.com/mattn/go-sqlite3/.travis.yml
generated
vendored
8
Godeps/_workspace/src/github.com/mattn/go-sqlite3/.travis.yml
generated
vendored
@ -1,9 +1,13 @@
|
||||
language: go
|
||||
sudo: required
|
||||
dist: trusty
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
before_install:
|
||||
- go get github.com/axw/gocov/gocov
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx
|
||||
- $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx
|
||||
- go test -v . -tags "libsqlite3"
|
||||
|
27
Godeps/_workspace/src/github.com/mattn/go-sqlite3/README.md
generated
vendored
27
Godeps/_workspace/src/github.com/mattn/go-sqlite3/README.md
generated
vendored
@ -1,8 +1,9 @@
|
||||
go-sqlite3
|
||||
==========
|
||||
|
||||
[](https://travis-ci.org/mattn/go-sqlite3)
|
||||
[](https://coveralls.io/r/mattn/go-sqlite3?branch=master)
|
||||
[](https://travis-ci.org/mattn/go-sqlite3)
|
||||
[](https://coveralls.io/r/mattn/go-sqlite3?branch=master)
|
||||
[](http://godoc.org/github.com/mattn/go-sqlite3)
|
||||
|
||||
Description
|
||||
-----------
|
||||
@ -16,6 +17,10 @@ This package can be installed with the go get command:
|
||||
|
||||
go get github.com/mattn/go-sqlite3
|
||||
|
||||
_go-sqlite3_ is *cgo* package.
|
||||
If you want to build your app using go-sqlite3, you need gcc.
|
||||
However, if you install _go-sqlite3_ with `go install github.com/mattn/go-sqlite3`, you don't need gcc to build your app anymore.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
@ -26,6 +31,20 @@ Examples can be found under the `./_example` directory
|
||||
FAQ
|
||||
---
|
||||
|
||||
* Want to build go-sqlite3 with libsqlite3 on my linux.
|
||||
|
||||
Use `go build --tags "libsqlite3 linux"`
|
||||
|
||||
* Want to build go-sqlite3 with libsqlite3 on OS X.
|
||||
|
||||
Install sqlite3 from homebrew: `brew install sqlite3`
|
||||
|
||||
Use `go build --tags "libsqlite3 darwin"`
|
||||
|
||||
* Want to build go-sqlite3 with icu extension.
|
||||
|
||||
Use `go build --tags "icu"`
|
||||
|
||||
* Can't build go-sqlite3 on windows 64bit.
|
||||
|
||||
> Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit.
|
||||
@ -36,7 +55,7 @@ FAQ
|
||||
> You can pass some arguments into the connection string, for example, a URI.
|
||||
> See: https://github.com/mattn/go-sqlite3/issues/39
|
||||
|
||||
* Do you want cross compiling? mingw on Linux or Mac?
|
||||
* Do you want to cross compile? mingw on Linux or Mac?
|
||||
|
||||
> See: https://github.com/mattn/go-sqlite3/issues/106
|
||||
> See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html
|
||||
@ -54,7 +73,7 @@ sqlite3-binding.c, sqlite3-binding.h, sqlite3ext.h
|
||||
|
||||
The -binding suffix was added to avoid build failures under gccgo.
|
||||
|
||||
In this repository, those files are amalgamation code that copied from SQLite3. The license of those codes are depend on the license of SQLite3.
|
||||
In this repository, those files are an amalgamation of code that was copied from SQLite3. The license of that code is the same as the license of SQLite3.
|
||||
|
||||
Author
|
||||
------
|
||||
|
4
Godeps/_workspace/src/github.com/mattn/go-sqlite3/backup.go
generated
vendored
4
Godeps/_workspace/src/github.com/mattn/go-sqlite3/backup.go
generated
vendored
@ -6,7 +6,11 @@
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#ifndef USE_LIBSQLITE3
|
||||
#include <sqlite3-binding.h>
|
||||
#else
|
||||
#include <sqlite3.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
|
336
Godeps/_workspace/src/github.com/mattn/go-sqlite3/callback.go
generated
vendored
Normal file
336
Godeps/_workspace/src/github.com/mattn/go-sqlite3/callback.go
generated
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
// You can't export a Go function to C and have definitions in the C
|
||||
// preamble in the same file, so we have to have callbackTrampoline in
|
||||
// its own file. Because we need a separate file anyway, the support
|
||||
// code for SQLite custom functions is in here.
|
||||
|
||||
/*
|
||||
#include <sqlite3-binding.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
|
||||
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//export callbackTrampoline
|
||||
func callbackTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) {
|
||||
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
|
||||
fi := lookupHandle(uintptr(C.sqlite3_user_data(ctx))).(*functionInfo)
|
||||
fi.Call(ctx, args)
|
||||
}
|
||||
|
||||
//export stepTrampoline
|
||||
func stepTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) {
|
||||
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
|
||||
ai := lookupHandle(uintptr(C.sqlite3_user_data(ctx))).(*aggInfo)
|
||||
ai.Step(ctx, args)
|
||||
}
|
||||
|
||||
//export doneTrampoline
|
||||
func doneTrampoline(ctx *C.sqlite3_context) {
|
||||
handle := uintptr(C.sqlite3_user_data(ctx))
|
||||
ai := lookupHandle(handle).(*aggInfo)
|
||||
ai.Done(ctx)
|
||||
}
|
||||
|
||||
// Use handles to avoid passing Go pointers to C.
|
||||
|
||||
type handleVal struct {
|
||||
db *SQLiteConn
|
||||
val interface{}
|
||||
}
|
||||
|
||||
var handleLock sync.Mutex
|
||||
var handleVals = make(map[uintptr]handleVal)
|
||||
var handleIndex uintptr = 100
|
||||
|
||||
func newHandle(db *SQLiteConn, v interface{}) uintptr {
|
||||
handleLock.Lock()
|
||||
defer handleLock.Unlock()
|
||||
i := handleIndex
|
||||
handleIndex++
|
||||
handleVals[i] = handleVal{db, v}
|
||||
return i
|
||||
}
|
||||
|
||||
func lookupHandle(handle uintptr) interface{} {
|
||||
handleLock.Lock()
|
||||
defer handleLock.Unlock()
|
||||
r, ok := handleVals[handle]
|
||||
if !ok {
|
||||
if handle >= 100 && handle < handleIndex {
|
||||
panic("deleted handle")
|
||||
} else {
|
||||
panic("invalid handle")
|
||||
}
|
||||
}
|
||||
return r.val
|
||||
}
|
||||
|
||||
func deleteHandles(db *SQLiteConn) {
|
||||
handleLock.Lock()
|
||||
defer handleLock.Unlock()
|
||||
for handle, val := range handleVals {
|
||||
if val.db == db {
|
||||
delete(handleVals, handle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is only here so that tests can refer to it.
|
||||
type callbackArgRaw C.sqlite3_value
|
||||
|
||||
type callbackArgConverter func(*C.sqlite3_value) (reflect.Value, error)
|
||||
|
||||
type callbackArgCast struct {
|
||||
f callbackArgConverter
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (c callbackArgCast) Run(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
val, err := c.f(v)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
if !val.Type().ConvertibleTo(c.typ) {
|
||||
return reflect.Value{}, fmt.Errorf("cannot convert %s to %s", val.Type(), c.typ)
|
||||
}
|
||||
return val.Convert(c.typ), nil
|
||||
}
|
||||
|
||||
func callbackArgInt64(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
|
||||
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
|
||||
}
|
||||
return reflect.ValueOf(int64(C.sqlite3_value_int64(v))), nil
|
||||
}
|
||||
|
||||
func callbackArgBool(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
|
||||
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
|
||||
}
|
||||
i := int64(C.sqlite3_value_int64(v))
|
||||
val := false
|
||||
if i != 0 {
|
||||
val = true
|
||||
}
|
||||
return reflect.ValueOf(val), nil
|
||||
}
|
||||
|
||||
func callbackArgFloat64(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
if C.sqlite3_value_type(v) != C.SQLITE_FLOAT {
|
||||
return reflect.Value{}, fmt.Errorf("argument must be a FLOAT")
|
||||
}
|
||||
return reflect.ValueOf(float64(C.sqlite3_value_double(v))), nil
|
||||
}
|
||||
|
||||
func callbackArgBytes(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
switch C.sqlite3_value_type(v) {
|
||||
case C.SQLITE_BLOB:
|
||||
l := C.sqlite3_value_bytes(v)
|
||||
p := C.sqlite3_value_blob(v)
|
||||
return reflect.ValueOf(C.GoBytes(p, l)), nil
|
||||
case C.SQLITE_TEXT:
|
||||
l := C.sqlite3_value_bytes(v)
|
||||
c := unsafe.Pointer(C.sqlite3_value_text(v))
|
||||
return reflect.ValueOf(C.GoBytes(c, l)), nil
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
|
||||
}
|
||||
}
|
||||
|
||||
func callbackArgString(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
switch C.sqlite3_value_type(v) {
|
||||
case C.SQLITE_BLOB:
|
||||
l := C.sqlite3_value_bytes(v)
|
||||
p := (*C.char)(C.sqlite3_value_blob(v))
|
||||
return reflect.ValueOf(C.GoStringN(p, l)), nil
|
||||
case C.SQLITE_TEXT:
|
||||
c := (*C.char)(unsafe.Pointer(C.sqlite3_value_text(v)))
|
||||
return reflect.ValueOf(C.GoString(c)), nil
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
|
||||
}
|
||||
}
|
||||
|
||||
func callbackArgGeneric(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
switch C.sqlite3_value_type(v) {
|
||||
case C.SQLITE_INTEGER:
|
||||
return callbackArgInt64(v)
|
||||
case C.SQLITE_FLOAT:
|
||||
return callbackArgFloat64(v)
|
||||
case C.SQLITE_TEXT:
|
||||
return callbackArgString(v)
|
||||
case C.SQLITE_BLOB:
|
||||
return callbackArgBytes(v)
|
||||
case C.SQLITE_NULL:
|
||||
// Interpret NULL as a nil byte slice.
|
||||
var ret []byte
|
||||
return reflect.ValueOf(ret), nil
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
func callbackArg(typ reflect.Type) (callbackArgConverter, error) {
|
||||
switch typ.Kind() {
|
||||
case reflect.Interface:
|
||||
if typ.NumMethod() != 0 {
|
||||
return nil, errors.New("the only supported interface type is interface{}")
|
||||
}
|
||||
return callbackArgGeneric, nil
|
||||
case reflect.Slice:
|
||||
if typ.Elem().Kind() != reflect.Uint8 {
|
||||
return nil, errors.New("the only supported slice type is []byte")
|
||||
}
|
||||
return callbackArgBytes, nil
|
||||
case reflect.String:
|
||||
return callbackArgString, nil
|
||||
case reflect.Bool:
|
||||
return callbackArgBool, nil
|
||||
case reflect.Int64:
|
||||
return callbackArgInt64, nil
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||
c := callbackArgCast{callbackArgInt64, typ}
|
||||
return c.Run, nil
|
||||
case reflect.Float64:
|
||||
return callbackArgFloat64, nil
|
||||
case reflect.Float32:
|
||||
c := callbackArgCast{callbackArgFloat64, typ}
|
||||
return c.Run, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("don't know how to convert to %s", typ)
|
||||
}
|
||||
}
|
||||
|
||||
func callbackConvertArgs(argv []*C.sqlite3_value, converters []callbackArgConverter, variadic callbackArgConverter) ([]reflect.Value, error) {
|
||||
var args []reflect.Value
|
||||
|
||||
if len(argv) < len(converters) {
|
||||
return nil, fmt.Errorf("function requires at least %d arguments", len(converters))
|
||||
}
|
||||
|
||||
for i, arg := range argv[:len(converters)] {
|
||||
v, err := converters[i](arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, v)
|
||||
}
|
||||
|
||||
if variadic != nil {
|
||||
for _, arg := range argv[len(converters):] {
|
||||
v, err := variadic(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, v)
|
||||
}
|
||||
}
|
||||
return args, nil
|
||||
}
|
||||
|
||||
type callbackRetConverter func(*C.sqlite3_context, reflect.Value) error
|
||||
|
||||
func callbackRetInteger(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int64:
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||
v = v.Convert(reflect.TypeOf(int64(0)))
|
||||
case reflect.Bool:
|
||||
b := v.Interface().(bool)
|
||||
if b {
|
||||
v = reflect.ValueOf(int64(1))
|
||||
} else {
|
||||
v = reflect.ValueOf(int64(0))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("cannot convert %s to INTEGER", v.Type())
|
||||
}
|
||||
|
||||
C.sqlite3_result_int64(ctx, C.sqlite3_int64(v.Interface().(int64)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func callbackRetFloat(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Float64:
|
||||
case reflect.Float32:
|
||||
v = v.Convert(reflect.TypeOf(float64(0)))
|
||||
default:
|
||||
return fmt.Errorf("cannot convert %s to FLOAT", v.Type())
|
||||
}
|
||||
|
||||
C.sqlite3_result_double(ctx, C.double(v.Interface().(float64)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func callbackRetBlob(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||
if v.Type().Kind() != reflect.Slice || v.Type().Elem().Kind() != reflect.Uint8 {
|
||||
return fmt.Errorf("cannot convert %s to BLOB", v.Type())
|
||||
}
|
||||
i := v.Interface()
|
||||
if i == nil || len(i.([]byte)) == 0 {
|
||||
C.sqlite3_result_null(ctx)
|
||||
} else {
|
||||
bs := i.([]byte)
|
||||
C._sqlite3_result_blob(ctx, unsafe.Pointer(&bs[0]), C.int(len(bs)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||
if v.Type().Kind() != reflect.String {
|
||||
return fmt.Errorf("cannot convert %s to TEXT", v.Type())
|
||||
}
|
||||
C._sqlite3_result_text(ctx, C.CString(v.Interface().(string)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func callbackRet(typ reflect.Type) (callbackRetConverter, error) {
|
||||
switch typ.Kind() {
|
||||
case reflect.Slice:
|
||||
if typ.Elem().Kind() != reflect.Uint8 {
|
||||
return nil, errors.New("the only supported slice type is []byte")
|
||||
}
|
||||
return callbackRetBlob, nil
|
||||
case reflect.String:
|
||||
return callbackRetText, nil
|
||||
case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||
return callbackRetInteger, nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return callbackRetFloat, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("don't know how to convert to %s", typ)
|
||||
}
|
||||
}
|
||||
|
||||
func callbackError(ctx *C.sqlite3_context, err error) {
|
||||
cstr := C.CString(err.Error())
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
C.sqlite3_result_error(ctx, cstr, -1)
|
||||
}
|
||||
|
||||
// Test support code. Tests are not allowed to import "C", so we can't
|
||||
// declare any functions that use C.sqlite3_value.
|
||||
func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter {
|
||||
return func(*C.sqlite3_value) (reflect.Value, error) {
|
||||
return v, err
|
||||
}
|
||||
}
|
41
Godeps/_workspace/src/github.com/mattn/go-sqlite3/doc.go
generated
vendored
41
Godeps/_workspace/src/github.com/mattn/go-sqlite3/doc.go
generated
vendored
@ -1,7 +1,7 @@
|
||||
/*
|
||||
Package sqlite3 provides interface to SQLite3 databases.
|
||||
|
||||
This works as driver for database/sql.
|
||||
This works as a driver for database/sql.
|
||||
|
||||
Installation
|
||||
|
||||
@ -9,7 +9,7 @@ Installation
|
||||
|
||||
Supported Types
|
||||
|
||||
Currently, go-sqlite3 support following data types.
|
||||
Currently, go-sqlite3 supports the following data types.
|
||||
|
||||
+------------------------------+
|
||||
|go | sqlite3 |
|
||||
@ -26,14 +26,14 @@ Currently, go-sqlite3 support following data types.
|
||||
|
||||
SQLite3 Extension
|
||||
|
||||
You can write your own extension module for sqlite3. For example, below is a
|
||||
extension for Regexp matcher operation.
|
||||
You can write your own extension module for sqlite3. For example, below is an
|
||||
extension for a Regexp matcher operation.
|
||||
|
||||
#include <pcre.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sqlite3ext.h>
|
||||
|
||||
|
||||
SQLITE_EXTENSION_INIT1
|
||||
static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
||||
if (argc >= 2) {
|
||||
@ -44,7 +44,7 @@ extension for Regexp matcher operation.
|
||||
int vec[500];
|
||||
int n, rc;
|
||||
pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL);
|
||||
rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
|
||||
rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
|
||||
if (rc <= 0) {
|
||||
sqlite3_result_error(context, errstr, 0);
|
||||
return;
|
||||
@ -52,7 +52,7 @@ extension for Regexp matcher operation.
|
||||
sqlite3_result_int(context, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
@ -63,8 +63,8 @@ extension for Regexp matcher operation.
|
||||
(void*)db, regexp_func, NULL, NULL);
|
||||
}
|
||||
|
||||
It need to build as so/dll shared library. And you need to register
|
||||
extension module like below.
|
||||
It needs to be built as a so/dll shared library. And you need to register
|
||||
the extension module like below.
|
||||
|
||||
sql.Register("sqlite3_with_extensions",
|
||||
&sqlite3.SQLiteDriver{
|
||||
@ -79,9 +79,9 @@ Then, you can use this extension.
|
||||
|
||||
Connection Hook
|
||||
|
||||
You can hook and inject your codes when connection established. database/sql
|
||||
doesn't provide the way to get native go-sqlite3 interfaces. So if you want,
|
||||
you need to hook ConnectHook and get the SQLiteConn.
|
||||
You can hook and inject your code when the connection is established. database/sql
|
||||
doesn't provide a way to get native go-sqlite3 interfaces. So if you want,
|
||||
you need to set ConnectHook and get the SQLiteConn.
|
||||
|
||||
sql.Register("sqlite3_with_hook_example",
|
||||
&sqlite3.SQLiteDriver{
|
||||
@ -91,5 +91,22 @@ you need to hook ConnectHook and get the SQLiteConn.
|
||||
},
|
||||
})
|
||||
|
||||
Go SQlite3 Extensions
|
||||
|
||||
If you want to register Go functions as SQLite extension functions,
|
||||
call RegisterFunction from ConnectHook.
|
||||
|
||||
regex = func(re, s string) (bool, error) {
|
||||
return regexp.MatchString(re, s)
|
||||
}
|
||||
sql.Register("sqlite3_with_go_func",
|
||||
&sqlite3.SQLiteDriver{
|
||||
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
|
||||
return conn.RegisterFunc("regexp", regex, true)
|
||||
},
|
||||
})
|
||||
|
||||
See the documentation of RegisterFunc for more details.
|
||||
|
||||
*/
|
||||
package sqlite3
|
||||
|
242
Godeps/_workspace/src/github.com/mattn/go-sqlite3/error_test.go
generated
vendored
242
Godeps/_workspace/src/github.com/mattn/go-sqlite3/error_test.go
generated
vendored
@ -1,242 +0,0 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimpleError(t *testing.T) {
|
||||
e := ErrError.Error()
|
||||
if e != "SQL logic error or missing database" {
|
||||
t.Error("wrong error code:" + e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorruptDbErrors(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
f, err := os.Create(dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
f.Write([]byte{1, 2, 3, 4, 5})
|
||||
f.Close()
|
||||
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err == nil {
|
||||
_, err = db.Exec("drop table foo")
|
||||
}
|
||||
|
||||
sqliteErr := err.(Error)
|
||||
if sqliteErr.Code != ErrNotADB {
|
||||
t.Error("wrong error code for corrupted DB")
|
||||
}
|
||||
if err.Error() == "" {
|
||||
t.Error("wrong error string for corrupted DB")
|
||||
}
|
||||
db.Close()
|
||||
}
|
||||
|
||||
func TestSqlLogicErrors(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
const expectedErr = "table Foo already exists"
|
||||
_, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)")
|
||||
if err.Error() != expectedErr {
|
||||
t.Errorf("Unexpected error: %s, expected %s", err.Error(), expectedErr)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExtendedErrorCodes_ForeignKey(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3-err")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("PRAGMA foreign_keys=ON;")
|
||||
if err != nil {
|
||||
t.Errorf("PRAGMA foreign_keys=ON: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE Foo (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value INTEGER NOT NULL,
|
||||
ref INTEGER NULL REFERENCES Foo (id),
|
||||
UNIQUE(value)
|
||||
);`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (100, 100);")
|
||||
if err == nil {
|
||||
t.Error("No error!")
|
||||
} else {
|
||||
sqliteErr := err.(Error)
|
||||
if sqliteErr.Code != ErrConstraint {
|
||||
t.Errorf("Wrong basic error code: %d != %d",
|
||||
sqliteErr.Code, ErrConstraint)
|
||||
}
|
||||
if sqliteErr.ExtendedCode != ErrConstraintForeignKey {
|
||||
t.Errorf("Wrong extended error code: %d != %d",
|
||||
sqliteErr.ExtendedCode, ErrConstraintForeignKey)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExtendedErrorCodes_NotNull(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3-err")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("PRAGMA foreign_keys=ON;")
|
||||
if err != nil {
|
||||
t.Errorf("PRAGMA foreign_keys=ON: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE Foo (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value INTEGER NOT NULL,
|
||||
ref INTEGER NULL REFERENCES Foo (id),
|
||||
UNIQUE(value)
|
||||
);`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);")
|
||||
if err != nil {
|
||||
t.Fatalf("Creating first row: %v", err)
|
||||
}
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatalf("Retrieving last insert id: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO Foo (ref) VALUES (?);", id)
|
||||
if err == nil {
|
||||
t.Error("No error!")
|
||||
} else {
|
||||
sqliteErr := err.(Error)
|
||||
if sqliteErr.Code != ErrConstraint {
|
||||
t.Errorf("Wrong basic error code: %d != %d",
|
||||
sqliteErr.Code, ErrConstraint)
|
||||
}
|
||||
if sqliteErr.ExtendedCode != ErrConstraintNotNull {
|
||||
t.Errorf("Wrong extended error code: %d != %d",
|
||||
sqliteErr.ExtendedCode, ErrConstraintNotNull)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExtendedErrorCodes_Unique(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3-err")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("PRAGMA foreign_keys=ON;")
|
||||
if err != nil {
|
||||
t.Errorf("PRAGMA foreign_keys=ON: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE Foo (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value INTEGER NOT NULL,
|
||||
ref INTEGER NULL REFERENCES Foo (id),
|
||||
UNIQUE(value)
|
||||
);`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);")
|
||||
if err != nil {
|
||||
t.Fatalf("Creating first row: %v", err)
|
||||
}
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatalf("Retrieving last insert id: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (?, 100);", id)
|
||||
if err == nil {
|
||||
t.Error("No error!")
|
||||
} else {
|
||||
sqliteErr := err.(Error)
|
||||
if sqliteErr.Code != ErrConstraint {
|
||||
t.Errorf("Wrong basic error code: %d != %d",
|
||||
sqliteErr.Code, ErrConstraint)
|
||||
}
|
||||
if sqliteErr.ExtendedCode != ErrConstraintUnique {
|
||||
t.Errorf("Wrong extended error code: %d != %d",
|
||||
sqliteErr.ExtendedCode, ErrConstraintUnique)
|
||||
}
|
||||
extended := sqliteErr.Code.Extend(3).Error()
|
||||
expected := "constraint failed"
|
||||
if extended != expected {
|
||||
t.Errorf("Wrong basic error code: %q != %q",
|
||||
extended, expected)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
68891
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3-binding.c
generated
vendored
68891
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3-binding.c
generated
vendored
File diff suppressed because it is too large
Load Diff
2594
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3-binding.h
generated
vendored
2594
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3-binding.h
generated
vendored
File diff suppressed because it is too large
Load Diff
465
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3.go
generated
vendored
465
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3.go
generated
vendored
@ -8,8 +8,12 @@ package sqlite3
|
||||
/*
|
||||
#cgo CFLAGS: -std=gnu99
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
|
||||
#ifndef USE_LIBSQLITE3
|
||||
#include <sqlite3-binding.h>
|
||||
#else
|
||||
#include <sqlite3.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -25,6 +29,10 @@ package sqlite3
|
||||
# define SQLITE_OPEN_FULLMUTEX 0
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_DETERMINISTIC
|
||||
# define SQLITE_DETERMINISTIC 0
|
||||
#endif
|
||||
|
||||
static int
|
||||
_sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs) {
|
||||
#ifdef SQLITE_OPEN_URI
|
||||
@ -48,24 +56,49 @@ _sqlite3_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) {
|
||||
#include <stdint.h>
|
||||
|
||||
static int
|
||||
_sqlite3_exec(sqlite3* db, const char* pcmd, long* rowid, long* changes)
|
||||
_sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* changes)
|
||||
{
|
||||
int rv = sqlite3_exec(db, pcmd, 0, 0, 0);
|
||||
*rowid = (long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long) sqlite3_changes(db);
|
||||
*rowid = (long long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long long) sqlite3_changes(db);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
_sqlite3_step(sqlite3_stmt* stmt, long* rowid, long* changes)
|
||||
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
||||
{
|
||||
int rv = sqlite3_step(stmt);
|
||||
sqlite3* db = sqlite3_db_handle(stmt);
|
||||
*rowid = (long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long) sqlite3_changes(db);
|
||||
*rowid = (long long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long long) sqlite3_changes(db);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void _sqlite3_result_text(sqlite3_context* ctx, const char* s) {
|
||||
sqlite3_result_text(ctx, s, -1, &free);
|
||||
}
|
||||
|
||||
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l) {
|
||||
sqlite3_result_blob(ctx, b, l, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
||||
int _sqlite3_create_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
uintptr_t pApp,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*)
|
||||
) {
|
||||
return sqlite3_create_function(db, zFunctionName, nArg, eTextRep, (void*) pApp, xFunc, xStep, xFinal);
|
||||
}
|
||||
|
||||
void callbackTrampoline(sqlite3_context*, int, sqlite3_value**);
|
||||
void stepTrampoline(sqlite3_context*, int, sqlite3_value**);
|
||||
void doneTrampoline(sqlite3_context*);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
@ -75,6 +108,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -87,6 +121,10 @@ import (
|
||||
// into the database. When parsing a string from a timestamp or
|
||||
// datetime column, the formats are tried in order.
|
||||
var SQLiteTimestampFormats = []string{
|
||||
// By default, store timestamps with whatever timezone they come with.
|
||||
// When parsed, they will be returned with the same timezone.
|
||||
"2006-01-02 15:04:05.999999999-07:00",
|
||||
"2006-01-02T15:04:05.999999999-07:00",
|
||||
"2006-01-02 15:04:05.999999999",
|
||||
"2006-01-02T15:04:05.999999999",
|
||||
"2006-01-02 15:04:05",
|
||||
@ -94,14 +132,13 @@ var SQLiteTimestampFormats = []string{
|
||||
"2006-01-02 15:04",
|
||||
"2006-01-02T15:04",
|
||||
"2006-01-02",
|
||||
"2006-01-02 15:04:05-07:00",
|
||||
}
|
||||
|
||||
func init() {
|
||||
sql.Register("sqlite3", &SQLiteDriver{})
|
||||
}
|
||||
|
||||
// Return SQLite library Version information.
|
||||
// Version returns SQLite library version information.
|
||||
func Version() (libVersion string, libVersionNumber int, sourceId string) {
|
||||
libVersion = C.GoString(C.sqlite3_libversion())
|
||||
libVersionNumber = int(C.sqlite3_libversion_number())
|
||||
@ -117,8 +154,11 @@ type SQLiteDriver struct {
|
||||
|
||||
// Conn struct.
|
||||
type SQLiteConn struct {
|
||||
db *C.sqlite3
|
||||
loc *time.Location
|
||||
db *C.sqlite3
|
||||
loc *time.Location
|
||||
txlock string
|
||||
funcs []*functionInfo
|
||||
aggregators []*aggInfo
|
||||
}
|
||||
|
||||
// Tx struct.
|
||||
@ -152,6 +192,107 @@ type SQLiteRows struct {
|
||||
cls bool
|
||||
}
|
||||
|
||||
type functionInfo struct {
|
||||
f reflect.Value
|
||||
argConverters []callbackArgConverter
|
||||
variadicConverter callbackArgConverter
|
||||
retConverter callbackRetConverter
|
||||
}
|
||||
|
||||
func (fi *functionInfo) Call(ctx *C.sqlite3_context, argv []*C.sqlite3_value) {
|
||||
args, err := callbackConvertArgs(argv, fi.argConverters, fi.variadicConverter)
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
ret := fi.f.Call(args)
|
||||
|
||||
if len(ret) == 2 && ret[1].Interface() != nil {
|
||||
callbackError(ctx, ret[1].Interface().(error))
|
||||
return
|
||||
}
|
||||
|
||||
err = fi.retConverter(ctx, ret[0])
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type aggInfo struct {
|
||||
constructor reflect.Value
|
||||
|
||||
// Active aggregator objects for aggregations in flight. The
|
||||
// aggregators are indexed by a counter stored in the aggregation
|
||||
// user data space provided by sqlite.
|
||||
active map[int64]reflect.Value
|
||||
next int64
|
||||
|
||||
stepArgConverters []callbackArgConverter
|
||||
stepVariadicConverter callbackArgConverter
|
||||
|
||||
doneRetConverter callbackRetConverter
|
||||
}
|
||||
|
||||
func (ai *aggInfo) agg(ctx *C.sqlite3_context) (int64, reflect.Value, error) {
|
||||
aggIdx := (*int64)(C.sqlite3_aggregate_context(ctx, C.int(8)))
|
||||
if *aggIdx == 0 {
|
||||
*aggIdx = ai.next
|
||||
ret := ai.constructor.Call(nil)
|
||||
if len(ret) == 2 && ret[1].Interface() != nil {
|
||||
return 0, reflect.Value{}, ret[1].Interface().(error)
|
||||
}
|
||||
if ret[0].IsNil() {
|
||||
return 0, reflect.Value{}, errors.New("aggregator constructor returned nil state")
|
||||
}
|
||||
ai.next++
|
||||
ai.active[*aggIdx] = ret[0]
|
||||
}
|
||||
return *aggIdx, ai.active[*aggIdx], nil
|
||||
}
|
||||
|
||||
func (ai *aggInfo) Step(ctx *C.sqlite3_context, argv []*C.sqlite3_value) {
|
||||
_, agg, err := ai.agg(ctx)
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
args, err := callbackConvertArgs(argv, ai.stepArgConverters, ai.stepVariadicConverter)
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
ret := agg.MethodByName("Step").Call(args)
|
||||
if len(ret) == 1 && ret[0].Interface() != nil {
|
||||
callbackError(ctx, ret[0].Interface().(error))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (ai *aggInfo) Done(ctx *C.sqlite3_context) {
|
||||
idx, agg, err := ai.agg(ctx)
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
defer func() { delete(ai.active, idx) }()
|
||||
|
||||
ret := agg.MethodByName("Done").Call(nil)
|
||||
if len(ret) == 2 && ret[1].Interface() != nil {
|
||||
callbackError(ctx, ret[1].Interface().(error))
|
||||
return
|
||||
}
|
||||
|
||||
err = ai.doneRetConverter(ctx, ret[0])
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Commit transaction.
|
||||
func (tx *SQLiteTx) Commit() error {
|
||||
_, err := tx.c.exec("COMMIT")
|
||||
@ -164,6 +305,208 @@ func (tx *SQLiteTx) Rollback() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// RegisterFunc makes a Go function available as a SQLite function.
|
||||
//
|
||||
// The Go function can have arguments of the following types: any
|
||||
// numeric type except complex, bool, []byte, string and
|
||||
// interface{}. interface{} arguments are given the direct translation
|
||||
// of the SQLite data type: int64 for INTEGER, float64 for FLOAT,
|
||||
// []byte for BLOB, string for TEXT.
|
||||
//
|
||||
// The function can additionally be variadic, as long as the type of
|
||||
// the variadic argument is one of the above.
|
||||
//
|
||||
// If pure is true. SQLite will assume that the function's return
|
||||
// value depends only on its inputs, and make more aggressive
|
||||
// optimizations in its queries.
|
||||
//
|
||||
// See _example/go_custom_funcs for a detailed example.
|
||||
func (c *SQLiteConn) RegisterFunc(name string, impl interface{}, pure bool) error {
|
||||
var fi functionInfo
|
||||
fi.f = reflect.ValueOf(impl)
|
||||
t := fi.f.Type()
|
||||
if t.Kind() != reflect.Func {
|
||||
return errors.New("Non-function passed to RegisterFunc")
|
||||
}
|
||||
if t.NumOut() != 1 && t.NumOut() != 2 {
|
||||
return errors.New("SQLite functions must return 1 or 2 values")
|
||||
}
|
||||
if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
return errors.New("Second return value of SQLite function must be error")
|
||||
}
|
||||
|
||||
numArgs := t.NumIn()
|
||||
if t.IsVariadic() {
|
||||
numArgs--
|
||||
}
|
||||
|
||||
for i := 0; i < numArgs; i++ {
|
||||
conv, err := callbackArg(t.In(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fi.argConverters = append(fi.argConverters, conv)
|
||||
}
|
||||
|
||||
if t.IsVariadic() {
|
||||
conv, err := callbackArg(t.In(numArgs).Elem())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fi.variadicConverter = conv
|
||||
// Pass -1 to sqlite so that it allows any number of
|
||||
// arguments. The call helper verifies that the minimum number
|
||||
// of arguments is present for variadic functions.
|
||||
numArgs = -1
|
||||
}
|
||||
|
||||
conv, err := callbackRet(t.Out(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fi.retConverter = conv
|
||||
|
||||
// fi must outlast the database connection, or we'll have dangling pointers.
|
||||
c.funcs = append(c.funcs, &fi)
|
||||
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
opts := C.SQLITE_UTF8
|
||||
if pure {
|
||||
opts |= C.SQLITE_DETERMINISTIC
|
||||
}
|
||||
rv := C._sqlite3_create_function(c.db, cname, C.int(numArgs), C.int(opts), C.uintptr_t(newHandle(c, &fi)), (*[0]byte)(unsafe.Pointer(C.callbackTrampoline)), nil, nil)
|
||||
if rv != C.SQLITE_OK {
|
||||
return c.lastError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterAggregator makes a Go type available as a SQLite aggregation function.
|
||||
//
|
||||
// Because aggregation is incremental, it's implemented in Go with a
|
||||
// type that has 2 methods: func Step(values) accumulates one row of
|
||||
// data into the accumulator, and func Done() ret finalizes and
|
||||
// returns the aggregate value. "values" and "ret" may be any type
|
||||
// supported by RegisterFunc.
|
||||
//
|
||||
// RegisterAggregator takes as implementation a constructor function
|
||||
// that constructs an instance of the aggregator type each time an
|
||||
// aggregation begins. The constructor must return a pointer to a
|
||||
// type, or an interface that implements Step() and Done().
|
||||
//
|
||||
// The constructor function and the Step/Done methods may optionally
|
||||
// return an error in addition to their other return values.
|
||||
//
|
||||
// See _example/go_custom_funcs for a detailed example.
|
||||
func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool) error {
|
||||
var ai aggInfo
|
||||
ai.constructor = reflect.ValueOf(impl)
|
||||
t := ai.constructor.Type()
|
||||
if t.Kind() != reflect.Func {
|
||||
return errors.New("non-function passed to RegisterAggregator")
|
||||
}
|
||||
if t.NumOut() != 1 && t.NumOut() != 2 {
|
||||
return errors.New("SQLite aggregator constructors must return 1 or 2 values")
|
||||
}
|
||||
if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
return errors.New("Second return value of SQLite function must be error")
|
||||
}
|
||||
if t.NumIn() != 0 {
|
||||
return errors.New("SQLite aggregator constructors must not have arguments")
|
||||
}
|
||||
|
||||
agg := t.Out(0)
|
||||
switch agg.Kind() {
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
default:
|
||||
return errors.New("SQlite aggregator constructor must return a pointer object")
|
||||
}
|
||||
stepFn, found := agg.MethodByName("Step")
|
||||
if !found {
|
||||
return errors.New("SQlite aggregator doesn't have a Step() function")
|
||||
}
|
||||
step := stepFn.Type
|
||||
if step.NumOut() != 0 && step.NumOut() != 1 {
|
||||
return errors.New("SQlite aggregator Step() function must return 0 or 1 values")
|
||||
}
|
||||
if step.NumOut() == 1 && !step.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
return errors.New("type of SQlite aggregator Step() return value must be error")
|
||||
}
|
||||
|
||||
stepNArgs := step.NumIn()
|
||||
start := 0
|
||||
if agg.Kind() == reflect.Ptr {
|
||||
// Skip over the method receiver
|
||||
stepNArgs--
|
||||
start++
|
||||
}
|
||||
if step.IsVariadic() {
|
||||
stepNArgs--
|
||||
}
|
||||
for i := start; i < start+stepNArgs; i++ {
|
||||
conv, err := callbackArg(step.In(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ai.stepArgConverters = append(ai.stepArgConverters, conv)
|
||||
}
|
||||
if step.IsVariadic() {
|
||||
conv, err := callbackArg(t.In(start + stepNArgs).Elem())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ai.stepVariadicConverter = conv
|
||||
// Pass -1 to sqlite so that it allows any number of
|
||||
// arguments. The call helper verifies that the minimum number
|
||||
// of arguments is present for variadic functions.
|
||||
stepNArgs = -1
|
||||
}
|
||||
|
||||
doneFn, found := agg.MethodByName("Done")
|
||||
if !found {
|
||||
return errors.New("SQlite aggregator doesn't have a Done() function")
|
||||
}
|
||||
done := doneFn.Type
|
||||
doneNArgs := done.NumIn()
|
||||
if agg.Kind() == reflect.Ptr {
|
||||
// Skip over the method receiver
|
||||
doneNArgs--
|
||||
}
|
||||
if doneNArgs != 0 {
|
||||
return errors.New("SQlite aggregator Done() function must have no arguments")
|
||||
}
|
||||
if done.NumOut() != 1 && done.NumOut() != 2 {
|
||||
return errors.New("SQLite aggregator Done() function must return 1 or 2 values")
|
||||
}
|
||||
if done.NumOut() == 2 && !done.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
return errors.New("second return value of SQLite aggregator Done() function must be error")
|
||||
}
|
||||
|
||||
conv, err := callbackRet(done.Out(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ai.doneRetConverter = conv
|
||||
ai.active = make(map[int64]reflect.Value)
|
||||
ai.next = 1
|
||||
|
||||
// ai must outlast the database connection, or we'll have dangling pointers.
|
||||
c.aggregators = append(c.aggregators, &ai)
|
||||
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
opts := C.SQLITE_UTF8
|
||||
if pure {
|
||||
opts |= C.SQLITE_DETERMINISTIC
|
||||
}
|
||||
rv := C._sqlite3_create_function(c.db, cname, C.int(stepNArgs), C.int(opts), C.uintptr_t(newHandle(c, &ai)), nil, (*[0]byte)(unsafe.Pointer(C.stepTrampoline)), (*[0]byte)(unsafe.Pointer(C.doneTrampoline)))
|
||||
if rv != C.SQLITE_OK {
|
||||
return c.lastError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AutoCommit return which currently auto commit or not.
|
||||
func (c *SQLiteConn) AutoCommit() bool {
|
||||
return int(C.sqlite3_get_autocommit(c.db)) != 0
|
||||
@ -242,7 +585,7 @@ func (c *SQLiteConn) exec(cmd string) (driver.Result, error) {
|
||||
pcmd := C.CString(cmd)
|
||||
defer C.free(unsafe.Pointer(pcmd))
|
||||
|
||||
var rowid, changes C.long
|
||||
var rowid, changes C.longlong
|
||||
rv := C._sqlite3_exec(c.db, pcmd, &rowid, &changes)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, c.lastError()
|
||||
@ -252,7 +595,7 @@ func (c *SQLiteConn) exec(cmd string) (driver.Result, error) {
|
||||
|
||||
// Begin transaction.
|
||||
func (c *SQLiteConn) Begin() (driver.Tx, error) {
|
||||
if _, err := c.exec("BEGIN"); err != nil {
|
||||
if _, err := c.exec(c.txlock); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SQLiteTx{c}, nil
|
||||
@ -263,22 +606,26 @@ func errorString(err Error) string {
|
||||
}
|
||||
|
||||
// Open database and return a new connection.
|
||||
// You can specify DSN string with URI filename.
|
||||
// You can specify a DSN string using a URI as the filename.
|
||||
// test.db
|
||||
// file:test.db?cache=shared&mode=memory
|
||||
// :memory:
|
||||
// file::memory:
|
||||
// go-sqlite handle especially query parameters.
|
||||
// go-sqlite3 adds the following query parameters to those used by SQLite:
|
||||
// _loc=XXX
|
||||
// Specify location of time format. It's possible to specify "auto".
|
||||
// _busy_timeout=XXX
|
||||
// Specify value for sqlite3_busy_timeout.
|
||||
// _txlock=XXX
|
||||
// Specify locking behavior for transactions. XXX can be "immediate",
|
||||
// "deferred", "exclusive".
|
||||
func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
if C.sqlite3_threadsafe() == 0 {
|
||||
return nil, errors.New("sqlite library was not compiled for thread-safe operation")
|
||||
}
|
||||
|
||||
var loc *time.Location
|
||||
txlock := "BEGIN"
|
||||
busy_timeout := 5000
|
||||
pos := strings.IndexRune(dsn, '?')
|
||||
if pos >= 1 {
|
||||
@ -308,6 +655,20 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
busy_timeout = int(iv)
|
||||
}
|
||||
|
||||
// _txlock
|
||||
if val := params.Get("_txlock"); val != "" {
|
||||
switch val {
|
||||
case "immediate":
|
||||
txlock = "BEGIN IMMEDIATE"
|
||||
case "exclusive":
|
||||
txlock = "BEGIN EXCLUSIVE"
|
||||
case "deferred":
|
||||
txlock = "BEGIN"
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _txlock: %v", val)
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(dsn, "file:") {
|
||||
dsn = dsn[:pos]
|
||||
}
|
||||
@ -333,26 +694,11 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
return nil, Error{Code: ErrNo(rv)}
|
||||
}
|
||||
|
||||
conn := &SQLiteConn{db: db, loc: loc}
|
||||
conn := &SQLiteConn{db: db, loc: loc, txlock: txlock}
|
||||
|
||||
if len(d.Extensions) > 0 {
|
||||
rv = C.sqlite3_enable_load_extension(db, 1)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(db)))
|
||||
}
|
||||
|
||||
for _, extension := range d.Extensions {
|
||||
cext := C.CString(extension)
|
||||
defer C.free(unsafe.Pointer(cext))
|
||||
rv = C.sqlite3_load_extension(db, cext, nil, nil)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(db)))
|
||||
}
|
||||
}
|
||||
|
||||
rv = C.sqlite3_enable_load_extension(db, 0)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(db)))
|
||||
if err := conn.loadExtensions(d.Extensions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,6 +713,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
|
||||
// Close the connection.
|
||||
func (c *SQLiteConn) Close() error {
|
||||
deleteHandles(c)
|
||||
rv := C.sqlite3_close_v2(c.db)
|
||||
if rv != C.SQLITE_OK {
|
||||
return c.lastError()
|
||||
@ -376,7 +723,7 @@ func (c *SQLiteConn) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prepare query string. Return a new statement.
|
||||
// Prepare the query string. Return a new statement.
|
||||
func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) {
|
||||
pquery := C.CString(query)
|
||||
defer C.free(unsafe.Pointer(pquery))
|
||||
@ -476,13 +823,13 @@ func (s *SQLiteStmt) bind(args []driver.Value) error {
|
||||
case float64:
|
||||
rv = C.sqlite3_bind_double(s.s, n, C.double(v))
|
||||
case []byte:
|
||||
var p *byte
|
||||
if len(v) > 0 {
|
||||
p = &v[0]
|
||||
if len(v) == 0 {
|
||||
rv = C._sqlite3_bind_blob(s.s, n, nil, 0)
|
||||
} else {
|
||||
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(&v[0]), C.int(len(v)))
|
||||
}
|
||||
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(p), C.int(len(v)))
|
||||
case time.Time:
|
||||
b := []byte(v.UTC().Format(SQLiteTimestampFormats[0]))
|
||||
b := []byte(v.Format(SQLiteTimestampFormats[0]))
|
||||
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
|
||||
}
|
||||
if rv != C.SQLITE_OK {
|
||||
@ -517,7 +864,7 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) {
|
||||
C.sqlite3_clear_bindings(s.s)
|
||||
return nil, err
|
||||
}
|
||||
var rowid, changes C.long
|
||||
var rowid, changes C.longlong
|
||||
rv := C._sqlite3_step(s.s, &rowid, &changes)
|
||||
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
|
||||
err := s.c.lastError()
|
||||
@ -554,6 +901,17 @@ func (rc *SQLiteRows) Columns() []string {
|
||||
return rc.cols
|
||||
}
|
||||
|
||||
// Return column types.
|
||||
func (rc *SQLiteRows) DeclTypes() []string {
|
||||
if rc.decltype == nil {
|
||||
rc.decltype = make([]string, rc.nc)
|
||||
for i := 0; i < rc.nc; i++ {
|
||||
rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))))
|
||||
}
|
||||
}
|
||||
return rc.decltype
|
||||
}
|
||||
|
||||
// Move cursor to next.
|
||||
func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
rv := C.sqlite3_step(rc.s.s)
|
||||
@ -568,12 +926,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if rc.decltype == nil {
|
||||
rc.decltype = make([]string, rc.nc)
|
||||
for i := 0; i < rc.nc; i++ {
|
||||
rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))))
|
||||
}
|
||||
}
|
||||
rc.DeclTypes()
|
||||
|
||||
for i := range dest {
|
||||
switch C.sqlite3_column_type(rc.s.s, C.int(i)) {
|
||||
@ -581,18 +934,15 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
val := int64(C.sqlite3_column_int64(rc.s.s, C.int(i)))
|
||||
switch rc.decltype[i] {
|
||||
case "timestamp", "datetime", "date":
|
||||
unixTimestamp := strconv.FormatInt(val, 10)
|
||||
var t time.Time
|
||||
if len(unixTimestamp) == 13 {
|
||||
duration, err := time.ParseDuration(unixTimestamp + "ms")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing %s value %d, %s", rc.decltype[i], val, err)
|
||||
}
|
||||
epoch := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
t = epoch.Add(duration)
|
||||
// Assume a millisecond unix timestamp if it's 13 digits -- too
|
||||
// large to be a reasonable timestamp in seconds.
|
||||
if val > 1e12 || val < -1e12 {
|
||||
val *= int64(time.Millisecond) // convert ms to nsec
|
||||
} else {
|
||||
t = time.Unix(val, 0)
|
||||
val *= int64(time.Second) // convert sec to nsec
|
||||
}
|
||||
t = time.Unix(0, val).UTC()
|
||||
if rc.s.c.loc != nil {
|
||||
t = t.In(rc.s.c.loc)
|
||||
}
|
||||
@ -624,11 +974,14 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
case C.SQLITE_TEXT:
|
||||
var err error
|
||||
var timeVal time.Time
|
||||
s := C.GoString((*C.char)(unsafe.Pointer(C.sqlite3_column_text(rc.s.s, C.int(i)))))
|
||||
|
||||
n := int(C.sqlite3_column_bytes(rc.s.s, C.int(i)))
|
||||
s := C.GoStringN((*C.char)(unsafe.Pointer(C.sqlite3_column_text(rc.s.s, C.int(i)))), C.int(n))
|
||||
|
||||
switch rc.decltype[i] {
|
||||
case "timestamp", "datetime", "date":
|
||||
var t time.Time
|
||||
s = strings.TrimSuffix(s, "Z")
|
||||
for _, format := range SQLiteTimestampFormats {
|
||||
if timeVal, err = time.ParseInLocation(format, s, time.UTC); err == nil {
|
||||
t = timeVal
|
||||
|
83
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_fts3_test.go
generated
vendored
83
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_fts3_test.go
generated
vendored
@ -1,83 +0,0 @@
|
||||
// Copyright (C) 2015 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFTS3(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE foo")
|
||||
_, err = db.Exec("CREATE VIRTUAL TABLE foo USING fts3(id INTEGER PRIMARY KEY, value TEXT)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 1, `今日の 晩御飯は 天麩羅よ`)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert value:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 2, `今日は いい 天気だ`)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert value:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, value FROM foo WHERE value MATCH '今日* 天*'")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var value string
|
||||
|
||||
if err := rows.Scan(&id, &value); err != nil {
|
||||
t.Error("Unable to scan results:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if id == 1 && value != `今日の 晩御飯は 天麩羅よ` {
|
||||
t.Error("Value for id 1 should be `今日の 晩御飯は 天麩羅よ`, but:", value)
|
||||
} else if id == 2 && value != `今日は いい 天気だ` {
|
||||
t.Error("Value for id 2 should be `今日は いい 天気だ`, but:", value)
|
||||
}
|
||||
}
|
||||
|
||||
rows, err = db.Query("SELECT value FROM foo WHERE value MATCH '今日* 天麩羅*'")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var value string
|
||||
if !rows.Next() {
|
||||
t.Fatal("Result should be only one")
|
||||
}
|
||||
|
||||
if err := rows.Scan(&value); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
|
||||
if value != `今日の 晩御飯は 天麩羅よ` {
|
||||
t.Fatal("Value should be `今日の 晩御飯は 天麩羅よ`, but:", value)
|
||||
}
|
||||
|
||||
if rows.Next() {
|
||||
t.Fatal("Result should be only one")
|
||||
}
|
||||
}
|
13
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_fts5.go
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_fts5.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build fts5
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_FTS5
|
||||
#cgo LDFLAGS: -lm
|
||||
*/
|
||||
import "C"
|
13
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_icu.go
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_icu.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build icu
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -licuuc -licui18n
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_ICU
|
||||
*/
|
||||
import "C"
|
12
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_json1.go
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_json1.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build json1
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_JSON1
|
||||
*/
|
||||
import "C"
|
14
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
generated
vendored
Normal file
14
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build libsqlite3
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DUSE_LIBSQLITE3
|
||||
#cgo linux LDFLAGS: -lsqlite3
|
||||
#cgo darwin LDFLAGS: -L/usr/local/opt/sqlite/lib -lsqlite3
|
||||
*/
|
||||
import "C"
|
63
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
generated
vendored
Normal file
63
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build !sqlite_omit_load_extension
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#include <sqlite3-binding.h>
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (c *SQLiteConn) loadExtensions(extensions []string) error {
|
||||
rv := C.sqlite3_enable_load_extension(c.db, 1)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
for _, extension := range extensions {
|
||||
cext := C.CString(extension)
|
||||
defer C.free(unsafe.Pointer(cext))
|
||||
rv = C.sqlite3_load_extension(c.db, cext, nil, nil)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
}
|
||||
|
||||
rv = C.sqlite3_enable_load_extension(c.db, 0)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
|
||||
rv := C.sqlite3_enable_load_extension(c.db, 1)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
clib := C.CString(lib)
|
||||
defer C.free(unsafe.Pointer(clib))
|
||||
centry := C.CString(entry)
|
||||
defer C.free(unsafe.Pointer(centry))
|
||||
|
||||
rv = C.sqlite3_load_extension(c.db, clib, centry, nil)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
rv = C.sqlite3_enable_load_extension(c.db, 0)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
23
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_omit_load_extension.go
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_omit_load_extension.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build sqlite_omit_load_extension
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
func (c *SQLiteConn) loadExtensions(extensions []string) error {
|
||||
return errors.New("Extensions have been disabled for static builds")
|
||||
}
|
||||
|
||||
func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
|
||||
return errors.New("Extensions have been disabled for static builds")
|
||||
}
|
1
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_other.go
generated
vendored
1
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_other.go
generated
vendored
@ -9,6 +9,5 @@ package sqlite3
|
||||
/*
|
||||
#cgo CFLAGS: -I.
|
||||
#cgo linux LDFLAGS: -ldl
|
||||
#cgo LDFLAGS: -lpthread
|
||||
*/
|
||||
import "C"
|
||||
|
947
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_test.go
generated
vendored
947
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_test.go
generated
vendored
@ -1,947 +0,0 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-sqlite3/sqlite3_test"
|
||||
)
|
||||
|
||||
func TempFilename() string {
|
||||
randBytes := make([]byte, 16)
|
||||
rand.Read(randBytes)
|
||||
return filepath.Join(os.TempDir(), "foo"+hex.EncodeToString(randBytes)+".db")
|
||||
}
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
if stat, err := os.Stat(tempFilename); err != nil || stat.IsDir() {
|
||||
t.Error("Failed to create ./foo.db")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
stmt, err := db.Prepare("select id from foo where id = ?")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to select records:", err)
|
||||
}
|
||||
|
||||
db.Close()
|
||||
_, err = stmt.Exec(1)
|
||||
if err == nil {
|
||||
t.Fatal("Failed to operate closed statement")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("insert into foo(id) values(123)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert record:", err)
|
||||
}
|
||||
affected, _ := res.RowsAffected()
|
||||
if affected != 1 {
|
||||
t.Fatalf("Expected %d for affected rows, but %d:", 1, affected)
|
||||
}
|
||||
|
||||
rows, err := db.Query("select id from foo")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to select records:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
rows.Next()
|
||||
|
||||
var result int
|
||||
rows.Scan(&result)
|
||||
if result != 123 {
|
||||
t.Errorf("Fetched %q; expected %q", 123, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("insert into foo(id) values(123)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert record:", err)
|
||||
}
|
||||
expected, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get LastInsertId:", err)
|
||||
}
|
||||
affected, _ := res.RowsAffected()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get RowsAffected:", err)
|
||||
}
|
||||
if affected != 1 {
|
||||
t.Fatalf("Expected %d for affected rows, but %d:", 1, affected)
|
||||
}
|
||||
|
||||
res, err = db.Exec("update foo set id = 234")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to update record:", err)
|
||||
}
|
||||
lastId, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get LastInsertId:", err)
|
||||
}
|
||||
if expected != lastId {
|
||||
t.Errorf("Expected %q for last Id, but %q:", expected, lastId)
|
||||
}
|
||||
affected, _ = res.RowsAffected()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get RowsAffected:", err)
|
||||
}
|
||||
if affected != 1 {
|
||||
t.Fatalf("Expected %d for affected rows, but %d:", 1, affected)
|
||||
}
|
||||
|
||||
rows, err := db.Query("select id from foo")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to select records:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
rows.Next()
|
||||
|
||||
var result int
|
||||
rows.Scan(&result)
|
||||
if result != 234 {
|
||||
t.Errorf("Fetched %q; expected %q", 234, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("insert into foo(id) values(123)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert record:", err)
|
||||
}
|
||||
expected, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get LastInsertId:", err)
|
||||
}
|
||||
affected, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get RowsAffected:", err)
|
||||
}
|
||||
if affected != 1 {
|
||||
t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected)
|
||||
}
|
||||
|
||||
res, err = db.Exec("delete from foo where id = 123")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to delete record:", err)
|
||||
}
|
||||
lastId, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get LastInsertId:", err)
|
||||
}
|
||||
if expected != lastId {
|
||||
t.Errorf("Expected %q for last Id, but %q:", expected, lastId)
|
||||
}
|
||||
affected, err = res.RowsAffected()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get RowsAffected:", err)
|
||||
}
|
||||
if affected != 1 {
|
||||
t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected)
|
||||
}
|
||||
|
||||
rows, err := db.Query("select id from foo")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to select records:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
t.Error("Fetched row but expected not rows")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBooleanRoundtrip(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE foo")
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER, value BOOL)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id, value) VALUES(1, ?)", true)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert true value:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id, value) VALUES(2, ?)", false)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert false value:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, value FROM foo")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var value bool
|
||||
|
||||
if err := rows.Scan(&id, &value); err != nil {
|
||||
t.Error("Unable to scan results:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if id == 1 && !value {
|
||||
t.Error("Value for id 1 should be true, not false")
|
||||
|
||||
} else if id == 2 && value {
|
||||
t.Error("Value for id 2 should be false, not true")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE foo")
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER, ts timeSTAMP, dt DATETIME)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
|
||||
timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC)
|
||||
timestamp3 := time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC)
|
||||
tests := []struct {
|
||||
value interface{}
|
||||
expected time.Time
|
||||
}{
|
||||
{"nonsense", time.Time{}},
|
||||
{"0000-00-00 00:00:00", time.Time{}},
|
||||
{timestamp1, timestamp1},
|
||||
{timestamp1.Unix(), timestamp1},
|
||||
{timestamp1.UnixNano() / int64(time.Millisecond), timestamp1},
|
||||
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1},
|
||||
{timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1},
|
||||
{timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1},
|
||||
{timestamp1.Format("2006-01-02 15:04:05"), timestamp1},
|
||||
{timestamp1.Format("2006-01-02T15:04:05"), timestamp1},
|
||||
{timestamp2, timestamp2},
|
||||
{"2006-01-02 15:04:05.123456789", timestamp2},
|
||||
{"2006-01-02T15:04:05.123456789", timestamp2},
|
||||
{"2012-11-04", timestamp3},
|
||||
{"2012-11-04 00:00", timestamp3},
|
||||
{"2012-11-04 00:00:00", timestamp3},
|
||||
{"2012-11-04 00:00:00.000", timestamp3},
|
||||
{"2012-11-04T00:00", timestamp3},
|
||||
{"2012-11-04T00:00:00", timestamp3},
|
||||
{"2012-11-04T00:00:00.000", timestamp3},
|
||||
}
|
||||
for i := range tests {
|
||||
_, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert timestamp:", err)
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, ts, dt FROM foo ORDER BY id ASC")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
seen := 0
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var ts, dt time.Time
|
||||
|
||||
if err := rows.Scan(&id, &ts, &dt); err != nil {
|
||||
t.Error("Unable to scan results:", err)
|
||||
continue
|
||||
}
|
||||
if id < 0 || id >= len(tests) {
|
||||
t.Error("Bad row id: ", id)
|
||||
continue
|
||||
}
|
||||
seen++
|
||||
if !tests[id].expected.Equal(ts) {
|
||||
t.Errorf("Timestamp value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt)
|
||||
}
|
||||
if !tests[id].expected.Equal(dt) {
|
||||
t.Errorf("Datetime value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt)
|
||||
}
|
||||
}
|
||||
|
||||
if seen != len(tests) {
|
||||
t.Errorf("Expected to see %d rows", len(tests))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolean(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER, fbool BOOLEAN)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
bool1 := true
|
||||
_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(1, ?)", bool1)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert boolean:", err)
|
||||
}
|
||||
|
||||
bool2 := false
|
||||
_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(2, ?)", bool2)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert boolean:", err)
|
||||
}
|
||||
|
||||
bool3 := "nonsense"
|
||||
_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(3, ?)", bool3)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert nonsense:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, fbool FROM foo where fbool = ?", bool1)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
counter := 0
|
||||
|
||||
var id int
|
||||
var fbool bool
|
||||
|
||||
for rows.Next() {
|
||||
if err := rows.Scan(&id, &fbool); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
counter++
|
||||
}
|
||||
|
||||
if counter != 1 {
|
||||
t.Fatalf("Expected 1 row but %v", counter)
|
||||
}
|
||||
|
||||
if id != 1 && fbool != true {
|
||||
t.Fatalf("Value for id 1 should be %v, not %v", bool1, fbool)
|
||||
}
|
||||
|
||||
rows, err = db.Query("SELECT id, fbool FROM foo where fbool = ?", bool2)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
counter = 0
|
||||
|
||||
for rows.Next() {
|
||||
if err := rows.Scan(&id, &fbool); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
counter++
|
||||
}
|
||||
|
||||
if counter != 1 {
|
||||
t.Fatalf("Expected 1 row but %v", counter)
|
||||
}
|
||||
|
||||
if id != 2 && fbool != false {
|
||||
t.Fatalf("Value for id 2 should be %v, not %v", bool2, fbool)
|
||||
}
|
||||
|
||||
// make sure "nonsense" triggered an error
|
||||
rows, err = db.Query("SELECT id, fbool FROM foo where id=?;", 3)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
rows.Next()
|
||||
err = rows.Scan(&id, &fbool)
|
||||
if err == nil {
|
||||
t.Error("Expected error from \"nonsense\" bool")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat32(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id) VALUES(null)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert null:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id FROM foo")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
if !rows.Next() {
|
||||
t.Fatal("Unable to query results:", err)
|
||||
}
|
||||
|
||||
var id interface{}
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
if id != nil {
|
||||
t.Error("Expected nil but not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNull(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query("SELECT 3.141592")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
if !rows.Next() {
|
||||
t.Fatal("Unable to query results:", err)
|
||||
}
|
||||
|
||||
var v interface{}
|
||||
if err := rows.Scan(&v); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
f, ok := v.(float64)
|
||||
if !ok {
|
||||
t.Error("Expected float but not")
|
||||
}
|
||||
if f != 3.141592 {
|
||||
t.Error("Expected 3.141592 but not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransaction(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to begin transaction:", err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec("INSERT INTO foo(id) VALUES(1)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert null:", err)
|
||||
}
|
||||
|
||||
rows, err := tx.Query("SELECT id from foo")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
err = tx.Rollback()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to rollback transaction:", err)
|
||||
}
|
||||
|
||||
if rows.Next() {
|
||||
t.Fatal("Unable to query results:", err)
|
||||
}
|
||||
|
||||
tx, err = db.Begin()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to begin transaction:", err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec("INSERT INTO foo(id) VALUES(1)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert null:", err)
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to commit transaction:", err)
|
||||
}
|
||||
|
||||
rows, err = tx.Query("SELECT id from foo")
|
||||
if err == nil {
|
||||
t.Fatal("Expected failure to query")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWAL(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
if _, err = db.Exec("PRAGMA journal_mode=WAL;"); err != nil {
|
||||
t.Fatal("Failed to Exec PRAGMA journal_mode:", err)
|
||||
}
|
||||
if _, err = db.Exec("PRAGMA locking_mode=EXCLUSIVE;"); err != nil {
|
||||
t.Fatal("Failed to Exec PRAGMA locking_mode:", err)
|
||||
}
|
||||
if _, err = db.Exec("CREATE TABLE test (id SERIAL, user TEXT NOT NULL, name TEXT NOT NULL);"); err != nil {
|
||||
t.Fatal("Failed to Exec CREATE TABLE:", err)
|
||||
}
|
||||
if _, err = db.Exec("INSERT INTO test (user, name) VALUES ('user','name');"); err != nil {
|
||||
t.Fatal("Failed to Exec INSERT:", err)
|
||||
}
|
||||
|
||||
trans, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to Begin:", err)
|
||||
}
|
||||
s, err := trans.Prepare("INSERT INTO test (user, name) VALUES (?, ?);")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to Prepare:", err)
|
||||
}
|
||||
|
||||
var count int
|
||||
if err = trans.QueryRow("SELECT count(user) FROM test;").Scan(&count); err != nil {
|
||||
t.Fatal("Failed to QueryRow:", err)
|
||||
}
|
||||
if _, err = s.Exec("bbbb", "aaaa"); err != nil {
|
||||
t.Fatal("Failed to Exec prepared statement:", err)
|
||||
}
|
||||
if err = s.Close(); err != nil {
|
||||
t.Fatal("Failed to Close prepared statement:", err)
|
||||
}
|
||||
if err = trans.Commit(); err != nil {
|
||||
t.Fatal("Failed to Commit:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimezoneConversion(t *testing.T) {
|
||||
zones := []string{"UTC", "US/Central", "US/Pacific", "Local"}
|
||||
for _, tz := range zones {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename+"?_loc="+url.QueryEscape(tz))
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE foo")
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER, ts TIMESTAMP, dt DATETIME)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
loc, err := time.LoadLocation(tz)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to load location:", err)
|
||||
}
|
||||
|
||||
timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
|
||||
timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC)
|
||||
timestamp3 := time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC)
|
||||
tests := []struct {
|
||||
value interface{}
|
||||
expected time.Time
|
||||
}{
|
||||
{"nonsense", time.Time{}.In(loc)},
|
||||
{"0000-00-00 00:00:00", time.Time{}.In(loc)},
|
||||
{timestamp1, timestamp1.In(loc)},
|
||||
{timestamp1.Unix(), timestamp1.In(loc)},
|
||||
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1.In(loc)},
|
||||
{timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1.In(loc)},
|
||||
{timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1.In(loc)},
|
||||
{timestamp1.Format("2006-01-02 15:04:05"), timestamp1.In(loc)},
|
||||
{timestamp1.Format("2006-01-02T15:04:05"), timestamp1.In(loc)},
|
||||
{timestamp2, timestamp2.In(loc)},
|
||||
{"2006-01-02 15:04:05.123456789", timestamp2.In(loc)},
|
||||
{"2006-01-02T15:04:05.123456789", timestamp2.In(loc)},
|
||||
{"2012-11-04", timestamp3.In(loc)},
|
||||
{"2012-11-04 00:00", timestamp3.In(loc)},
|
||||
{"2012-11-04 00:00:00", timestamp3.In(loc)},
|
||||
{"2012-11-04 00:00:00.000", timestamp3.In(loc)},
|
||||
{"2012-11-04T00:00", timestamp3.In(loc)},
|
||||
{"2012-11-04T00:00:00", timestamp3.In(loc)},
|
||||
{"2012-11-04T00:00:00.000", timestamp3.In(loc)},
|
||||
}
|
||||
for i := range tests {
|
||||
_, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert timestamp:", err)
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, ts, dt FROM foo ORDER BY id ASC")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
seen := 0
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var ts, dt time.Time
|
||||
|
||||
if err := rows.Scan(&id, &ts, &dt); err != nil {
|
||||
t.Error("Unable to scan results:", err)
|
||||
continue
|
||||
}
|
||||
if id < 0 || id >= len(tests) {
|
||||
t.Error("Bad row id: ", id)
|
||||
continue
|
||||
}
|
||||
seen++
|
||||
if !tests[id].expected.Equal(ts) {
|
||||
t.Errorf("Timestamp value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, ts)
|
||||
}
|
||||
if !tests[id].expected.Equal(dt) {
|
||||
t.Errorf("Datetime value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt)
|
||||
}
|
||||
if tests[id].expected.Location().String() != ts.Location().String() {
|
||||
t.Errorf("Location for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected.Location().String(), ts.Location().String())
|
||||
}
|
||||
if tests[id].expected.Location().String() != dt.Location().String() {
|
||||
t.Errorf("Location for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected.Location().String(), dt.Location().String())
|
||||
}
|
||||
}
|
||||
|
||||
if seen != len(tests) {
|
||||
t.Errorf("Expected to see %d rows", len(tests))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuite(t *testing.T) {
|
||||
db, err := sql.Open("sqlite3", ":memory:")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
sqlite3_test.RunTests(t, db, sqlite3_test.SQLITE)
|
||||
}
|
||||
|
||||
// TODO: Execer & Queryer currently disabled
|
||||
// https://github.com/mattn/go-sqlite3/issues/82
|
||||
func TestExecer(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
create table foo (id integer); -- one comment
|
||||
insert into foo(id) values(?);
|
||||
insert into foo(id) values(?);
|
||||
insert into foo(id) values(?); -- another comment
|
||||
`, 1, 2, 3)
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Exec:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryer(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
create table foo (id integer);
|
||||
`)
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Query:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query(`
|
||||
insert into foo(id) values(?);
|
||||
insert into foo(id) values(?);
|
||||
insert into foo(id) values(?);
|
||||
select id from foo order by id;
|
||||
`, 3, 2, 1)
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Query:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
n := 1
|
||||
if rows != nil {
|
||||
for rows.Next() {
|
||||
var id int
|
||||
err = rows.Scan(&id)
|
||||
if err != nil {
|
||||
t.Error("Failed to db.Query:", err)
|
||||
}
|
||||
if id != n {
|
||||
t.Error("Failed to db.Query: not matched results")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStress(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
db.Exec("CREATE TABLE foo (id int);")
|
||||
db.Exec("INSERT INTO foo VALUES(1);")
|
||||
db.Exec("INSERT INTO foo VALUES(2);")
|
||||
db.Close()
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
for j := 0; j < 3; j++ {
|
||||
rows, err := db.Query("select * from foo where id=1;")
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Query:", err)
|
||||
}
|
||||
for rows.Next() {
|
||||
var i int
|
||||
if err := rows.Scan(&i); err != nil {
|
||||
t.Errorf("Scan failed: %v\n", err)
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
t.Errorf("Post-scan failed: %v\n", err)
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
db.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeLocal(t *testing.T) {
|
||||
zone := "Asia/Tokyo"
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename+"?_loc="+zone)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
db.Exec("CREATE TABLE foo (dt datetime);")
|
||||
db.Exec("INSERT INTO foo VALUES('2015-03-05 15:16:17');")
|
||||
|
||||
row := db.QueryRow("select * from foo")
|
||||
var d time.Time
|
||||
err = row.Scan(&d)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to scan datetime:", err)
|
||||
}
|
||||
if d.Hour() == 15 || !strings.Contains(d.String(), "JST") {
|
||||
t.Fatal("Result should have timezone", d)
|
||||
}
|
||||
db.Close()
|
||||
|
||||
db, err = sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
row = db.QueryRow("select * from foo")
|
||||
err = row.Scan(&d)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to scan datetime:", err)
|
||||
}
|
||||
if d.UTC().Hour() != 15 || !strings.Contains(d.String(), "UTC") {
|
||||
t.Fatalf("Result should not have timezone %v %v", zone, d.String())
|
||||
}
|
||||
|
||||
_, err = db.Exec("DELETE FROM foo")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to delete table:", err)
|
||||
}
|
||||
dt, err := time.Parse("2006/1/2 15/4/5 -0700 MST", "2015/3/5 15/16/17 +0900 JST")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to parse datetime:", err)
|
||||
}
|
||||
db.Exec("INSERT INTO foo VALUES(?);", dt)
|
||||
|
||||
db.Close()
|
||||
db, err = sql.Open("sqlite3", tempFilename+"?_loc="+zone)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
row = db.QueryRow("select * from foo")
|
||||
err = row.Scan(&d)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to scan datetime:", err)
|
||||
}
|
||||
if d.Hour() != 15 || !strings.Contains(d.String(), "JST") {
|
||||
t.Fatalf("Result should have timezone %v %v", zone, d.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
s, n, id := Version()
|
||||
if s == "" || n == 0 || id == "" {
|
||||
t.Errorf("Version failed %q, %d, %q\n", s, n, id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNumberNamedParams(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
create table foo (id integer, name text, extra text);
|
||||
`)
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Query:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(`insert into foo(id, name, extra) values($1, $2, $2)`, 1, "foo")
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Exec:", err)
|
||||
}
|
||||
|
||||
row := db.QueryRow(`select id, extra from foo where id = $1 and extra = $2`, 1, "foo")
|
||||
if row == nil {
|
||||
t.Error("Failed to call db.QueryRow")
|
||||
}
|
||||
var id int
|
||||
var extra string
|
||||
err = row.Scan(&id, &extra)
|
||||
if err != nil {
|
||||
t.Error("Failed to db.Scan:", err)
|
||||
}
|
||||
if id != 1 || extra != "foo" {
|
||||
t.Error("Failed to db.QueryRow: not matched results")
|
||||
}
|
||||
}
|
17
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_test/sqltest.go
generated
vendored
17
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_test/sqltest.go
generated
vendored
@ -275,12 +275,11 @@ func TestPreparedStmt(t *testing.T) {
|
||||
}
|
||||
|
||||
const nRuns = 10
|
||||
ch := make(chan bool)
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < nRuns; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer func() {
|
||||
ch <- true
|
||||
}()
|
||||
defer wg.Done()
|
||||
for j := 0; j < 10; j++ {
|
||||
count := 0
|
||||
if err := sel.QueryRow().Scan(&count); err != nil && err != sql.ErrNoRows {
|
||||
@ -294,9 +293,7 @@ func TestPreparedStmt(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
}
|
||||
for i := 0; i < nRuns; i++ {
|
||||
<-ch
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Benchmarks need to use panic() since b.Error errors are lost when
|
||||
@ -318,7 +315,7 @@ func BenchmarkQuery(b *testing.B) {
|
||||
var i int
|
||||
var f float64
|
||||
var s string
|
||||
// var t time.Time
|
||||
// var t time.Time
|
||||
if err := db.QueryRow("select null, 1, 1.1, 'foo'").Scan(&n, &i, &f, &s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -331,7 +328,7 @@ func BenchmarkParams(b *testing.B) {
|
||||
var i int
|
||||
var f float64
|
||||
var s string
|
||||
// var t time.Time
|
||||
// var t time.Time
|
||||
if err := db.QueryRow("select ?, ?, ?, ?", nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -350,7 +347,7 @@ func BenchmarkStmt(b *testing.B) {
|
||||
var i int
|
||||
var f float64
|
||||
var s string
|
||||
// var t time.Time
|
||||
// var t time.Time
|
||||
if err := st.QueryRow(nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
2
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_windows.go
generated
vendored
2
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_windows.go
generated
vendored
@ -8,7 +8,7 @@ package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe
|
||||
#cgo windows,386 CFLAGS: -D_localtime32=localtime
|
||||
#cgo windows,386 CFLAGS: -D_USE_32BIT_TIME_T
|
||||
#cgo LDFLAGS: -lmingwex -lmingw32
|
||||
*/
|
||||
import "C"
|
||||
|
65
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3ext.h
generated
vendored
65
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3ext.h
generated
vendored
@ -28,7 +28,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each others' shared
|
||||
** versions of SQLite will not be able to load each other's shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
@ -250,11 +250,40 @@ struct sqlite3_api_routines {
|
||||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*vsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
/* Version 3.8.7 and later */
|
||||
int (*auto_extension)(void(*)(void));
|
||||
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||
void(*)(void*),unsigned char);
|
||||
int (*cancel_auto_extension)(void(*)(void));
|
||||
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||
void *(*malloc64)(sqlite3_uint64);
|
||||
sqlite3_uint64 (*msize)(void*);
|
||||
void *(*realloc64)(void*,sqlite3_uint64);
|
||||
void (*reset_auto_extension)(void);
|
||||
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
/* Version 3.8.11 and later */
|
||||
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||
void (*value_free)(sqlite3_value*);
|
||||
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||
/* Version 3.9.0 and later */
|
||||
unsigned int (*value_subtype)(sqlite3_value*);
|
||||
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||
/* Version 3.10.0 and later */
|
||||
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
int (*strlike)(const char*,const char*,unsigned int);
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
};
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected throught the global sqlite3_api structure.
|
||||
** redirected through the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
@ -263,7 +292,7 @@ struct sqlite3_api_routines {
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#ifndef SQLITE_CORE
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
@ -390,6 +419,7 @@ struct sqlite3_api_routines {
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_vsnprintf sqlite3_api->vsnprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
@ -467,9 +497,34 @@ struct sqlite3_api_routines {
|
||||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
#endif /* SQLITE_CORE */
|
||||
/* Version 3.8.7 and later */
|
||||
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||
#define sqlite3_msize sqlite3_api->msize
|
||||
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||
#define sqlite3_strglob sqlite3_api->strglob
|
||||
/* Version 3.8.11 and later */
|
||||
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||
#define sqlite3_value_free sqlite3_api->value_free
|
||||
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||
/* Version 3.9.0 and later */
|
||||
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||
/* Version 3.10.0 and later */
|
||||
#define sqlite3_status64 sqlite3_api->status64
|
||||
#define sqlite3_strlike sqlite3_api->strlike
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#ifndef SQLITE_CORE
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
/* This case when the file really is being compiled as a loadable
|
||||
** extension */
|
||||
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||
|
Loading…
Reference in New Issue
Block a user