Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gosqlite
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
gosqlite
Commits
24e630f3
Commit
24e630f3
authored
Oct 28, 2012
by
gwenn
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Start working on virtual table support.
parent
5ec57d10
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
407 additions
and
3 deletions
+407
-3
meta.go
meta.go
+6
-3
sqlite.go
sqlite.go
+1
-0
vtab.c
vtab.c
+118
-0
vtab.go
vtab.go
+216
-0
vtab_test.go
vtab_test.go
+66
-0
No files found.
meta.go
View file @
24e630f3
...
...
@@ -296,13 +296,16 @@ func (c *Conn) IndexColumns(dbName, index string) ([]Column, error) {
// that are useful for constructing SQL statements.
// (See http://sqlite.org/c3ref/mprintf.html)
func
Mprintf
(
format
string
,
arg
string
)
string
{
zSQL
:=
mPrintf
(
format
,
arg
)
defer
C
.
sqlite3_free
(
unsafe
.
Pointer
(
zSQL
))
return
C
.
GoString
(
zSQL
)
}
func
mPrintf
(
format
,
arg
string
)
*
C
.
char
{
cf
:=
C
.
CString
(
format
)
defer
C
.
free
(
unsafe
.
Pointer
(
cf
))
ca
:=
C
.
CString
(
arg
)
defer
C
.
free
(
unsafe
.
Pointer
(
ca
))
zSQL
:=
C
.
my_mprintf
(
cf
,
ca
)
defer
C
.
sqlite3_free
(
unsafe
.
Pointer
(
zSQL
))
return
C
.
GoString
(
zSQL
)
return
C
.
my_mprintf
(
cf
,
ca
)
}
// Mprintf2 is like fmt.Printf but implements some additional formatting options
...
...
sqlite.go
View file @
24e630f3
...
...
@@ -171,6 +171,7 @@ type Conn struct {
rollbackHook
*
sqliteRollbackHook
updateHook
*
sqliteUpdateHook
udfs
map
[
string
]
*
sqliteFunction
modules
map
[
string
]
*
sqliteModule
}
// Version returns the run-time library version number
...
...
vtab.c
0 → 100644
View file @
24e630f3
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <sqlite3.h>
#include <string.h>
#include "_cgo_export.h"
typedef
struct
goVTab
goVTab
;
struct
goVTab
{
sqlite3_vtab
base
;
void
*
vTab
;
};
static
int
cXInit
(
sqlite3
*
db
,
void
*
pAux
,
int
argc
,
const
char
*
const
*
argv
,
sqlite3_vtab
**
ppVTab
,
char
**
pzErr
,
int
isCreate
)
{
void
*
vTab
=
goMInit
(
db
,
pAux
,
argc
,
(
char
**
)
argv
,
pzErr
,
isCreate
);
if
(
!
vTab
||
*
pzErr
)
{
return
SQLITE_ERROR
;
}
goVTab
*
pvTab
=
(
goVTab
*
)
sqlite3_malloc
(
sizeof
(
goVTab
));
if
(
!
pvTab
)
{
*
pzErr
=
sqlite3_mprintf
(
"%s"
,
"Out of memory"
);
return
SQLITE_NOMEM
;
}
memset
(
pvTab
,
0
,
sizeof
(
goVTab
));
pvTab
->
vTab
=
vTab
;
*
ppVTab
=
(
sqlite3_vtab
*
)
pvTab
;
*
pzErr
=
NULL
;
return
SQLITE_OK
;
}
static
int
cXCreate
(
sqlite3
*
db
,
void
*
pAux
,
int
argc
,
const
char
*
const
*
argv
,
sqlite3_vtab
**
ppVTab
,
char
**
pzErr
)
{
return
cXInit
(
db
,
pAux
,
argc
,
argv
,
ppVTab
,
pzErr
,
1
);
}
static
int
cXConnect
(
sqlite3
*
db
,
void
*
pAux
,
int
argc
,
const
char
*
const
*
argv
,
sqlite3_vtab
**
ppVTab
,
char
**
pzErr
)
{
return
cXInit
(
db
,
pAux
,
argc
,
argv
,
ppVTab
,
pzErr
,
0
);
}
static
int
cXBestIndex
(
sqlite3_vtab
*
pVTab
,
sqlite3_index_info
*
info
)
{
return
SQLITE_OK
;
}
static
int
cXRelease
(
sqlite3_vtab
*
pVTab
,
int
isDestroy
)
{
char
*
pzErr
=
goMRelease
(((
goVTab
*
)
pVTab
)
->
vTab
,
isDestroy
);
if
(
pzErr
)
{
if
(
pVTab
->
zErrMsg
)
sqlite3_free
(
pVTab
->
zErrMsg
);
pVTab
->
zErrMsg
=
pzErr
;
return
SQLITE_ERROR
;
}
if
(
pVTab
->
zErrMsg
)
sqlite3_free
(
pVTab
->
zErrMsg
);
sqlite3_free
(
pVTab
);
return
SQLITE_OK
;
}
static
int
cXDisconnect
(
sqlite3_vtab
*
pVTab
)
{
return
cXRelease
(
pVTab
,
0
);
}
static
int
cXDestroy
(
sqlite3_vtab
*
pVTab
)
{
return
cXRelease
(
pVTab
,
1
);
}
static
int
cXOpen
(
sqlite3_vtab
*
pVTab
,
sqlite3_vtab_cursor
**
ppCursor
)
{
return
0
;
}
static
int
cXClose
(
sqlite3_vtab_cursor
*
pCursor
)
{
return
0
;
}
static
int
cXFilter
(
sqlite3_vtab_cursor
*
pCursor
,
int
idxNum
,
const
char
*
idxStr
,
int
argc
,
sqlite3_value
**
argv
)
{
return
0
;
}
static
int
cXNext
(
sqlite3_vtab_cursor
*
pCursor
)
{
return
goXNext
(
pCursor
);
}
static
int
cXEof
(
sqlite3_vtab_cursor
*
pCursor
)
{
return
0
;
}
static
int
cXColumn
(
sqlite3_vtab_cursor
*
pCursor
,
sqlite3_context
*
ctx
,
int
i
)
{
return
0
;
}
static
int
cXRowid
(
sqlite3_vtab_cursor
*
pCursor
,
sqlite3_int64
*
pRowid
)
{
return
0
;
}
static
sqlite3_module
goModule
=
{
0
,
/* iVersion */
cXCreate
,
/* xCreate - create a table */
cXConnect
,
/* xConnect - connect to an existing table */
cXBestIndex
,
/* xBestIndex - Determine search strategy */
cXDisconnect
,
/* xDisconnect - Disconnect from a table */
cXDestroy
,
/* xDestroy - Drop a table */
cXOpen
,
/* xOpen - open a cursor */
cXClose
,
/* xClose - close a cursor */
cXFilter
,
/* xFilter - configure scan constraints */
cXNext
,
/* xNext - advance a cursor */
cXEof
,
/* xEof */
cXColumn
,
/* xColumn - read data */
cXRowid
,
/* xRowid - read data */
// TODO
0
,
/* xUpdate - write data */
0
,
/* xBegin - begin transaction */
0
,
/* xSync - sync transaction */
0
,
/* xCommit - commit transaction */
0
,
/* xRollback - rollback transaction */
0
,
/* xFindFunction - function overloading */
0
,
/* xRename - rename the table */
0
,
/* xSavepoint */
0
,
/* xRelease */
0
/* xRollbackTo */
};
int
goSqlite3CreateModule
(
sqlite3
*
db
,
const
char
*
zName
,
void
*
pClientData
)
{
return
sqlite3_create_module_v2
(
db
,
zName
,
&
goModule
,
pClientData
,
goMDestroy
);
}
vtab.go
0 → 100644
View file @
24e630f3
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
sqlite
/*
#include <sqlite3.h>
#include <stdlib.h>
int goSqlite3CreateModule(sqlite3 *db, const char *zName, void *pClientData);
*/
import
"C"
import
(
"reflect"
"unsafe"
)
type
sqliteVTab
struct
{
c
*
Conn
// TODO Useful?
vTab
VTab
}
//export goMInit
func
goMInit
(
db
,
pClientData
unsafe
.
Pointer
,
argc
int
,
argv
**
C
.
char
,
pzErr
**
C
.
char
,
isCreate
int
)
unsafe
.
Pointer
{
udm
:=
(
*
sqliteModule
)(
pClientData
)
if
udm
.
c
.
db
!=
(
*
C
.
sqlite3
)(
db
)
{
*
pzErr
=
mPrintf
(
"%s"
,
"Inconsistent db handles"
)
return
nil
}
args
:=
make
([]
string
,
argc
)
var
A
[]
*
C
.
char
slice
:=
reflect
.
SliceHeader
{
uintptr
(
unsafe
.
Pointer
(
argv
)),
argc
,
argc
}
a
:=
reflect
.
NewAt
(
reflect
.
TypeOf
(
A
),
unsafe
.
Pointer
(
&
slice
))
.
Elem
()
.
Interface
()
for
i
,
s
:=
range
a
.
([]
*
C
.
char
)
{
args
[
i
]
=
C
.
GoString
(
s
)
}
var
vTab
VTab
var
err
error
if
isCreate
==
1
{
vTab
,
err
=
udm
.
module
.
Create
(
udm
.
c
,
args
)
}
else
{
vTab
,
err
=
udm
.
module
.
Connect
(
udm
.
c
,
args
)
}
if
err
!=
nil
{
*
pzErr
=
mPrintf
(
"%s"
,
err
.
Error
())
return
nil
}
udt
:=
&
sqliteVTab
{
udm
.
c
,
vTab
}
*
pzErr
=
nil
return
unsafe
.
Pointer
(
udt
)
}
//export goMRelease
func
goMRelease
(
pVTab
unsafe
.
Pointer
,
isDestroy
int
)
*
C
.
char
{
udt
:=
(
*
sqliteVTab
)(
pVTab
)
var
err
error
if
isDestroy
==
1
{
err
=
udt
.
vTab
.
Destroy
()
}
else
{
err
=
udt
.
vTab
.
Disconnect
()
}
if
err
!=
nil
{
return
mPrintf
(
"%s"
,
err
.
Error
())
}
return
nil
}
//export goMDestroy
func
goMDestroy
(
pClientData
unsafe
.
Pointer
)
{
udm
:=
(
*
sqliteModule
)(
pClientData
)
udm
.
module
.
Destroy
()
delete
(
udm
.
c
.
modules
,
udm
.
name
)
}
//export goXNext
func
goXNext
(
cursor
unsafe
.
Pointer
)
C
.
int
{
//c := (*VTableCursor)(cursor)
return
0
}
type
Module
interface
{
Create
(
c
*
Conn
,
args
[]
string
)
(
VTab
,
error
)
// See http://sqlite.org/vtab.html#xcreate
Connect
(
c
*
Conn
,
args
[]
string
)
(
VTab
,
error
)
// See http://sqlite.org/vtab.html#xconnect
Destroy
()
// See http://sqlite.org/c3ref/create_module.html
}
// (See http://sqlite.org/c3ref/vtab.html)
type
VTab
interface
{
BestIndex
(
/*sqlite3_index_info**/
)
error
// See http://sqlite.org/vtab.html#xbestindex
Disconnect
()
error
// See http://sqlite.org/vtab.html#xdisconnect
Destroy
()
error
// See http://sqlite.org/vtab.html#sqlite3_module.xDestroy
Open
()
(
VTabCursor
,
error
)
// See http://sqlite.org/vtab.html#xopen
}
// (See http://sqlite.org/c3ref/vtab.html)
type
VTabExtended
interface
{
VTab
Update
(
/*int argc, sqlite3_value **argv, */
rowid
int64
)
error
Begin
()
error
Sync
()
error
Commit
()
error
Rollback
()
error
//FindFunction(nArg int, name string /*, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg*/) error
Rename
(
newName
string
)
error
Savepoint
(
i
int
)
error
Release
(
i
int
)
error
RollbackTo
(
i
int
)
error
}
// (See http://sqlite.org/c3ref/vtab_cursor.html)
type
VTabCursor
interface
{
Close
()
error
// See http://sqlite.org/vtab.html#xclose
Filter
(
idxNum
int
,
idxStr
string
/*, int argc, sqlite3_value **argv*/
)
error
// See http://sqlite.org/vtab.html#xfilter
Next
()
error
// See http://sqlite.org/vtab.html#xnext
Eof
()
bool
// See http://sqlite.org/vtab.html#xeof
// col is zero-based so the first column is numbered 0
Column
(
c
*
Context
,
col
int
)
error
// See http://sqlite.org/vtab.html#xcolumn
Rowid
()
(
int64
,
error
)
// See http://sqlite.org/vtab.html#xrowid
}
type
vTabCursor
struct
{
base
*
C
.
sqlite3_vtab_cursor
}
// DeclareVTab declares the Schema of a virtual table.
// (See http://sqlite.org/c3ref/declare_vtab.html)
func
(
c
*
Conn
)
DeclareVTab
(
sql
string
)
error
{
zSQL
:=
C
.
CString
(
sql
)
defer
C
.
free
(
unsafe
.
Pointer
(
zSQL
))
return
c
.
error
(
C
.
sqlite3_declare_vtab
(
c
.
db
,
zSQL
))
}
type
sqliteModule
struct
{
c
*
Conn
name
string
module
Module
}
// CreateModule registers a virtual table implementation.
// (See http://sqlite.org/c3ref/create_module.html)
func
(
c
*
Conn
)
CreateModule
(
moduleName
string
,
module
Module
)
error
{
mname
:=
C
.
CString
(
moduleName
)
defer
C
.
free
(
unsafe
.
Pointer
(
mname
))
// To make sure it is not gced, keep a reference in the connection.
udm
:=
&
sqliteModule
{
c
,
moduleName
,
module
}
if
len
(
c
.
modules
)
==
0
{
c
.
modules
=
make
(
map
[
string
]
*
sqliteModule
)
}
c
.
modules
[
moduleName
]
=
udm
// FIXME What happens if different modules are registered with the same name?
return
c
.
error
(
C
.
goSqlite3CreateModule
(
c
.
db
,
mname
,
unsafe
.
Pointer
(
udm
)))
}
/*
GO C
CreateModule( int sqlite3_create_module_v2(
|- c *Conn |- sqlite3 *db
|- moduleName string |- const char *zName
|- goModule |- const sqlite3_module *p (~) Methods for the module
|- *sqliteModule |- void *pClientData () Client data for xCreate/xConnect
\- goVDestroy \- void(*xDestroy)(void*) () Client data destructor function
) )
goModule sqlite3_module {
|- int iVersion
x |- int (*xCreate)(sqlite3*, void *pAux, int argc, char **argv, sqlite3_vtab **ppVTab,
char **pzErr)
x |- int (*xConnect)(sqlite3*, void *pAux, int argc, char **argv, sqlite3_vtab **ppVTab,
char **pzErr)
x |- int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*)
x |- int (*xDisconnect)(sqlite3_vtab *pVTab)
x |- int (*xDestroy)(sqlite3_vtab *pVTab)
x |- int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor)
x |- int (*xClose)(sqlite3_vtab_cursor*)
x |- int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc,
sqlite3_value **argv)
x |- int (*xNext)(sqlite3_vtab_cursor*)
x |- int (*xEof)(sqlite3_vtab_cursor*)
x |- int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int)
x |- int (*xRowid)(sqlite3_vtab_cursor*, sqlite_int64 *pRowid)
o |- int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite_int64 *)
o |- int (*xBegin)(sqlite3_vtab *pVTab)
o |- int (*xSync)(sqlite3_vtab *pVTab)
o |- int (*xCommit)(sqlite3_vtab *pVTab)
o |- int (*xRollback)(sqlite3_vtab *pVTab)
o |- int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg)
x |- int (*xRename)(sqlite3_vtab *pVtab, const char *zNew)
o |- int (*xSavepoint)(sqlite3_vtab *pVTab, int)
o |- int (*xRelease)(sqlite3_vtab *pVTab, int)
o \- int (*xRollbackTo)(sqlite3_vtab *pVTab, int)
}
int sqlite3_declare_vtab( (Called in xCreate/xConnect)
|- sqlite3 *db,
\- const char *zCreateTable
)
? sqlite3_vtab { (Created by xCreate/xConnect)
|- const sqlite3_module *pModule
|- int nRef
|- char *zErrMsg
\- ...
}
? sqlite3_vtab_cursor { (Created by xOpen)
|- sqlite3_vtab *pVtab
\- ...
}
*/
vtab_test.go
0 → 100644
View file @
24e630f3
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
sqlite_test
import
(
.
"github.com/gwenn/gosqlite"
"testing"
)
type
testModule
struct
{
t
*
testing
.
T
}
type
testVTab
struct
{
}
func
(
m
testModule
)
Create
(
c
*
Conn
,
args
[]
string
)
(
VTab
,
error
)
{
//println("testVTab.Create")
assert
(
m
.
t
,
"Six arguments expected"
,
len
(
args
)
==
6
)
assertEquals
(
m
.
t
,
"Expected '%s' but got '%s' as module name"
,
"test"
,
args
[
0
])
assertEquals
(
m
.
t
,
"Expected '%s' but got '%s' as db name"
,
"main"
,
args
[
1
])
assertEquals
(
m
.
t
,
"Expected '%s' but got '%s' as table name"
,
"vtab"
,
args
[
2
])
assertEquals
(
m
.
t
,
"Expected '%s' but got '%s' as first arg"
,
"'1'"
,
args
[
3
])
assertEquals
(
m
.
t
,
"Expected '%s' but got '%s' as first arg"
,
"2"
,
args
[
4
])
assertEquals
(
m
.
t
,
"Expected '%s' but got '%s' as first arg"
,
"three"
,
args
[
5
])
c
.
DeclareVTab
(
"CREATE TABLE x(test TEXT)"
)
return
testVTab
{},
nil
}
func
(
m
testModule
)
Connect
(
c
*
Conn
,
args
[]
string
)
(
VTab
,
error
)
{
println
(
"testVTab.Connect"
)
return
m
.
Create
(
c
,
args
)
}
func
(
m
testModule
)
Destroy
()
{
//println("testModule.Destroy")
}
func
(
v
testVTab
)
BestIndex
()
error
{
println
(
"testVTab.BestIndex"
)
return
nil
}
func
(
v
testVTab
)
Disconnect
()
error
{
//println("testVTab.Disconnect")
return
nil
}
func
(
v
testVTab
)
Destroy
()
error
{
//println("testVTab.Destroy")
return
nil
}
func
(
v
testVTab
)
Open
()
(
VTabCursor
,
error
)
{
println
(
"testVTab.Open"
)
return
nil
,
nil
}
func
TestCreateModule
(
t
*
testing
.
T
)
{
db
:=
open
(
t
)
defer
db
.
Close
()
err
:=
db
.
CreateModule
(
"test"
,
testModule
{
t
})
checkNoError
(
t
,
err
,
"couldn't create module: %s"
)
err
=
db
.
Exec
(
"CREATE VIRTUAL TABLE vtab USING test('1', 2, three)"
)
checkNoError
(
t
,
err
,
"couldn't create virtual table: %s"
)
err
=
db
.
Exec
(
"DROP TABLE vtab"
)
checkNoError
(
t
,
err
,
"couldn't drop virtual table: %s"
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment