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
c699a930
Commit
c699a930
authored
Nov 03, 2012
by
gwenn
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Small step toward Virtual table support
parent
24e630f3
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
140 additions
and
41 deletions
+140
-41
vtab.c
vtab.c
+27
-3
vtab.go
vtab.go
+78
-36
vtab_test.go
vtab_test.go
+35
-2
No files found.
vtab.c
View file @
c699a930
...
...
@@ -39,11 +39,12 @@ static int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv,
}
static
int
cXBestIndex
(
sqlite3_vtab
*
pVTab
,
sqlite3_index_info
*
info
)
{
// TODO
return
SQLITE_OK
;
}
static
int
cXRelease
(
sqlite3_vtab
*
pVTab
,
int
isDestroy
)
{
char
*
pzErr
=
go
M
Release
(((
goVTab
*
)
pVTab
)
->
vTab
,
isDestroy
);
char
*
pzErr
=
go
V
Release
(((
goVTab
*
)
pVTab
)
->
vTab
,
isDestroy
);
if
(
pzErr
)
{
if
(
pVTab
->
zErrMsg
)
sqlite3_free
(
pVTab
->
zErrMsg
);
...
...
@@ -63,11 +64,34 @@ static int cXDestroy(sqlite3_vtab *pVTab) {
return
cXRelease
(
pVTab
,
1
);
}
typedef
struct
goVTabCursor
goVTabCursor
;
struct
goVTabCursor
{
sqlite3_vtab_cursor
base
;
void
*
vTabCursor
;
};
static
int
cXOpen
(
sqlite3_vtab
*
pVTab
,
sqlite3_vtab_cursor
**
ppCursor
)
{
return
0
;
void
*
vTabCursor
=
goVOpen
(((
goVTab
*
)
pVTab
)
->
vTab
,
&
(
pVTab
->
zErrMsg
));
goVTabCursor
*
pCursor
=
(
goVTabCursor
*
)
sqlite3_malloc
(
sizeof
(
goVTabCursor
));
if
(
!
pCursor
)
{
return
SQLITE_NOMEM
;
}
memset
(
pCursor
,
0
,
sizeof
(
goVTabCursor
));
pCursor
->
vTabCursor
=
vTabCursor
;
*
ppCursor
=
(
sqlite3_vtab_cursor
*
)
pCursor
;
return
SQLITE_OK
;
}
static
int
cXClose
(
sqlite3_vtab_cursor
*
pCursor
)
{
return
0
;
char
*
pzErr
=
goVClose
(((
goVTabCursor
*
)
pCursor
)
->
vTabCursor
);
if
(
pzErr
)
{
if
(
pCursor
->
pVtab
->
zErrMsg
)
sqlite3_free
(
pCursor
->
pVtab
->
zErrMsg
);
pCursor
->
pVtab
->
zErrMsg
=
pzErr
;
return
SQLITE_ERROR
;
}
sqlite3_free
(
pCursor
);
return
SQLITE_OK
;
}
static
int
cXFilter
(
sqlite3_vtab_cursor
*
pCursor
,
int
idxNum
,
const
char
*
idxStr
,
int
argc
,
sqlite3_value
**
argv
)
{
return
0
;
...
...
vtab.go
View file @
c699a930
...
...
@@ -17,15 +17,28 @@ import (
"unsafe"
)
type
sqliteModule
struct
{
c
*
Conn
name
string
module
Module
vts
map
[
*
sqliteVTab
]
bool
}
type
sqliteVTab
struct
{
c
*
Conn
// TODO Useful?
vTab
VTab
module
*
sqliteModule
vTab
VTab
vtcs
map
[
*
sqliteVTabCursor
]
bool
}
type
sqliteVTabCursor
struct
{
vTab
*
sqliteVTab
vTabCursor
VTabCursor
}
//export goMInit
func
goMInit
(
db
,
pClientData
unsafe
.
Pointer
,
argc
int
,
argv
**
C
.
char
,
pzErr
**
C
.
char
,
isCreate
int
)
unsafe
.
Pointer
{
ud
m
:=
(
*
sqliteModule
)(
pClientData
)
if
ud
m
.
c
.
db
!=
(
*
C
.
sqlite3
)(
db
)
{
m
:=
(
*
sqliteModule
)(
pClientData
)
if
m
.
c
.
db
!=
(
*
C
.
sqlite3
)(
db
)
{
*
pzErr
=
mPrintf
(
"%s"
,
"Inconsistent db handles"
)
return
nil
}
...
...
@@ -39,45 +52,84 @@ func goMInit(db, pClientData unsafe.Pointer, argc int, argv **C.char, pzErr **C.
var
vTab
VTab
var
err
error
if
isCreate
==
1
{
vTab
,
err
=
udm
.
module
.
Create
(
ud
m
.
c
,
args
)
vTab
,
err
=
m
.
module
.
Create
(
m
.
c
,
args
)
}
else
{
vTab
,
err
=
udm
.
module
.
Connect
(
ud
m
.
c
,
args
)
vTab
,
err
=
m
.
module
.
Connect
(
m
.
c
,
args
)
}
if
err
!=
nil
{
*
pzErr
=
mPrintf
(
"%s"
,
err
.
Error
())
return
nil
}
udt
:=
&
sqliteVTab
{
udm
.
c
,
vTab
}
vt
:=
&
sqliteVTab
{
m
,
vTab
,
nil
}
// prevents 'vt' from being gced
if
m
.
vts
==
nil
{
m
.
vts
=
make
(
map
[
*
sqliteVTab
]
bool
)
}
m
.
vts
[
vt
]
=
true
*
pzErr
=
nil
return
unsafe
.
Pointer
(
ud
t
)
return
unsafe
.
Pointer
(
v
t
)
}
//export go
M
Release
func
go
M
Release
(
pVTab
unsafe
.
Pointer
,
isDestroy
int
)
*
C
.
char
{
ud
t
:=
(
*
sqliteVTab
)(
pVTab
)
//export go
V
Release
func
go
V
Release
(
pVTab
unsafe
.
Pointer
,
isDestroy
int
)
*
C
.
char
{
v
t
:=
(
*
sqliteVTab
)(
pVTab
)
var
err
error
if
isDestroy
==
1
{
err
=
ud
t
.
vTab
.
Destroy
()
err
=
v
t
.
vTab
.
Destroy
()
}
else
{
err
=
ud
t
.
vTab
.
Disconnect
()
err
=
v
t
.
vTab
.
Disconnect
()
}
if
err
!=
nil
{
return
mPrintf
(
"%s"
,
err
.
Error
())
}
// TODO Check vt.vtcs is empty
vt
.
vtcs
=
nil
delete
(
vt
.
module
.
vts
,
vt
)
return
nil
}
//export goVOpen
func
goVOpen
(
pVTab
unsafe
.
Pointer
,
pzErr
**
C
.
char
)
unsafe
.
Pointer
{
vt
:=
(
*
sqliteVTab
)(
pVTab
)
vTabCursor
,
err
:=
vt
.
vTab
.
Open
()
if
err
!=
nil
{
*
pzErr
=
mPrintf
(
"%s"
,
err
.
Error
())
return
nil
}
// prevents 'vt' from being gced
vtc
:=
&
sqliteVTabCursor
{
vt
,
vTabCursor
}
if
vt
.
vtcs
==
nil
{
vt
.
vtcs
=
make
(
map
[
*
sqliteVTabCursor
]
bool
)
}
vt
.
vtcs
[
vtc
]
=
true
*
pzErr
=
nil
return
unsafe
.
Pointer
(
vtc
)
}
//export goVClose
func
goVClose
(
pCursor
unsafe
.
Pointer
)
*
C
.
char
{
vtc
:=
(
*
sqliteVTabCursor
)(
pCursor
)
err
:=
vtc
.
vTabCursor
.
Close
()
if
err
!=
nil
{
return
mPrintf
(
"%s"
,
err
.
Error
())
}
delete
(
vtc
.
vTab
.
vtcs
,
vtc
)
return
nil
}
//export goMDestroy
func
goMDestroy
(
pClientData
unsafe
.
Pointer
)
{
udm
:=
(
*
sqliteModule
)(
pClientData
)
udm
.
module
.
Destroy
()
delete
(
udm
.
c
.
modules
,
udm
.
name
)
m
:=
(
*
sqliteModule
)(
pClientData
)
m
.
module
.
Destroy
()
// TODO Check m.vts is empty
m
.
vts
=
nil
delete
(
m
.
c
.
modules
,
m
.
name
)
}
//export goXNext
func
goXNext
(
c
ursor
unsafe
.
Pointer
)
C
.
int
{
//
c := (*VTableCursor)(c
ursor)
func
goXNext
(
pC
ursor
unsafe
.
Pointer
)
C
.
int
{
//
vtc := (*sqliteVTabCursor)(pC
ursor)
return
0
}
...
...
@@ -124,10 +176,6 @@ type VTabCursor interface {
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
{
...
...
@@ -136,19 +184,13 @@ func (c *Conn) DeclareVTab(sql string) error {
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
}
udm
:=
&
sqliteModule
{
c
,
moduleName
,
module
,
nil
}
if
len
(
c
.
modules
)
==
0
{
c
.
modules
=
make
(
map
[
string
]
*
sqliteModule
)
}
...
...
@@ -168,15 +210,15 @@ CreateModule( int sqlite3_create_module_v2(
goModule sqlite3_module {
|- int iVersion
x
|- int (*xCreate)(sqlite3*, void *pAux, int argc, char **argv, sqlite3_vtab **ppVTab,
goMInit
|- 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,
goMInit
|- 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*)
goVRelease
|- int (*xDisconnect)(sqlite3_vtab *pVTab)
goVRelease
|- int (*xDestroy)(sqlite3_vtab *pVTab)
goVOpen
|- int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor)
goVClose
|- 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*)
...
...
@@ -201,7 +243,7 @@ o \- int (*xRollbackTo)(sqlite3_vtab *pVTab,
\- const char *zCreateTable
)
?
sqlite3_vtab { (Created by xCreate/xConnect)
sqliteVTab
sqlite3_vtab { (Created by xCreate/xConnect)
|- const sqlite3_module *pModule
|- int nRef
|- char *zErrMsg
...
...
vtab_test.go
View file @
c699a930
...
...
@@ -16,6 +16,9 @@ type testModule struct {
type
testVTab
struct
{
}
type
testVTabCursor
struct
{
}
func
(
m
testModule
)
Create
(
c
*
Conn
,
args
[]
string
)
(
VTab
,
error
)
{
//println("testVTab.Create")
assert
(
m
.
t
,
"Six arguments expected"
,
len
(
args
)
==
6
)
...
...
@@ -50,8 +53,33 @@ func (v testVTab) Destroy() error {
return
nil
}
func
(
v
testVTab
)
Open
()
(
VTabCursor
,
error
)
{
println
(
"testVTab.Open"
)
return
nil
,
nil
//println("testVTab.Open")
return
testVTabCursor
{},
nil
}
func
(
v
testVTabCursor
)
Close
()
error
{
//println("testVTabCursor.Close")
return
nil
}
func
(
v
testVTabCursor
)
Filter
(
idxNum
int
,
idxStr
string
/*, int argc, sqlite3_value **argv*/
)
error
{
println
(
"testVTabCursor.Filter"
)
return
nil
}
func
(
v
testVTabCursor
)
Next
()
error
{
println
(
"testVTabCursor.Next"
)
return
nil
}
func
(
v
testVTabCursor
)
Eof
()
bool
{
println
(
"testVTabCursor.Eof"
)
return
true
}
func
(
v
testVTabCursor
)
Column
(
c
*
Context
,
col
int
)
error
{
println
(
"testVTabCursor.Column"
)
return
nil
}
func
(
v
testVTabCursor
)
Rowid
()
(
int64
,
error
)
{
println
(
"testVTabCursor.Rowid"
)
return
1
,
nil
}
func
TestCreateModule
(
t
*
testing
.
T
)
{
...
...
@@ -61,6 +89,11 @@ func TestCreateModule(t *testing.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"
)
var
value
*
string
err
=
db
.
OneValue
(
"SELECT * from vtab"
,
&
value
)
checkNoError
(
t
,
err
,
"couldn't select from virtual table: %s"
)
//assert(t, "Not null value expected", value != nil)
//assertEquals(t, "Expected '%s' but got '%s'", "test", *value)
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