mirror of https://github.com/perkeep/perkeep.git
Remove misc/sqlite directory. Old experiment.
Change-Id: I207c96dc77221fddeebb8ecdf1bc61c15269ef16
This commit is contained in:
parent
d065aac5b7
commit
f7707d75c1
|
@ -1 +0,0 @@
|
|||
foo.db*
|
|
@ -1,13 +0,0 @@
|
|||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG=camdev/sqlite
|
||||
|
||||
CGOFILES=\
|
||||
vfs.go\
|
||||
sqlite.go\
|
||||
|
||||
CGO_OFILES=\
|
||||
sqlite3_obj.o\
|
||||
vfs.o\
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
|
@ -1,13 +0,0 @@
|
|||
#if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
|
||||
# define __USE_MINGW_ANSI_STDIO 0
|
||||
# include <stdio.h>
|
||||
#elif defined(__unix__)
|
||||
# define SQLITE_OS_OTHER 1
|
||||
#else
|
||||
# error Unsupported OS
|
||||
#endif
|
||||
|
||||
#ifndef INCLUDE_SQLITE_VERSION_SYMBOL
|
||||
#define SKIP_SQLITE_VERSION
|
||||
#endif
|
||||
#include "sqlite3.h"
|
|
@ -1,297 +0,0 @@
|
|||
package sqlite
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -D_GNU_SOURCE -D_XOPEN_SOURCE=500
|
||||
#cgo linux LDFLAGS: -lpthread
|
||||
#cgo windows CFLAGS: -D_GNU_SOURCE
|
||||
#cgo windows LDFLAGS: -lpthread -lgcc_s -lmingwex -lmsvcrt
|
||||
|
||||
#include "go-sqlite.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static int my_bind_text(sqlite3_stmt *stmt, int n, char *p, int np) {
|
||||
return sqlite3_bind_text(stmt, n, p, np, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
static int my_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) {
|
||||
return sqlite3_bind_blob(stmt, n, p, np, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
extern int go_init_vfs();
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
C.go_init_vfs()
|
||||
}
|
||||
|
||||
type Errno int
|
||||
|
||||
func (e Errno) String() string {
|
||||
s := errText[e]
|
||||
if s == "" {
|
||||
return fmt.Sprintf("errno %d", e)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
var (
|
||||
ErrError os.Error = Errno(1) // /* SQL error or missing database */
|
||||
ErrInternal os.Error = Errno(2) // /* Internal logic error in SQLite */
|
||||
ErrPerm os.Error = Errno(3) // /* Access permission denied */
|
||||
ErrAbort os.Error = Errno(4) // /* Callback routine requested an abort */
|
||||
ErrBusy os.Error = Errno(5) // /* The database file is locked */
|
||||
ErrLocked os.Error = Errno(6) // /* A table in the database is locked */
|
||||
ErrNoMem os.Error = Errno(7) // /* A malloc() failed */
|
||||
ErrReadOnly os.Error = Errno(8) // /* Attempt to write a readonly database */
|
||||
ErrInterrupt os.Error = Errno(9) // /* Operation terminated by sqlite3_interrupt()*/
|
||||
ErrIOErr os.Error = Errno(10) // /* Some kind of disk I/O error occurred */
|
||||
ErrCorrupt os.Error = Errno(11) // /* The database disk image is malformed */
|
||||
ErrFull os.Error = Errno(13) // /* Insertion failed because database is full */
|
||||
ErrCantOpen os.Error = Errno(14) // /* Unable to open the database file */
|
||||
ErrEmpty os.Error = Errno(16) // /* Database is empty */
|
||||
ErrSchema os.Error = Errno(17) // /* The database schema changed */
|
||||
ErrTooBig os.Error = Errno(18) // /* String or BLOB exceeds size limit */
|
||||
ErrConstraint os.Error = Errno(19) // /* Abort due to constraint violation */
|
||||
ErrMismatch os.Error = Errno(20) // /* Data type mismatch */
|
||||
ErrMisuse os.Error = Errno(21) // /* Library used incorrectly */
|
||||
ErrNolfs os.Error = Errno(22) // /* Uses OS features not supported on host */
|
||||
ErrAuth os.Error = Errno(23) // /* Authorization denied */
|
||||
ErrFormat os.Error = Errno(24) // /* Auxiliary database format error */
|
||||
ErrRange os.Error = Errno(25) // /* 2nd parameter to sqlite3_bind out of range */
|
||||
ErrNotDB os.Error = Errno(26) // /* File opened that is not a database file */
|
||||
Row = Errno(100) // /* sqlite3_step() has another row ready */
|
||||
Done = Errno(101) // /* sqlite3_step() has finished executing */
|
||||
)
|
||||
|
||||
var errText = map[Errno]string{
|
||||
1: "SQL error or missing database",
|
||||
2: "Internal logic error in SQLite",
|
||||
3: "Access permission denied",
|
||||
4: "Callback routine requested an abort",
|
||||
5: "The database file is locked",
|
||||
6: "A table in the database is locked",
|
||||
7: "A malloc() failed",
|
||||
8: "Attempt to write a readonly database",
|
||||
9: "Operation terminated by sqlite3_interrupt()*/",
|
||||
10: "Some kind of disk I/O error occurred",
|
||||
11: "The database disk image is malformed",
|
||||
12: "NOT USED. Table or record not found",
|
||||
13: "Insertion failed because database is full",
|
||||
14: "Unable to open the database file",
|
||||
15: "NOT USED. Database lock protocol error",
|
||||
16: "Database is empty",
|
||||
17: "The database schema changed",
|
||||
18: "String or BLOB exceeds size limit",
|
||||
19: "Abort due to constraint violation",
|
||||
20: "Data type mismatch",
|
||||
21: "Library used incorrectly",
|
||||
22: "Uses OS features not supported on host",
|
||||
23: "Authorization denied",
|
||||
24: "Auxiliary database format error",
|
||||
25: "2nd parameter to sqlite3_bind out of range",
|
||||
26: "File opened that is not a database file",
|
||||
100: "sqlite3_step() has another row ready",
|
||||
101: "sqlite3_step() has finished executing",
|
||||
}
|
||||
|
||||
func (c *Conn) error(rv C.int) os.Error {
|
||||
if rv == 21 { // misuse
|
||||
return Errno(rv)
|
||||
}
|
||||
return os.NewError(Errno(rv).String() + ": " + C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
type Conn struct {
|
||||
db *C.sqlite3
|
||||
}
|
||||
|
||||
func Version() string {
|
||||
p := C.sqlite3_libversion()
|
||||
return C.GoString(p)
|
||||
}
|
||||
|
||||
func Open(filename string) (*Conn, os.Error) {
|
||||
var db *C.sqlite3
|
||||
name := C.CString(filename)
|
||||
defer C.free(unsafe.Pointer(name))
|
||||
rv := C.sqlite3_open(name, &db)
|
||||
if rv != 0 {
|
||||
return nil, Errno(rv)
|
||||
}
|
||||
if db == nil {
|
||||
return nil, os.NewError("sqlite succeeded without returning a database")
|
||||
}
|
||||
return &Conn{db}, nil
|
||||
}
|
||||
|
||||
func (c *Conn) Exec(cmd string, args ...interface{}) os.Error {
|
||||
s, err := c.Prepare(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Finalize()
|
||||
err = s.Exec(args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rv := C.sqlite3_step(s.stmt)
|
||||
errno := Errno(rv)
|
||||
if errno != Done {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Stmt struct {
|
||||
c *Conn
|
||||
stmt *C.sqlite3_stmt
|
||||
err os.Error
|
||||
}
|
||||
|
||||
func (c *Conn) Prepare(cmd string) (*Stmt, os.Error) {
|
||||
cmdstr := C.CString(cmd)
|
||||
defer C.free(unsafe.Pointer(cmdstr))
|
||||
var stmt *C.sqlite3_stmt
|
||||
var tail *C.char
|
||||
rv := C.sqlite3_prepare_v2(c.db, cmdstr, C.int(len(cmd)+1), &stmt, &tail)
|
||||
if rv != 0 {
|
||||
return nil, c.error(rv)
|
||||
}
|
||||
return &Stmt{c: c, stmt: stmt}, nil
|
||||
}
|
||||
|
||||
func (s *Stmt) Exec(args ...interface{}) os.Error {
|
||||
rv := C.sqlite3_reset(s.stmt)
|
||||
if rv != 0 {
|
||||
return s.c.error(rv)
|
||||
}
|
||||
|
||||
n := int(C.sqlite3_bind_parameter_count(s.stmt))
|
||||
if n != len(args) {
|
||||
return os.NewError(fmt.Sprintf("incorrect argument count: have %d want %d", len(args), n))
|
||||
}
|
||||
|
||||
for i, v := range args {
|
||||
var str string
|
||||
switch v := v.(type) {
|
||||
case []byte:
|
||||
var p *byte
|
||||
if len(v) > 0 {
|
||||
p = &v[0]
|
||||
}
|
||||
if rv := C.my_bind_blob(s.stmt, C.int(i+1), unsafe.Pointer(p), C.int(len(v))); rv != 0 {
|
||||
return s.c.error(rv)
|
||||
}
|
||||
continue
|
||||
|
||||
case bool:
|
||||
if v {
|
||||
str = "1"
|
||||
} else {
|
||||
str = "0"
|
||||
}
|
||||
|
||||
default:
|
||||
str = fmt.Sprint(v)
|
||||
}
|
||||
|
||||
cstr := C.CString(str)
|
||||
rv := C.my_bind_text(s.stmt, C.int(i+1), cstr, C.int(len(str)))
|
||||
C.free(unsafe.Pointer(cstr))
|
||||
if rv != 0 {
|
||||
return s.c.error(rv)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stmt) Error() os.Error {
|
||||
return s.err
|
||||
}
|
||||
|
||||
func (s *Stmt) Next() bool {
|
||||
rv := C.sqlite3_step(s.stmt)
|
||||
err := Errno(rv)
|
||||
if err == Row {
|
||||
return true
|
||||
}
|
||||
if err != Done {
|
||||
s.err = s.c.error(rv)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Stmt) Scan(args ...interface{}) os.Error {
|
||||
n := int(C.sqlite3_column_count(s.stmt))
|
||||
if n != len(args) {
|
||||
return os.NewError("incorrect argument count")
|
||||
}
|
||||
|
||||
for i, v := range args {
|
||||
n := C.sqlite3_column_bytes(s.stmt, C.int(i))
|
||||
p := C.sqlite3_column_blob(s.stmt, C.int(i))
|
||||
if p == nil && n > 0 {
|
||||
return os.NewError("got nil blob")
|
||||
}
|
||||
var data []byte
|
||||
if n > 0 {
|
||||
data = (*[1 << 30]byte)(unsafe.Pointer(p))[0:n]
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case *[]byte:
|
||||
*v = data
|
||||
case *string:
|
||||
*v = string(data)
|
||||
case *bool:
|
||||
*v = string(data) == "1"
|
||||
case *int:
|
||||
x, err := strconv.Atoi(string(data))
|
||||
if err != nil {
|
||||
return os.NewError("arg " + strconv.Itoa(i) + " as int: " + err.String())
|
||||
}
|
||||
*v = x
|
||||
case *int64:
|
||||
x, err := strconv.Atoi64(string(data))
|
||||
if err != nil {
|
||||
return os.NewError("arg " + strconv.Itoa(i) + " as int64: " + err.String())
|
||||
}
|
||||
*v = x
|
||||
case *float64:
|
||||
x, err := strconv.Atof64(string(data))
|
||||
if err != nil {
|
||||
return os.NewError("arg " + strconv.Itoa(i) + " as float64: " + err.String())
|
||||
}
|
||||
*v = x
|
||||
default:
|
||||
return os.NewError("unsupported type in Scan: " + reflect.TypeOf(v).String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stmt) Finalize() os.Error {
|
||||
rv := C.sqlite3_finalize(s.stmt)
|
||||
if rv != 0 {
|
||||
return s.c.error(rv)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) Close() os.Error {
|
||||
rv := C.sqlite3_close(c.db)
|
||||
if rv != 0 {
|
||||
return c.error(rv)
|
||||
}
|
||||
return nil
|
||||
}
|
128416
misc/sqlite/sqlite3.c
128416
misc/sqlite/sqlite3.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +0,0 @@
|
|||
#define INCLUDE_SQLITE_VERSION_SYMBOL
|
||||
#include "go-sqlite.h"
|
||||
#include "sqlite3.c"
|
|
@ -1,48 +0,0 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFoo(t *testing.T) {
|
||||
td, err := ioutil.TempDir("", "go-sqlite-test")
|
||||
if err != nil {
|
||||
t.Fatalf("TempDir: %v", err)
|
||||
}
|
||||
dbName := filepath.Join(td, "foo.db")
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
db, err := Open(dbName)
|
||||
if err != nil {
|
||||
t.Fatalf("open: %v", err)
|
||||
}
|
||||
err = db.Exec("CREATE TABLE IF NOT EXISTS foo (a INT, b VARCHAR(200))")
|
||||
if err != nil {
|
||||
t.Fatalf("create table: %v", err)
|
||||
}
|
||||
|
||||
err = db.Exec("INSERT INTO foo VALUES (1, ?)", "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("insert: %v", err)
|
||||
}
|
||||
err = db.Exec("INSERT INTO foo VALUES (2, DATETIME('now'))")
|
||||
if err != nil {
|
||||
t.Fatalf("insert: %v", err)
|
||||
}
|
||||
err = db.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("close: %v", err)
|
||||
}
|
||||
|
||||
fi, err := os.Stat(dbName)
|
||||
if err != nil {
|
||||
t.Fatalf("Stat: %v", err)
|
||||
}
|
||||
if fi.Size == 0 {
|
||||
t.Fatalf("FileInfo.Size after writes was 0")
|
||||
}
|
||||
t.Logf("fi.Size = %d", fi.Size)
|
||||
}
|
|
@ -1,258 +0,0 @@
|
|||
#include "go-sqlite.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "_cgo_export.h"
|
||||
|
||||
static sqlite3_io_methods g_file_methods;
|
||||
|
||||
typedef struct GoFile GoFile;
|
||||
struct GoFile {
|
||||
sqlite3_io_methods const *pMethod; /* Always the first entry */
|
||||
int fd;
|
||||
};
|
||||
|
||||
/* File methods */
|
||||
|
||||
static int go_file_close(sqlite3_file* file) {
|
||||
GoFileClose(((GoFile*) file)->fd);
|
||||
// Matching sqlite3's os_unix.c here.
|
||||
memset(file, 0, sizeof(GoFile));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_file_read(sqlite3_file* file, void* dest, int iAmt, sqlite3_int64 iOfst) {
|
||||
return GoFileRead(((GoFile*) file)->fd, dest, iAmt, iOfst);
|
||||
}
|
||||
|
||||
static int go_file_write(sqlite3_file* file, const void* src, int iAmt, sqlite3_int64 iOfst) {
|
||||
return GoFileWrite(((GoFile*) file)->fd, src, iAmt, iOfst);
|
||||
}
|
||||
|
||||
static int go_file_truncate(sqlite3_file* file, sqlite3_int64 size) {
|
||||
const int fd = ((GoFile*) file)->fd;
|
||||
fprintf(stderr, "TODO go_file_truncate(%d)\n", fd);
|
||||
// TODO: implement
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_file_sync(sqlite3_file* file, int flags) {
|
||||
const int fd = ((GoFile*) file)->fd;
|
||||
fprintf(stderr, "TODO go_file_sync(%d)\n", fd);
|
||||
// TODO: implement
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_file_file_size(sqlite3_file* file, sqlite3_int64* pSize) {
|
||||
const int fd = ((GoFile*) file)->fd;
|
||||
struct GoFileFileSize_return result = GoFileFileSize(fd);
|
||||
fprintf(stderr, "go_file_file_size(%d) = %d, %lld\n", fd, result.r0, result.r1);
|
||||
if (result.r0 != 0) {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
*pSize = result.r1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_file_lock(sqlite3_file* file, int flags) {
|
||||
const int fd = ((GoFile*) file)->fd;
|
||||
fprintf(stderr, "TODO go_file_lock(%d)\n", fd);
|
||||
// TODO: implement
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_file_unlock(sqlite3_file* file, int flags) {
|
||||
const int fd = ((GoFile*) file)->fd;
|
||||
fprintf(stderr, "TODO go_file_unlock(%d)\n", fd);
|
||||
// TODO: implement
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_file_check_reserved_lock(sqlite3_file* file, int* pResOut) {
|
||||
const int fd = ((GoFile*) file)->fd;
|
||||
fprintf(stderr, "TODO go_file_check_reserved_lock(%d)\n", fd);
|
||||
// TODO: implement
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_file_file_control(sqlite3_file* file, int op, void* pArg) {
|
||||
const int fd = ((GoFile*) file)->fd;
|
||||
fprintf(stderr, "TODO go_file_file_control(%d, %d)\n", fd, op);
|
||||
// TODO: implement
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_file_sector_size(sqlite3_file* file) {
|
||||
// Matching sqlite3's os_unix.c here; this is SQLITE_DEFAULT_SECTOR_SIZE.
|
||||
return 512;
|
||||
}
|
||||
|
||||
static int go_file_device_characteristics(sqlite3_file* file) {
|
||||
// Matching sqlite3's os_unix.c here.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VFS methods */
|
||||
|
||||
static int go_vfs_open(sqlite3_vfs* vfs,
|
||||
const char* zName,
|
||||
sqlite3_file* file,
|
||||
int flags,
|
||||
int* pOutFlags) {
|
||||
fprintf(stderr, "go_vfs_open: %s\n", zName);
|
||||
GoFile* go_file = (GoFile*) file;
|
||||
memset(go_file, 0, sizeof(go_file));
|
||||
|
||||
const int fd = GoVFSOpen((char*) zName, flags);
|
||||
if (fd == -1) {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
go_file->pMethod = &g_file_methods;
|
||||
go_file->fd = fd;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_vfs_delete(sqlite3_vfs* vfs, const char* zName, int syncDir) {
|
||||
return GoVFSDelete(zName, syncDir);
|
||||
}
|
||||
|
||||
static int go_vfs_access(sqlite3_vfs* vfs,
|
||||
const char* zName,
|
||||
int flags,
|
||||
int* pResOut) {
|
||||
*pResOut = GoVFSAccess(zName, flags);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_vfs_full_pathname(sqlite3_vfs* vfs,
|
||||
const char* zName,
|
||||
int nOut,
|
||||
char* zOut) {
|
||||
fprintf(stderr, "TODO go_vfs_full_pathname: %s\n", zName);
|
||||
// TODO: Actually implement this.
|
||||
strncpy(zOut, zName, nOut);
|
||||
zOut[nOut - 1] = '\0';
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static void* go_vfs_dl_open(sqlite3_vfs* vfs, const char* zFilename) {
|
||||
fprintf(stderr, "TODO go_vfs_dl_open\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void go_vfs_dl_error(sqlite3_vfs* vfs, int nByte, char *zErrMsg) {
|
||||
fprintf(stderr, "TODO go_vfs_dl_error\n");
|
||||
}
|
||||
|
||||
static void* go_vfs_dl_sym(sqlite3_vfs* vfs,
|
||||
void* handle,
|
||||
const char* zSymbol) {
|
||||
fprintf(stderr, "TODO go_vfs_dl_sym\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void go_vfs_dl_close(sqlite3_vfs* vfs, void* handle) {
|
||||
fprintf(stderr, "TODO go_vfs_dl_close\n");
|
||||
}
|
||||
|
||||
static int go_vfs_randomness(sqlite3_vfs* vfs, int nByte, char *zOut) {
|
||||
fprintf(stderr, "TODO go_vfs_randomness\n");
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_vfs_sleep(sqlite3_vfs* vfs, int microseconds) {
|
||||
fprintf(stderr, "TODO go_vfs_sleep\n");
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_vfs_current_time(sqlite3_vfs* vfs, double* now) {
|
||||
*now = GoVFSCurrentTimeInt64() / 86400000.0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_vfs_get_last_error(sqlite3_vfs* vfs, int foo, char* bar) {
|
||||
// Unused, per sqlite3's os_unix.c.
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int go_vfs_current_time_int64(sqlite3_vfs* vfs, sqlite3_int64* now) {
|
||||
*now = GoVFSCurrentTimeInt64();
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
int go_init_vfs(void) {
|
||||
static sqlite3_vfs vfs;
|
||||
memset(&vfs, 0, sizeof(vfs));
|
||||
vfs.iVersion = 2;
|
||||
vfs.szOsFile = sizeof(GoFile);
|
||||
vfs.mxPathname = 512;
|
||||
vfs.pNext = NULL;
|
||||
vfs.zName = "go";
|
||||
vfs.pAppData = NULL;
|
||||
/* Version 1 methods */
|
||||
vfs.xOpen = go_vfs_open;
|
||||
vfs.xDelete = go_vfs_delete;
|
||||
vfs.xAccess = go_vfs_access;
|
||||
vfs.xFullPathname = go_vfs_full_pathname;
|
||||
vfs.xDlOpen = go_vfs_dl_open;
|
||||
vfs.xDlError = go_vfs_dl_error;
|
||||
vfs.xDlSym = go_vfs_dl_sym;
|
||||
vfs.xDlClose = go_vfs_dl_close;
|
||||
vfs.xRandomness = go_vfs_randomness;
|
||||
vfs.xSleep = go_vfs_sleep;
|
||||
vfs.xCurrentTime = go_vfs_current_time;
|
||||
vfs.xGetLastError = go_vfs_get_last_error;
|
||||
/* Version 2 method */
|
||||
vfs.xCurrentTimeInt64 = go_vfs_current_time_int64;
|
||||
#if 0
|
||||
/*
|
||||
** The methods above are in versions 1 and 2 of the sqlite_vfs object.
|
||||
** Those below are for version 3 and greater.
|
||||
*/
|
||||
int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);
|
||||
sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);
|
||||
const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
|
||||
/*
|
||||
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
|
||||
** New fields may be appended in figure versions. The iVersion
|
||||
** value will increment whenever this happens.
|
||||
*/
|
||||
};
|
||||
#endif
|
||||
sqlite3_vfs_register(&vfs, 1);
|
||||
|
||||
memset(&g_file_methods, 0, sizeof(g_file_methods));
|
||||
g_file_methods.iVersion = 1;
|
||||
g_file_methods.xClose = go_file_close;
|
||||
g_file_methods.xRead = go_file_read;
|
||||
g_file_methods.xWrite = go_file_write;
|
||||
g_file_methods.xTruncate = go_file_truncate;
|
||||
g_file_methods.xSync = go_file_sync;
|
||||
g_file_methods.xFileSize = go_file_file_size;
|
||||
g_file_methods.xLock = go_file_lock;
|
||||
g_file_methods.xUnlock = go_file_unlock;
|
||||
g_file_methods.xCheckReservedLock = go_file_check_reserved_lock;
|
||||
g_file_methods.xFileControl = go_file_file_control;
|
||||
g_file_methods.xSectorSize = go_file_sector_size;
|
||||
g_file_methods.xDeviceCharacteristics = go_file_device_characteristics;
|
||||
#if 0
|
||||
/* Methods above are valid for version 1 */
|
||||
int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
|
||||
int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);
|
||||
void (*xShmBarrier)(sqlite3_file*);
|
||||
int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
|
||||
/* Methods above are valid for version 2 */
|
||||
/* Additional methods may be added in future releases */
|
||||
#endif
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#if SQLITE_OS_OTHER==1
|
||||
int sqlite3_os_init(void) { return SQLITE_OK; }
|
||||
int sqlite3_os_end(void) { return SQLITE_OK; }
|
||||
#endif
|
|
@ -1,224 +0,0 @@
|
|||
package sqlite
|
||||
|
||||
/*
|
||||
#include <string.h>
|
||||
|
||||
#define SKIP_SQLITE_VERSION
|
||||
#include "sqlite3.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Our map of fake fds to our internal *os.File. These aren't
|
||||
// actual fd numbers, since those don't exist on Windows.
|
||||
// Instead we just make some identifiers up.
|
||||
var fmu sync.Mutex
|
||||
var fileMap = make(map[int]*os.File) // fake_fd -> *os.File
|
||||
var lastFakeFd = 99000 // start high to catch bugs of people using these like real fds
|
||||
|
||||
func GetFile(fd int) (file *os.File) {
|
||||
fmu.Lock()
|
||||
defer fmu.Unlock()
|
||||
return fileMap[fd]
|
||||
}
|
||||
|
||||
//export GoFileClose
|
||||
// Returns 0 on success and -1 on error.
|
||||
func GoFileClose(fd C.int) int {
|
||||
file := GetFile(int(fd))
|
||||
fmu.Lock()
|
||||
fileMap[int(fd)] = nil, false
|
||||
fmu.Unlock()
|
||||
if file.Close() != nil {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
//export GoFileRead
|
||||
// Returns SQLite error code to be returned by xRead:
|
||||
// SQLITE_OK: read n bytes
|
||||
// SQLITE_IOERR_READ: got error while reading
|
||||
// SQLITE_IOERR_SHORT_READ: read fewer than n bytes; rest will be zeroed
|
||||
func GoFileRead(fd C.int, dst *C.char, n C.int, offset C.long) (rv int) {
|
||||
println("reading", n, "bytes at offset", offset, "from fd", fd)
|
||||
defer func() {
|
||||
println("read returning", rv)
|
||||
}()
|
||||
|
||||
file := GetFile(int(fd))
|
||||
if file == nil {
|
||||
return C.SQLITE_IOERR_READ
|
||||
}
|
||||
|
||||
buf := make([]byte, n)
|
||||
curbuf := buf
|
||||
for n > 0 {
|
||||
read, err := file.ReadAt(curbuf, int64(offset))
|
||||
curbuf = curbuf[read:]
|
||||
n -= C.int(read)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return C.SQLITE_IOERR_READ
|
||||
}
|
||||
}
|
||||
|
||||
C.memcpy(unsafe.Pointer(dst), unsafe.Pointer(&buf[0]), C.size_t(len(buf)))
|
||||
|
||||
if n != 0 {
|
||||
return C.SQLITE_IOERR_SHORT_READ
|
||||
}
|
||||
return C.SQLITE_OK
|
||||
}
|
||||
|
||||
//export GoFileWrite
|
||||
// Returns SQLite error code to be returned by xWrite:
|
||||
// SQLITE_OK: wrote n bytes
|
||||
// SQLITE_IOERR_WRITE: got error while writing
|
||||
// SQLITE_FULL: partial write
|
||||
func GoFileWrite(fd C.int, src *C.char, n C.int, offset C.long) (rv int) {
|
||||
println("writing", n, "bytes at offset", offset, "to fd", fd)
|
||||
defer func() {
|
||||
println("write returning", rv)
|
||||
}()
|
||||
|
||||
file := GetFile(int(fd))
|
||||
if file == nil {
|
||||
return C.SQLITE_IOERR_WRITE
|
||||
}
|
||||
|
||||
// TODO: avoid this copy
|
||||
buf := make([]byte, n)
|
||||
C.memcpy(unsafe.Pointer(&buf[0]), unsafe.Pointer(src), C.size_t(len(buf)))
|
||||
|
||||
nwritten, err := file.WriteAt(buf, int64(offset))
|
||||
if err != nil {
|
||||
if err == os.ENOSPC {
|
||||
return C.SQLITE_FULL
|
||||
}
|
||||
return C.SQLITE_IOERR_WRITE
|
||||
}
|
||||
if nwritten != int(n) {
|
||||
return C.SQLITE_IOERR_WRITE
|
||||
}
|
||||
|
||||
return C.SQLITE_OK
|
||||
}
|
||||
|
||||
//export GoFileFileSize
|
||||
// return[0]: 0 on success and -1 on error.
|
||||
// return[1]: size
|
||||
func GoFileFileSize(fd C.int) (rv int, size C.long) {
|
||||
println("getting file size for fd", fd)
|
||||
defer func() {
|
||||
println("returning", rv, "with size", size)
|
||||
}()
|
||||
|
||||
file := GetFile(int(fd))
|
||||
if file == nil {
|
||||
return -1, 0
|
||||
}
|
||||
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
return -1, 0
|
||||
}
|
||||
return 0, C.long(info.Size)
|
||||
}
|
||||
|
||||
//export GoVFSOpen
|
||||
// fd is -1 on error.
|
||||
func GoVFSOpen(filename *C.char, flags C.int) (fd int) {
|
||||
println("opening", C.GoString(filename), "with flags", int(flags))
|
||||
|
||||
goflags := 0
|
||||
if flags&C.SQLITE_OPEN_READONLY != 0 {
|
||||
goflags |= os.O_RDONLY
|
||||
}
|
||||
if flags&C.SQLITE_OPEN_READWRITE != 0 {
|
||||
goflags |= os.O_RDWR
|
||||
}
|
||||
if flags&C.SQLITE_OPEN_CREATE != 0 {
|
||||
goflags |= os.O_RDWR | os.O_CREATE
|
||||
}
|
||||
if flags&C.SQLITE_OPEN_DELETEONCLOSE != 0 {
|
||||
// TODO: Do something.
|
||||
}
|
||||
if flags&C.SQLITE_OPEN_EXCLUSIVE != 0 {
|
||||
goflags |= os.O_EXCL
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(C.GoString(filename), goflags, 0666)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
println("got error:", err.String())
|
||||
}
|
||||
println("returning fd", fd)
|
||||
}()
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
fmu.Lock()
|
||||
defer fmu.Unlock()
|
||||
fakeFd := lastFakeFd
|
||||
lastFakeFd++
|
||||
fileMap[fakeFd] = file
|
||||
return fakeFd
|
||||
}
|
||||
|
||||
//export GoVFSDelete
|
||||
// Returns SQLite error code to be returned by xWrite:
|
||||
// SQLITE_OK: deleted the file
|
||||
// SQLITE_IOERR_DELETE: failed to delete
|
||||
// SQLITE_IOERR_DIR_FSYNC: failed to fsync dir after deleting
|
||||
func GoVFSDelete(filename *C.char, syncDir C.int) (rv int) {
|
||||
println("deleting", C.GoString(filename), "with syncdir", syncDir)
|
||||
if err := os.Remove(C.GoString(filename)); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return C.SQLITE_OK
|
||||
}
|
||||
println("delete of", C.GoString(filename), "failed:", err.String())
|
||||
return C.SQLITE_IOERR_DELETE
|
||||
}
|
||||
// TODO: Support syncDir.
|
||||
return C.SQLITE_OK
|
||||
}
|
||||
|
||||
//export GoVFSAccess
|
||||
func GoVFSAccess(filename *C.char, flags C.int) (rv int) {
|
||||
fi, err := os.Stat(C.GoString(filename))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
switch flags {
|
||||
case C.SQLITE_ACCESS_EXISTS:
|
||||
if fi.Size != 0 {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
case C.SQLITE_ACCESS_READWRITE:
|
||||
// TODO: compute read/writeability in a manner similar to access()
|
||||
return 1
|
||||
case C.SQLITE_ACCESS_READ:
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
//export GoVFSCurrentTimeInt64
|
||||
func GoVFSCurrentTimeInt64() (now int64) {
|
||||
// Unix epoch as a Julian Day number times 86_400_000.
|
||||
const unixEpoch = 24405875 * 8640000
|
||||
return unixEpoch + (time.Nanoseconds() / 1000000)
|
||||
}
|
Loading…
Reference in New Issue