From 960d6a342ac848cabaee090656a2ae54d6cb1f13 Mon Sep 17 00:00:00 2001 From: Philip O'Toole Date: Sun, 28 Feb 2016 11:46:49 -0800 Subject: Alphabetical imports --- _example/hook/hook.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to '_example') diff --git a/_example/hook/hook.go b/_example/hook/hook.go index 3059f9e..c9f41a2 100644 --- a/_example/hook/hook.go +++ b/_example/hook/hook.go @@ -2,9 +2,10 @@ package main import ( "database/sql" - "github.com/mattn/go-sqlite3" "log" "os" + + "github.com/mattn/go-sqlite3" ) func main() { -- cgit v1.2.3 From baa815b31d0c13138a18524f23f4a2dab96d8273 Mon Sep 17 00:00:00 2001 From: Philip O'Toole Date: Sun, 28 Feb 2016 11:47:07 -0800 Subject: Fix reversed source and destination names --- _example/hook/hook.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to '_example') diff --git a/_example/hook/hook.go b/_example/hook/hook.go index c9f41a2..17bddeb 100644 --- a/_example/hook/hook.go +++ b/_example/hook/hook.go @@ -20,35 +20,35 @@ func main() { os.Remove("./foo.db") os.Remove("./bar.db") - destDb, err := sql.Open("sqlite3_with_hook_example", "./foo.db") + srcDb, err := sql.Open("sqlite3_with_hook_example", "./foo.db") if err != nil { log.Fatal(err) } - defer destDb.Close() - destDb.Ping() + defer srcDb.Close() + srcDb.Ping() - _, err = destDb.Exec("create table foo(id int, value text)") + _, err = srcDb.Exec("create table foo(id int, value text)") if err != nil { log.Fatal(err) } - _, err = destDb.Exec("insert into foo values(1, 'foo')") + _, err = srcDb.Exec("insert into foo values(1, 'foo')") if err != nil { log.Fatal(err) } - _, err = destDb.Exec("insert into foo values(2, 'bar')") + _, err = srcDb.Exec("insert into foo values(2, 'bar')") if err != nil { log.Fatal(err) } - _, err = destDb.Query("select * from foo") + _, err = srcDb.Query("select * from foo") if err != nil { log.Fatal(err) } - srcDb, err := sql.Open("sqlite3_with_hook_example", "./bar.db") + destDb, err := sql.Open("sqlite3_with_hook_example", "./bar.db") if err != nil { log.Fatal(err) } - defer srcDb.Close() - srcDb.Ping() + defer destDb.Close() + destDb.Ping() bk, err := sqlite3conn[1].Backup("main", sqlite3conn[0], "main") if err != nil { -- cgit v1.2.3 From ed211752885a3e9a33d39e12e8d0fa46c12d85fa Mon Sep 17 00:00:00 2001 From: Stani Date: Thu, 14 Apr 2016 20:56:02 +0200 Subject: add missing error checking to simple example --- _example/simple/simple.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to '_example') diff --git a/_example/simple/simple.go b/_example/simple/simple.go index 6ab8d25..261ed4d 100644 --- a/_example/simple/simple.go +++ b/_example/simple/simple.go @@ -52,9 +52,16 @@ func main() { for rows.Next() { var id int var name string - rows.Scan(&id, &name) + err = rows.Scan(&id, &name) + if err != nil { + log.Fatal(err) + } fmt.Println(id, name) } + err = rows.Err() + if err != nil { + log.Fatal(err) + } stmt, err = db.Prepare("select name from foo where id = ?") if err != nil { @@ -86,7 +93,14 @@ func main() { for rows.Next() { var id int var name string - rows.Scan(&id, &name) + err = rows.Scan(&id, &name) + if err != nil { + log.Fatal(err) + } fmt.Println(id, name) } + err = rows.Err() + if err != nil { + log.Fatal(err) + } } -- cgit v1.2.3 From 17a684694a3f713dc3df68893c1d29137d62efc9 Mon Sep 17 00:00:00 2001 From: "A.N" Date: Tue, 6 Sep 2016 23:13:30 +0300 Subject: Example program for the new SetTrace() Does INSERT, then SELECT on the inserted rows (in-memory database). The purpose of all these is to cause activity so there will be trace messages to display. Trace message formatting is included (a useful format, with explanations). --- _example/trace/main.go | 264 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 _example/trace/main.go (limited to '_example') diff --git a/_example/trace/main.go b/_example/trace/main.go new file mode 100644 index 0000000..6a2953f --- /dev/null +++ b/_example/trace/main.go @@ -0,0 +1,264 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + "os" + + sqlite3 "github.com/gimpldo/go-sqlite3" +) + +func traceCallback(info sqlite3.TraceInfo) int { + // Not very readable but may be useful; uncomment next line in case of doubt: + //fmt.Printf("Trace: %#v\n", info) + + var dbErrText string + if info.DBError.Code != 0 || info.DBError.ExtendedCode != 0 { + dbErrText = fmt.Sprintf("; DB error: %#v", info.DBError) + } else { + dbErrText = "." + } + + // Show the Statement-or-Trigger text in curly braces ('{', '}') + // since from the *paired* ASCII characters they are + // the least used in SQL syntax, therefore better visual delimiters. + // Maybe show 'ExpandedSQL' the same way as 'StmtOrTrigger'. + // + // A known use of curly braces (outside strings) is + // for ODBC escape sequences. Not likely to appear here. + // + // Template languages, etc. don't matter, we should see their *result* + // at *this* level. + // Strange curly braces in SQL code that reached the database driver + // suggest that there is a bug in the application. + // The braces are likely to be either template syntax or + // a programming language's string interpolation syntax. + + var expandedText string + if info.ExpandedSQL != "" { + if info.ExpandedSQL == info.StmtOrTrigger { + expandedText = " = exp" + } else { + expandedText = fmt.Sprintf(" expanded {%q}", info.ExpandedSQL) + } + } else { + expandedText = "" + } + + // SQLite docs as of September 6, 2016: Tracing and Profiling Functions + // https://www.sqlite.org/c3ref/profile.html + // + // The profile callback time is in units of nanoseconds, however + // the current implementation is only capable of millisecond resolution + // so the six least significant digits in the time are meaningless. + // Future versions of SQLite might provide greater resolution on the profiler callback. + + var runTimeText string + if info.RunTimeNanosec == 0 { + if info.EventCode == sqlite3.TraceProfile { + //runTimeText = "; no time" // seems confusing + runTimeText = "; time 0" // no measurement unit + } else { + //runTimeText = "; no time" // seems useless and confusing + } + } else { + const nanosPerMillisec = 1000000 + if info.RunTimeNanosec%nanosPerMillisec == 0 { + runTimeText = fmt.Sprintf("; time %d ms", info.RunTimeNanosec/nanosPerMillisec) + } else { + // unexpected: better than millisecond resolution + runTimeText = fmt.Sprintf("; time %d ns!!!", info.RunTimeNanosec) + } + } + + var modeText string + if info.AutoCommit { + modeText = "-AC-" + } else { + modeText = "+Tx+" + } + + fmt.Printf("Trace: ev %d %s conn 0x%x, stmt 0x%x {%q}%s%s%s\n", + info.EventCode, modeText, info.ConnHandle, info.StmtHandle, + info.StmtOrTrigger, expandedText, + runTimeText, + dbErrText) + return 0 +} + +func main() { + eventMask := sqlite3.TraceStmt | sqlite3.TraceProfile | sqlite3.TraceRow | sqlite3.TraceClose + + sql.Register("sqlite3_tracing", + &sqlite3.SQLiteDriver{ + ConnectHook: func(conn *sqlite3.SQLiteConn) error { + err := conn.SetTrace(&sqlite3.TraceConfig{ + Callback: traceCallback, + EventMask: uint(eventMask), + WantExpandedSQL: true, + }) + return err + }, + }) + + os.Exit(dbMain()) +} + +// Harder to do DB work in main(). +// It's better with a separate function because +// 'defer' and 'os.Exit' don't go well together. +// +// DO NOT use 'log.Fatal...' below: remember that it's equivalent to +// Print() followed by a call to os.Exit(1) --- and +// we want to avoid Exit() so 'defer' can do cleanup. +// Use 'log.Panic...' instead. + +func dbMain() int { + db, err := sql.Open("sqlite3_tracing", ":memory:") + if err != nil { + fmt.Printf("Failed to open database: %#+v\n", err) + return 1 + } + defer db.Close() + + err = db.Ping() + if err != nil { + log.Panic(err) + } + + dbSetup(db) + + dbDoInsert(db) + dbDoInsertPrepared(db) + dbDoSelect(db) + dbDoSelectPrepared(db) + + return 0 +} + +// 'DDL' stands for "Data Definition Language": + +// Note: "INTEGER PRIMARY KEY NOT NULL AUTOINCREMENT" causes the error +// 'near "AUTOINCREMENT": syntax error'; without "NOT NULL" it works. +const tableDDL = `CREATE TABLE t1 ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + note VARCHAR NOT NULL +)` + +// 'DML' stands for "Data Manipulation Language": + +const insertDML = "INSERT INTO t1 (note) VALUES (?)" +const selectDML = "SELECT id, note FROM t1 WHERE note LIKE ?" + +const textPrefix = "bla-1234567890-" +const noteTextPattern = "%Prep%" + +const nGenRows = 4 // Number of Rows to Generate (for *each* approach tested) + +func dbSetup(db *sql.DB) { + var err error + + _, err = db.Exec("DROP TABLE IF EXISTS t1") + if err != nil { + log.Panic(err) + } + _, err = db.Exec(tableDDL) + if err != nil { + log.Panic(err) + } +} + +func dbDoInsert(db *sql.DB) { + const Descr = "DB-Exec" + for i := 0; i < nGenRows; i++ { + result, err := db.Exec(insertDML, textPrefix+Descr) + if err != nil { + log.Panic(err) + } + + resultDoCheck(result, Descr, i) + } +} + +func dbDoInsertPrepared(db *sql.DB) { + const Descr = "DB-Prepare" + + stmt, err := db.Prepare(insertDML) + if err != nil { + log.Panic(err) + } + defer stmt.Close() + + for i := 0; i < nGenRows; i++ { + result, err := stmt.Exec(textPrefix + Descr) + if err != nil { + log.Panic(err) + } + + resultDoCheck(result, Descr, i) + } +} + +func resultDoCheck(result sql.Result, callerDescr string, callIndex int) { + lastID, err := result.LastInsertId() + if err != nil { + log.Panic(err) + } + nAffected, err := result.RowsAffected() + if err != nil { + log.Panic(err) + } + + log.Printf("Exec result for %s (%d): ID = %d, affected = %d\n", callerDescr, callIndex, lastID, nAffected) +} + +func dbDoSelect(db *sql.DB) { + const Descr = "DB-Query" + + rows, err := db.Query(selectDML, noteTextPattern) + if err != nil { + log.Panic(err) + } + defer rows.Close() + + rowsDoFetch(rows, Descr) +} + +func dbDoSelectPrepared(db *sql.DB) { + const Descr = "DB-Prepare" + + stmt, err := db.Prepare(selectDML) + if err != nil { + log.Panic(err) + } + defer stmt.Close() + + rows, err := stmt.Query(noteTextPattern) + if err != nil { + log.Panic(err) + } + defer rows.Close() + + rowsDoFetch(rows, Descr) +} + +func rowsDoFetch(rows *sql.Rows, callerDescr string) { + var nRows int + var id int64 + var note string + + for rows.Next() { + err := rows.Scan(&id, ¬e) + if err != nil { + log.Panic(err) + } + log.Printf("Row for %s (%d): id=%d, note=%q\n", + callerDescr, nRows, id, note) + nRows++ + } + if err := rows.Err(); err != nil { + log.Panic(err) + } + log.Printf("Total %d rows for %s.\n", nRows, callerDescr) +} -- cgit v1.2.3 From 341bfcf7f19e6c3d3df8cd2ce6342a8b2125bbb0 Mon Sep 17 00:00:00 2001 From: Graeme Connell Date: Fri, 11 Nov 2016 09:50:05 -0700 Subject: Fix example import to point to mattn repo. --- _example/trace/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to '_example') diff --git a/_example/trace/main.go b/_example/trace/main.go index 6a2953f..9f83ee1 100644 --- a/_example/trace/main.go +++ b/_example/trace/main.go @@ -6,7 +6,7 @@ import ( "log" "os" - sqlite3 "github.com/gimpldo/go-sqlite3" + sqlite3 "github.com/mattn/go-sqlite3" ) func traceCallback(info sqlite3.TraceInfo) int { -- cgit v1.2.3 From efea85cb9a06f1d4f661649f6beb5fd04597a366 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 10 Jan 2017 00:40:58 +0900 Subject: fixes #368 --- _example/trace/main.go | 2 ++ 1 file changed, 2 insertions(+) (limited to '_example') diff --git a/_example/trace/main.go b/_example/trace/main.go index 9f83ee1..269e452 100644 --- a/_example/trace/main.go +++ b/_example/trace/main.go @@ -1,3 +1,5 @@ +// +build trace + package main import ( -- cgit v1.2.3 From b59c804b1dae401831c402e3337ca2a0f9df1552 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 11 Jan 2017 01:18:51 +0900 Subject: dummy constants --- _example/trace/main.go | 2 -- tracecallback_noimpl.go | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to '_example') diff --git a/_example/trace/main.go b/_example/trace/main.go index 269e452..9f83ee1 100644 --- a/_example/trace/main.go +++ b/_example/trace/main.go @@ -1,5 +1,3 @@ -// +build trace - package main import ( diff --git a/tracecallback_noimpl.go b/tracecallback_noimpl.go index f270415..09b55d0 100644 --- a/tracecallback_noimpl.go +++ b/tracecallback_noimpl.go @@ -4,7 +4,20 @@ package sqlite3 import "errors" +// Trace... constants identify the possible events causing callback invocation. +// Values are same as the corresponding SQLite Trace Event Codes. +const ( + TraceStmt = uint32(0x01) + TraceProfile = uint32(0x02) + TraceRow = uint32(0x04) + TraceClose = uint32(0x08) +) + // RegisterAggregator register the aggregator. func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool) error { return errors.New("This feature is not implemented") } + +func (c *SQLiteConn) SetTrace(requested *TraceConfig) error { + return errors.New("This feature is not implemented") +} -- cgit v1.2.3 From 618e784627e2d0c0883f92c1708de3107296a0f9 Mon Sep 17 00:00:00 2001 From: Conor Branagan Date: Sun, 11 Dec 2016 12:49:48 -0500 Subject: [vtable] Add pure Go example of GitHub repo vtable. --- _example/vtable/main.go | 37 ++++++++++++++++ _example/vtable/vtable.go | 110 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 _example/vtable/main.go create mode 100644 _example/vtable/vtable.go (limited to '_example') diff --git a/_example/vtable/main.go b/_example/vtable/main.go new file mode 100644 index 0000000..442069f --- /dev/null +++ b/_example/vtable/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "database/sql" + "fmt" + "github.com/mattn/go-sqlite3" + "log" +) + +func main() { + sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{ + ConnectHook: func(conn *sqlite3.SQLiteConn) error { + return conn.CreateModule("github", githubModule{}) + }, + }) + db, err := sql.Open("sqlite3_with_extensions", ":memory:") + if err != nil { + log.Fatal(err) + } + defer db.Close() + + _, err = db.Exec("create virtual table repo using github(id, full_name, description, html_url)") + if err != nil { + log.Fatal(err) + } + + rows, err := db.Query("select id, full_name, description, html_url from repo") + if err != nil { + log.Fatal(err) + } + defer rows.Close() + for rows.Next() { + var id, full_name, description, html_url string + rows.Scan(&id, &full_name, &description, &html_url) + fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, full_name, description, html_url) + } +} diff --git a/_example/vtable/vtable.go b/_example/vtable/vtable.go new file mode 100644 index 0000000..cc0f308 --- /dev/null +++ b/_example/vtable/vtable.go @@ -0,0 +1,110 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/mattn/go-sqlite3" + "io/ioutil" + "net/http" +) + +type GithubRepo struct { + ID int `json:"id"` + FullName string `json:"full_name"` + Description string `json:"description"` + HtmlURL string `json:"html_url"` +} + +type githubModule struct { +} + +func (m githubModule) Create(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) { + err := c.DeclareVTab(fmt.Sprintf(` + CREATE TABLE %s ( + id INT, + full_name TEXT, + description TEXT, + html_url TEXT + )`, args[0])) + if err != nil { + return nil, err + } + return &ghRepoTable{}, nil +} + +func (m githubModule) Connect(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) { + return m.Create(c, args) +} + +func (m githubModule) DestroyModule() {} + +type ghRepoTable struct { + repos []GithubRepo +} + +func (v *ghRepoTable) Open() (sqlite3.VTabCursor, error) { + resp, err := http.Get("https://api.github.com/repositories") + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + repos := make([]GithubRepo, 0) + if err := json.Unmarshal(body, &repos); err != nil { + return nil, err + } + return &ghRepoCursor{0, repos}, nil +} + +func (v *ghRepoTable) BestIndex(cst []sqlite3.InfoConstraint, ob []sqlite3.InfoOrderBy) (*sqlite3.IndexResult, error) { + return &sqlite3.IndexResult{}, nil +} + +func (v *ghRepoTable) Disconnect() error { return nil } +func (v *ghRepoTable) Destroy() error { return nil } + +type ghRepoCursor struct { + index int + repos []GithubRepo +} + +func (vc *ghRepoCursor) Column(c *sqlite3.Context, col int) error { + switch col { + case 0: + c.ResultInt(vc.repos[vc.index].ID) + case 1: + c.ResultText(vc.repos[vc.index].FullName) + case 2: + c.ResultText(vc.repos[vc.index].Description) + case 3: + c.ResultText(vc.repos[vc.index].HtmlURL) + } + return nil +} + +func (vc *ghRepoCursor) Filter(idxNum int, idxStr string, vals []interface{}) error { + vc.index = 0 + return nil +} + +func (vc *ghRepoCursor) Next() error { + vc.index++ + return nil +} + +func (vc *ghRepoCursor) EOF() bool { + return vc.index >= len(vc.repos) +} + +func (vc *ghRepoCursor) Rowid() (int64, error) { + return int64(vc.index), nil +} + +func (vc *ghRepoCursor) Close() error { + return nil +} -- cgit v1.2.3 From 9efa963d05cac8b780d1cb3abbd8493a94f1db82 Mon Sep 17 00:00:00 2001 From: Conor Branagan Date: Sat, 4 Mar 2017 18:15:00 -0500 Subject: [vtable] Rename Context to SQLiteContext To not conflict with core "context" package naming. --- _example/vtable/vtable.go | 4 +- context.go | 103 ---------------------------------------------- sqlite_context.go | 103 ++++++++++++++++++++++++++++++++++++++++++++++ vtable.go | 4 +- vtable_test.go | 2 +- 5 files changed, 108 insertions(+), 108 deletions(-) delete mode 100644 context.go create mode 100644 sqlite_context.go (limited to '_example') diff --git a/_example/vtable/vtable.go b/_example/vtable/vtable.go index cc0f308..13e2624 100644 --- a/_example/vtable/vtable.go +++ b/_example/vtable/vtable.go @@ -3,7 +3,7 @@ package main import ( "encoding/json" "fmt" - "github.com/mattn/go-sqlite3" + "github.com/DataDog/go-sqlite3" "io/ioutil" "net/http" ) @@ -73,7 +73,7 @@ type ghRepoCursor struct { repos []GithubRepo } -func (vc *ghRepoCursor) Column(c *sqlite3.Context, col int) error { +func (vc *ghRepoCursor) Column(c *sqlite3.SQLiteContext, col int) error { switch col { case 0: c.ResultInt(vc.repos[vc.index].ID) diff --git a/context.go b/context.go deleted file mode 100644 index ba943da..0000000 --- a/context.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (C) 2014 Yasuhiro Matsumoto . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package sqlite3 - -/* - -#ifndef USE_LIBSQLITE3 -#include -#else -#include -#endif -#include -// These wrappers are necessary because SQLITE_TRANSIENT -// is a pointer constant, and cgo doesn't translate them correctly. - -static inline void my_result_text(sqlite3_context *ctx, char *p, int np) { - sqlite3_result_text(ctx, p, np, SQLITE_TRANSIENT); -} - -static inline void my_result_blob(sqlite3_context *ctx, void *p, int np) { - sqlite3_result_blob(ctx, p, np, SQLITE_TRANSIENT); -} -*/ -import "C" - -import ( - "math" - "reflect" - "unsafe" -) - -const i64 = unsafe.Sizeof(int(0)) > 4 - -type ZeroBlobLength int32 -type Context C.sqlite3_context - -// ResultBool sets the result of an SQL function. -func (c *Context) ResultBool(b bool) { - if b { - c.ResultInt(1) - } else { - c.ResultInt(0) - } -} - -// ResultBlob sets the result of an SQL function. -// See: sqlite3_result_blob, http://sqlite.org/c3ref/result_blob.html -func (c *Context) ResultBlob(b []byte) { - if i64 && len(b) > math.MaxInt32 { - C.sqlite3_result_error_toobig((*C.sqlite3_context)(c)) - return - } - var p *byte - if len(b) > 0 { - p = &b[0] - } - C.my_result_blob((*C.sqlite3_context)(c), unsafe.Pointer(p), C.int(len(b))) -} - -// ResultDouble sets the result of an SQL function. -// See: sqlite3_result_double, http://sqlite.org/c3ref/result_blob.html -func (c *Context) ResultDouble(d float64) { - C.sqlite3_result_double((*C.sqlite3_context)(c), C.double(d)) -} - -// ResultInt sets the result of an SQL function. -// See: sqlite3_result_int, http://sqlite.org/c3ref/result_blob.html -func (c *Context) ResultInt(i int) { - if i64 && (i > math.MaxInt32 || i < math.MinInt32) { - C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i)) - } else { - C.sqlite3_result_int((*C.sqlite3_context)(c), C.int(i)) - } -} - -// ResultInt64 sets the result of an SQL function. -// See: sqlite3_result_int64, http://sqlite.org/c3ref/result_blob.html -func (c *Context) ResultInt64(i int64) { - C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i)) -} - -// ResultNull sets the result of an SQL function. -// See: sqlite3_result_null, http://sqlite.org/c3ref/result_blob.html -func (c *Context) ResultNull() { - C.sqlite3_result_null((*C.sqlite3_context)(c)) -} - -// ResultText sets the result of an SQL function. -// See: sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html -func (c *Context) ResultText(s string) { - h := (*reflect.StringHeader)(unsafe.Pointer(&s)) - cs, l := (*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len) - C.my_result_text((*C.sqlite3_context)(c), cs, l) -} - -// ResultZeroblob sets the result of an SQL function. -// See: sqlite3_result_zeroblob, http://sqlite.org/c3ref/result_blob.html -func (c *Context) ResultZeroblob(n ZeroBlobLength) { - C.sqlite3_result_zeroblob((*C.sqlite3_context)(c), C.int(n)) -} diff --git a/sqlite_context.go b/sqlite_context.go new file mode 100644 index 0000000..7652902 --- /dev/null +++ b/sqlite_context.go @@ -0,0 +1,103 @@ +// Copyright (C) 2014 Yasuhiro Matsumoto . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package sqlite3 + +/* + +#ifndef USE_LIBSQLITE3 +#include +#else +#include +#endif +#include +// These wrappers are necessary because SQLITE_TRANSIENT +// is a pointer constant, and cgo doesn't translate them correctly. + +static inline void my_result_text(sqlite3_context *ctx, char *p, int np) { + sqlite3_result_text(ctx, p, np, SQLITE_TRANSIENT); +} + +static inline void my_result_blob(sqlite3_context *ctx, void *p, int np) { + sqlite3_result_blob(ctx, p, np, SQLITE_TRANSIENT); +} +*/ +import "C" + +import ( + "math" + "reflect" + "unsafe" +) + +const i64 = unsafe.Sizeof(int(0)) > 4 + +type ZeroBlobLength int32 +type SQLiteContext C.sqlite3_context + +// ResultBool sets the result of an SQL function. +func (c *SQLiteContext) ResultBool(b bool) { + if b { + c.ResultInt(1) + } else { + c.ResultInt(0) + } +} + +// ResultBlob sets the result of an SQL function. +// See: sqlite3_result_blob, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultBlob(b []byte) { + if i64 && len(b) > math.MaxInt32 { + C.sqlite3_result_error_toobig((*C.sqlite3_context)(c)) + return + } + var p *byte + if len(b) > 0 { + p = &b[0] + } + C.my_result_blob((*C.sqlite3_context)(c), unsafe.Pointer(p), C.int(len(b))) +} + +// ResultDouble sets the result of an SQL function. +// See: sqlite3_result_double, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultDouble(d float64) { + C.sqlite3_result_double((*C.sqlite3_context)(c), C.double(d)) +} + +// ResultInt sets the result of an SQL function. +// See: sqlite3_result_int, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultInt(i int) { + if i64 && (i > math.MaxInt32 || i < math.MinInt32) { + C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i)) + } else { + C.sqlite3_result_int((*C.sqlite3_context)(c), C.int(i)) + } +} + +// ResultInt64 sets the result of an SQL function. +// See: sqlite3_result_int64, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultInt64(i int64) { + C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i)) +} + +// ResultNull sets the result of an SQL function. +// See: sqlite3_result_null, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultNull() { + C.sqlite3_result_null((*C.sqlite3_context)(c)) +} + +// ResultText sets the result of an SQL function. +// See: sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultText(s string) { + h := (*reflect.StringHeader)(unsafe.Pointer(&s)) + cs, l := (*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len) + C.my_result_text((*C.sqlite3_context)(c), cs, l) +} + +// ResultZeroblob sets the result of an SQL function. +// See: sqlite3_result_zeroblob, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultZeroblob(n ZeroBlobLength) { + C.sqlite3_result_zeroblob((*C.sqlite3_context)(c), C.int(n)) +} diff --git a/vtable.go b/vtable.go index 907e2dc..40ce2ea 100644 --- a/vtable.go +++ b/vtable.go @@ -294,7 +294,7 @@ func goVEof(pCursor unsafe.Pointer) C.int { //export goVColumn func goVColumn(pCursor, cp unsafe.Pointer, col int) *C.char { vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) - c := (*Context)(cp) + c := (*SQLiteContext)(cp) err := vtc.vTabCursor.Column(c, col) if err != nil { return mPrintf("%s", err.Error()) @@ -349,7 +349,7 @@ type VTabCursor interface { // http://sqlite.org/vtab.html#xeof EOF() bool // http://sqlite.org/vtab.html#xcolumn - Column(c *Context, col int) error + Column(c *SQLiteContext, col int) error // http://sqlite.org/vtab.html#xrowid Rowid() (int64, error) } diff --git a/vtable_test.go b/vtable_test.go index 4c7efcb..9b97927 100644 --- a/vtable_test.go +++ b/vtable_test.go @@ -94,7 +94,7 @@ func (vc *testVTabCursor) EOF() bool { return vc.index >= len(vc.vTab.intarray) } -func (vc *testVTabCursor) Column(c *Context, col int) error { +func (vc *testVTabCursor) Column(c *SQLiteContext, col int) error { if col != 0 { return fmt.Errorf("column index out of bounds: %d", col) } -- cgit v1.2.3 From fca908b49699a576553d06c5e058d9dda6309980 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Sun, 5 Mar 2017 20:48:17 +0900 Subject: fix import path --- _example/vtable/vtable.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to '_example') diff --git a/_example/vtable/vtable.go b/_example/vtable/vtable.go index 13e2624..40b460f 100644 --- a/_example/vtable/vtable.go +++ b/_example/vtable/vtable.go @@ -3,9 +3,10 @@ package main import ( "encoding/json" "fmt" - "github.com/DataDog/go-sqlite3" "io/ioutil" "net/http" + + "github.com/mattn/go-sqlite3" ) type GithubRepo struct { -- cgit v1.2.3 From a9d61d54c6d919d7f627743daa26e54687244566 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Sun, 5 Mar 2017 20:49:45 +0900 Subject: use pointer receiver --- _example/vtable/main.go | 5 +++-- _example/vtable/vtable.go | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to '_example') diff --git a/_example/vtable/main.go b/_example/vtable/main.go index 442069f..2f3b8a4 100644 --- a/_example/vtable/main.go +++ b/_example/vtable/main.go @@ -3,14 +3,15 @@ package main import ( "database/sql" "fmt" - "github.com/mattn/go-sqlite3" "log" + + "github.com/mattn/go-sqlite3" ) func main() { sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{ ConnectHook: func(conn *sqlite3.SQLiteConn) error { - return conn.CreateModule("github", githubModule{}) + return conn.CreateModule("github", &githubModule{}) }, }) db, err := sql.Open("sqlite3_with_extensions", ":memory:") diff --git a/_example/vtable/vtable.go b/_example/vtable/vtable.go index 40b460f..eb80e2a 100644 --- a/_example/vtable/vtable.go +++ b/_example/vtable/vtable.go @@ -19,7 +19,7 @@ type GithubRepo struct { type githubModule struct { } -func (m githubModule) Create(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) { +func (m *githubModule) Create(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) { err := c.DeclareVTab(fmt.Sprintf(` CREATE TABLE %s ( id INT, @@ -33,11 +33,11 @@ func (m githubModule) Create(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab return &ghRepoTable{}, nil } -func (m githubModule) Connect(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) { +func (m *githubModule) Connect(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) { return m.Create(c, args) } -func (m githubModule) DestroyModule() {} +func (m *githubModule) DestroyModule() {} type ghRepoTable struct { repos []GithubRepo -- cgit v1.2.3 From f9e79c0a39fae626821dd44da2372ded64b4f8d4 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Sun, 5 Mar 2017 20:52:55 +0900 Subject: golint --- _example/vtable/main.go | 6 +++--- _example/vtable/vtable.go | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) (limited to '_example') diff --git a/_example/vtable/main.go b/_example/vtable/main.go index 2f3b8a4..aad8dda 100644 --- a/_example/vtable/main.go +++ b/_example/vtable/main.go @@ -31,8 +31,8 @@ func main() { } defer rows.Close() for rows.Next() { - var id, full_name, description, html_url string - rows.Scan(&id, &full_name, &description, &html_url) - fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, full_name, description, html_url) + var id, fullName, description, htmlURL string + rows.Scan(&id, &fullName, &description, &htmlURL) + fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, fullName, description, htmlURL) } } diff --git a/_example/vtable/vtable.go b/_example/vtable/vtable.go index eb80e2a..1d6d824 100644 --- a/_example/vtable/vtable.go +++ b/_example/vtable/vtable.go @@ -9,11 +9,11 @@ import ( "github.com/mattn/go-sqlite3" ) -type GithubRepo struct { +type githubRepo struct { ID int `json:"id"` FullName string `json:"full_name"` Description string `json:"description"` - HtmlURL string `json:"html_url"` + HTMLURL string `json:"html_url"` } type githubModule struct { @@ -40,7 +40,7 @@ func (m *githubModule) Connect(c *sqlite3.SQLiteConn, args []string) (sqlite3.VT func (m *githubModule) DestroyModule() {} type ghRepoTable struct { - repos []GithubRepo + repos []githubRepo } func (v *ghRepoTable) Open() (sqlite3.VTabCursor, error) { @@ -55,7 +55,7 @@ func (v *ghRepoTable) Open() (sqlite3.VTabCursor, error) { return nil, err } - repos := make([]GithubRepo, 0) + var repos []githubRepo if err := json.Unmarshal(body, &repos); err != nil { return nil, err } @@ -71,7 +71,7 @@ func (v *ghRepoTable) Destroy() error { return nil } type ghRepoCursor struct { index int - repos []GithubRepo + repos []githubRepo } func (vc *ghRepoCursor) Column(c *sqlite3.SQLiteContext, col int) error { @@ -83,7 +83,7 @@ func (vc *ghRepoCursor) Column(c *sqlite3.SQLiteContext, col int) error { case 2: c.ResultText(vc.repos[vc.index].Description) case 3: - c.ResultText(vc.repos[vc.index].HtmlURL) + c.ResultText(vc.repos[vc.index].HTMLURL) } return nil } -- cgit v1.2.3 From ecc5105e21a211082827d69227de0899d3462e16 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Sun, 5 Mar 2017 22:29:09 +0900 Subject: golint --- _example/mod_vtable/extension.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to '_example') diff --git a/_example/mod_vtable/extension.go b/_example/mod_vtable/extension.go index 69ae2c7..f738af6 100644 --- a/_example/mod_vtable/extension.go +++ b/_example/mod_vtable/extension.go @@ -3,8 +3,9 @@ package main import ( "database/sql" "fmt" - "github.com/mattn/go-sqlite3" "log" + + "github.com/mattn/go-sqlite3" ) func main() { @@ -29,8 +30,8 @@ func main() { } defer rows.Close() for rows.Next() { - var id, full_name, description, html_url string - rows.Scan(&id, &full_name, &description, &html_url) - fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, full_name, description, html_url) + var id, fullName, description, htmlURL string + rows.Scan(&id, &fullName, &description, &htmlURL) + fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, fullName, description, htmlURL) } } -- cgit v1.2.3