Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add support for defining an "eponymous only" virtual table (#885)
* add support for defining an "eponymous only" virtual table As suggested here: #846 (comment) * add an example of an eponymous only vtab module * add a test case for an eponymous only vtab module
- Loading branch information
1 parent
66ff625
commit 92d2371
Showing
4 changed files
with
325 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package main | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
"log" | ||
|
||
"github.com/mattn/go-sqlite3" | ||
) | ||
|
||
func main() { | ||
sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{ | ||
ConnectHook: func(conn *sqlite3.SQLiteConn) error { | ||
return conn.CreateModule("series", &seriesModule{}) | ||
}, | ||
}) | ||
db, err := sql.Open("sqlite3_with_extensions", ":memory:") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer db.Close() | ||
|
||
rows, err := db.Query("select * from series") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer rows.Close() | ||
for rows.Next() { | ||
var value int | ||
rows.Scan(&value) | ||
fmt.Printf("value: %d\n", value) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/mattn/go-sqlite3" | ||
) | ||
|
||
type seriesModule struct{} | ||
|
||
func (m *seriesModule) EponymousOnlyModule() {} | ||
|
||
func (m *seriesModule) Create(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) { | ||
err := c.DeclareVTab(fmt.Sprintf(` | ||
CREATE TABLE %s ( | ||
value INT, | ||
start HIDDEN, | ||
stop HIDDEN, | ||
step HIDDEN | ||
)`, args[0])) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &seriesTable{0, 0, 1}, nil | ||
} | ||
|
||
func (m *seriesModule) Connect(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) { | ||
return m.Create(c, args) | ||
} | ||
|
||
func (m *seriesModule) DestroyModule() {} | ||
|
||
type seriesTable struct { | ||
start int64 | ||
stop int64 | ||
step int64 | ||
} | ||
|
||
func (v *seriesTable) Open() (sqlite3.VTabCursor, error) { | ||
return &seriesCursor{v, 0}, nil | ||
} | ||
|
||
func (v *seriesTable) BestIndex(csts []sqlite3.InfoConstraint, ob []sqlite3.InfoOrderBy) (*sqlite3.IndexResult, error) { | ||
used := make([]bool, len(csts)) | ||
for c, cst := range csts { | ||
if cst.Usable && cst.Op == sqlite3.OpEQ { | ||
used[c] = true | ||
} | ||
} | ||
|
||
return &sqlite3.IndexResult{ | ||
IdxNum: 0, | ||
IdxStr: "default", | ||
Used: used, | ||
}, nil | ||
} | ||
|
||
func (v *seriesTable) Disconnect() error { return nil } | ||
func (v *seriesTable) Destroy() error { return nil } | ||
|
||
type seriesCursor struct { | ||
*seriesTable | ||
value int64 | ||
} | ||
|
||
func (vc *seriesCursor) Column(c *sqlite3.SQLiteContext, col int) error { | ||
switch col { | ||
case 0: | ||
c.ResultInt64(vc.value) | ||
case 1: | ||
c.ResultInt64(vc.seriesTable.start) | ||
case 2: | ||
c.ResultInt64(vc.seriesTable.stop) | ||
case 3: | ||
c.ResultInt64(vc.seriesTable.step) | ||
} | ||
return nil | ||
} | ||
|
||
func (vc *seriesCursor) Filter(idxNum int, idxStr string, vals []interface{}) error { | ||
switch { | ||
case len(vals) < 1: | ||
vc.seriesTable.start = 0 | ||
vc.seriesTable.stop = 1000 | ||
vc.value = vc.seriesTable.start | ||
case len(vals) < 2: | ||
vc.seriesTable.start = vals[0].(int64) | ||
vc.seriesTable.stop = 1000 | ||
vc.value = vc.seriesTable.start | ||
case len(vals) < 3: | ||
vc.seriesTable.start = vals[0].(int64) | ||
vc.seriesTable.stop = vals[1].(int64) | ||
vc.value = vc.seriesTable.start | ||
case len(vals) < 4: | ||
vc.seriesTable.start = vals[0].(int64) | ||
vc.seriesTable.stop = vals[1].(int64) | ||
vc.seriesTable.step = vals[2].(int64) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (vc *seriesCursor) Next() error { | ||
vc.value += vc.step | ||
return nil | ||
} | ||
|
||
func (vc *seriesCursor) EOF() bool { | ||
return vc.value > vc.stop | ||
} | ||
|
||
func (vc *seriesCursor) Rowid() (int64, error) { | ||
return int64(vc.value), nil | ||
} | ||
|
||
func (vc *seriesCursor) Close() error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters