diff options
author | EuAndreh <eu@euandre.org> | 2024-08-14 17:30:56 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2024-08-14 17:30:56 -0300 |
commit | d9fa98494c83c42cad978b0b1000c35524b8026b (patch) | |
tree | 810f83870cb349bf66b742a3875e4efcb4de3d4a | |
parent | Remove unused files (diff) | |
download | golite-d9fa98494c83c42cad978b0b1000c35524b8026b.tar.gz golite-d9fa98494c83c42cad978b0b1000c35524b8026b.tar.xz |
Remove most files from _example/
-rw-r--r-- | _example/custom_driver_name/Makefile | 12 | ||||
-rw-r--r-- | _example/custom_driver_name/main.go | 13 | ||||
-rw-r--r-- | _example/custom_func/main.go | 133 | ||||
-rw-r--r-- | _example/hook/hook.go | 78 | ||||
-rw-r--r-- | _example/mod_vtable/Makefile | 29 | ||||
-rw-r--r-- | _example/mod_vtable/extension.go | 37 | ||||
-rw-r--r-- | _example/mod_vtable/picojson.h | 1040 | ||||
-rw-r--r-- | _example/mod_vtable/sqlite3_mod_vtable.cc | 238 | ||||
-rw-r--r-- | _example/simple/Dockerfile | 47 | ||||
-rw-r--r-- | _example/simple/simple.go | 109 | ||||
-rw-r--r-- | _example/trace/main.go | 264 | ||||
-rw-r--r-- | _example/vtable/main.go | 38 | ||||
-rw-r--r-- | _example/vtable/vtable.go | 116 | ||||
-rw-r--r-- | _example/vtable_eponymous_only/main.go | 33 | ||||
-rw-r--r-- | _example/vtable_eponymous_only/vtable.go | 118 |
15 files changed, 0 insertions, 2305 deletions
diff --git a/_example/custom_driver_name/Makefile b/_example/custom_driver_name/Makefile deleted file mode 100644 index 91fcde6..0000000 --- a/_example/custom_driver_name/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -TARGET = custom_driver_name -ifeq ($(OS),Windows_NT) -TARGET := $(TARGET).exe -endif - -all : $(TARGET) - -$(TARGET) : main.go - go build -ldflags="-X 'github.com/mattn/go-sqlite3.driverName=my-sqlite3'" - -clean : - rm -f $(TARGET) diff --git a/_example/custom_driver_name/main.go b/_example/custom_driver_name/main.go deleted file mode 100644 index 3148cae..0000000 --- a/_example/custom_driver_name/main.go +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import ( - "database/sql" - - _ "github.com/mattn/go-sqlite3" -) - -func main() { - for _, driver := range sql.Drivers() { - println(driver) - } -} diff --git a/_example/custom_func/main.go b/_example/custom_func/main.go deleted file mode 100644 index 85657e6..0000000 --- a/_example/custom_func/main.go +++ /dev/null @@ -1,133 +0,0 @@ -package main - -import ( - "database/sql" - "fmt" - "log" - "math" - "math/rand" - - sqlite "github.com/mattn/go-sqlite3" -) - -// Computes x^y -func pow(x, y int64) int64 { - return int64(math.Pow(float64(x), float64(y))) -} - -// Computes the bitwise exclusive-or of all its arguments -func xor(xs ...int64) int64 { - var ret int64 - for _, x := range xs { - ret ^= x - } - return ret -} - -// Returns a random number. It's actually deterministic here because -// we don't seed the RNG, but it's an example of a non-pure function -// from SQLite's POV. -func getrand() int64 { - return rand.Int63() -} - -// Computes the standard deviation of a GROUPed BY set of values -type stddev struct { - xs []int64 - // Running average calculation - sum int64 - n int64 -} - -func newStddev() *stddev { return &stddev{} } - -func (s *stddev) Step(x int64) { - s.xs = append(s.xs, x) - s.sum += x - s.n++ -} - -func (s *stddev) Done() float64 { - mean := float64(s.sum) / float64(s.n) - var sqDiff []float64 - for _, x := range s.xs { - sqDiff = append(sqDiff, math.Pow(float64(x)-mean, 2)) - } - var dev float64 - for _, x := range sqDiff { - dev += x - } - dev /= float64(len(sqDiff)) - return math.Sqrt(dev) -} - -func main() { - sql.Register("sqlite3_custom", &sqlite.SQLiteDriver{ - ConnectHook: func(conn *sqlite.SQLiteConn) error { - if err := conn.RegisterFunc("pow", pow, true); err != nil { - return err - } - if err := conn.RegisterFunc("xor", xor, true); err != nil { - return err - } - if err := conn.RegisterFunc("rand", getrand, false); err != nil { - return err - } - if err := conn.RegisterAggregator("stddev", newStddev, true); err != nil { - return err - } - return nil - }, - }) - - db, err := sql.Open("sqlite3_custom", ":memory:") - if err != nil { - log.Fatal("Failed to open database:", err) - } - defer db.Close() - - var i int64 - err = db.QueryRow("SELECT pow(2,3)").Scan(&i) - if err != nil { - log.Fatal("POW query error:", err) - } - fmt.Println("pow(2,3) =", i) // 8 - - err = db.QueryRow("SELECT xor(1,2,3,4,5,6)").Scan(&i) - if err != nil { - log.Fatal("XOR query error:", err) - } - fmt.Println("xor(1,2,3,4,5) =", i) // 7 - - err = db.QueryRow("SELECT rand()").Scan(&i) - if err != nil { - log.Fatal("RAND query error:", err) - } - fmt.Println("rand() =", i) // pseudorandom - - _, err = db.Exec("create table foo (department integer, profits integer)") - if err != nil { - log.Fatal("Failed to create table:", err) - } - _, err = db.Exec("insert into foo values (1, 10), (1, 20), (1, 45), (2, 42), (2, 115)") - if err != nil { - log.Fatal("Failed to insert records:", err) - } - - rows, err := db.Query("select department, stddev(profits) from foo group by department") - if err != nil { - log.Fatal("STDDEV query error:", err) - } - defer rows.Close() - for rows.Next() { - var dept int64 - var dev float64 - if err := rows.Scan(&dept, &dev); err != nil { - log.Fatal(err) - } - fmt.Printf("dept=%d stddev=%f\n", dept, dev) - } - if err := rows.Err(); err != nil { - log.Fatal(err) - } -} diff --git a/_example/hook/hook.go b/_example/hook/hook.go deleted file mode 100644 index 6023181..0000000 --- a/_example/hook/hook.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "database/sql" - "log" - "os" - - "github.com/mattn/go-sqlite3" -) - -func main() { - sqlite3conn := []*sqlite3.SQLiteConn{} - sql.Register("sqlite3_with_hook_example", - &sqlite3.SQLiteDriver{ - ConnectHook: func(conn *sqlite3.SQLiteConn) error { - sqlite3conn = append(sqlite3conn, conn) - conn.RegisterUpdateHook(func(op int, db string, table string, rowid int64) { - switch op { - case sqlite3.SQLITE_INSERT: - log.Println("Notified of insert on db", db, "table", table, "rowid", rowid) - } - }) - return nil - }, - }) - os.Remove("./foo.db") - os.Remove("./bar.db") - - srcDb, err := sql.Open("sqlite3_with_hook_example", "./foo.db") - if err != nil { - log.Fatal(err) - } - defer srcDb.Close() - srcDb.Ping() - - _, err = srcDb.Exec("create table foo(id int, value text)") - if err != nil { - log.Fatal(err) - } - _, err = srcDb.Exec("insert into foo values(1, 'foo')") - if err != nil { - log.Fatal(err) - } - _, err = srcDb.Exec("insert into foo values(2, 'bar')") - if err != nil { - log.Fatal(err) - } - _, err = srcDb.Query("select * from foo") - if err != nil { - log.Fatal(err) - } - destDb, err := sql.Open("sqlite3_with_hook_example", "./bar.db") - if err != nil { - log.Fatal(err) - } - defer destDb.Close() - destDb.Ping() - - bk, err := sqlite3conn[1].Backup("main", sqlite3conn[0], "main") - if err != nil { - log.Fatal(err) - } - - _, err = bk.Step(-1) - if err != nil { - log.Fatal(err) - } - _, err = destDb.Query("select * from foo") - if err != nil { - log.Fatal(err) - } - _, err = destDb.Exec("insert into foo values(3, 'bar')") - if err != nil { - log.Fatal(err) - } - - bk.Finish() -} diff --git a/_example/mod_vtable/Makefile b/_example/mod_vtable/Makefile deleted file mode 100644 index f65a004..0000000 --- a/_example/mod_vtable/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -ifeq ($(OS),Windows_NT) -EXE=extension.exe -LIB_EXT=dll -RM=cmd /c del -LIBCURL=-lcurldll -LDFLAG= -else -EXE=extension -ifeq ($(shell uname -s),Darwin) -LIB_EXT=dylib -else -LIB_EXT=so -endif -RM=rm -f -LDFLAG=-fPIC -LIBCURL=-lcurl -endif -LIB=sqlite3_mod_vtable.$(LIB_EXT) - -all : $(EXE) $(LIB) - -$(EXE) : extension.go - go build $< - -$(LIB) : sqlite3_mod_vtable.cc - g++ $(LDFLAG) -shared -o $@ $< -lsqlite3 $(LIBCURL) - -clean : - @-$(RM) $(EXE) $(LIB) diff --git a/_example/mod_vtable/extension.go b/_example/mod_vtable/extension.go deleted file mode 100644 index f738af6..0000000 --- a/_example/mod_vtable/extension.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "database/sql" - "fmt" - "log" - - "github.com/mattn/go-sqlite3" -) - -func main() { - sql.Register("sqlite3_with_extensions", - &sqlite3.SQLiteDriver{ - Extensions: []string{ - "sqlite3_mod_vtable", - }, - }) - - db, err := sql.Open("sqlite3_with_extensions", ":memory:") - if err != nil { - log.Fatal(err) - } - defer db.Close() - - db.Exec("create virtual table repo using github(id, full_name, description, html_url)") - - 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, 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/mod_vtable/picojson.h b/_example/mod_vtable/picojson.h deleted file mode 100644 index 2142647..0000000 --- a/_example/mod_vtable/picojson.h +++ /dev/null @@ -1,1040 +0,0 @@ -/* - * Copyright 2009-2010 Cybozu Labs, Inc. - * Copyright 2011 Kazuho Oku - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CYBOZU LABS, INC. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL CYBOZU LABS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of Cybozu Labs, Inc. - * - */ -#ifndef picojson_h -#define picojson_h - -#include <algorithm> -#include <cassert> -#include <cmath> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <iostream> -#include <iterator> -#include <map> -#include <string> -#include <vector> - -#ifdef _MSC_VER - #define SNPRINTF _snprintf_s - #pragma warning(push) - #pragma warning(disable : 4244) // conversion from int to char -#else - #define SNPRINTF snprintf -#endif - -namespace picojson { - - enum { - null_type, - boolean_type, - number_type, - string_type, - array_type, - object_type - }; - - struct null {}; - - class value { - public: - typedef std::vector<value> array; - typedef std::map<std::string, value> object; - union _storage { - bool boolean_; - double number_; - std::string* string_; - array* array_; - object* object_; - }; - protected: - int type_; - _storage u_; - public: - value(); - value(int type, bool); - explicit value(bool b); - explicit value(double n); - explicit value(const std::string& s); - explicit value(const array& a); - explicit value(const object& o); - explicit value(const char* s); - value(const char* s, size_t len); - ~value(); - value(const value& x); - value& operator=(const value& x); - void swap(value& x); - template <typename T> bool is() const; - template <typename T> const T& get() const; - template <typename T> T& get(); - bool evaluate_as_boolean() const; - const value& get(size_t idx) const; - const value& get(const std::string& key) const; - bool contains(size_t idx) const; - bool contains(const std::string& key) const; - std::string to_str() const; - template <typename Iter> void serialize(Iter os) const; - std::string serialize() const; - private: - template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool - }; - - typedef value::array array; - typedef value::object object; - - inline value::value() : type_(null_type) {} - - inline value::value(int type, bool) : type_(type) { - switch (type) { -#define INIT(p, v) case p##type: u_.p = v; break - INIT(boolean_, false); - INIT(number_, 0.0); - INIT(string_, new std::string()); - INIT(array_, new array()); - INIT(object_, new object()); -#undef INIT - default: break; - } - } - - inline value::value(bool b) : type_(boolean_type) { - u_.boolean_ = b; - } - - inline value::value(double n) : type_(number_type) { - u_.number_ = n; - } - - inline value::value(const std::string& s) : type_(string_type) { - u_.string_ = new std::string(s); - } - - inline value::value(const array& a) : type_(array_type) { - u_.array_ = new array(a); - } - - inline value::value(const object& o) : type_(object_type) { - u_.object_ = new object(o); - } - - inline value::value(const char* s) : type_(string_type) { - u_.string_ = new std::string(s); - } - - inline value::value(const char* s, size_t len) : type_(string_type) { - u_.string_ = new std::string(s, len); - } - - inline value::~value() { - switch (type_) { -#define DEINIT(p) case p##type: delete u_.p; break - DEINIT(string_); - DEINIT(array_); - DEINIT(object_); -#undef DEINIT - default: break; - } - } - - inline value::value(const value& x) : type_(x.type_) { - switch (type_) { -#define INIT(p, v) case p##type: u_.p = v; break - INIT(string_, new std::string(*x.u_.string_)); - INIT(array_, new array(*x.u_.array_)); - INIT(object_, new object(*x.u_.object_)); -#undef INIT - default: - u_ = x.u_; - break; - } - } - - inline value& value::operator=(const value& x) { - if (this != &x) { - this->~value(); - new (this) value(x); - } - return *this; - } - - inline void value::swap(value& x) { - std::swap(type_, x.type_); - std::swap(u_, x.u_); - } - -#define IS(ctype, jtype) \ - template <> inline bool value::is<ctype>() const { \ - return type_ == jtype##_type; \ - } - IS(null, null) - IS(bool, boolean) - IS(int, number) - IS(double, number) - IS(std::string, string) - IS(array, array) - IS(object, object) -#undef IS - -#define GET(ctype, var) \ - template <> inline const ctype& value::get<ctype>() const { \ - assert("type mismatch! call vis<type>() before get<type>()" \ - && is<ctype>()); \ - return var; \ - } \ - template <> inline ctype& value::get<ctype>() { \ - assert("type mismatch! call is<type>() before get<type>()" \ - && is<ctype>()); \ - return var; \ - } - GET(bool, u_.boolean_) - GET(double, u_.number_) - GET(std::string, *u_.string_) - GET(array, *u_.array_) - GET(object, *u_.object_) -#undef GET - - inline bool value::evaluate_as_boolean() const { - switch (type_) { - case null_type: - return false; - case boolean_type: - return u_.boolean_; - case number_type: - return u_.number_ != 0; - case string_type: - return ! u_.string_->empty(); - default: - return true; - } - } - - inline const value& value::get(size_t idx) const { - static value s_null; - assert(is<array>()); - return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; - } - - inline const value& value::get(const std::string& key) const { - static value s_null; - assert(is<object>()); - object::const_iterator i = u_.object_->find(key); - return i != u_.object_->end() ? i->second : s_null; - } - - inline bool value::contains(size_t idx) const { - assert(is<array>()); - return idx < u_.array_->size(); - } - - inline bool value::contains(const std::string& key) const { - assert(is<object>()); - object::const_iterator i = u_.object_->find(key); - return i != u_.object_->end(); - } - - inline std::string value::to_str() const { - switch (type_) { - case null_type: return "null"; - case boolean_type: return u_.boolean_ ? "true" : "false"; - case number_type: { - char buf[256]; - double tmp; - SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); - return buf; - } - case string_type: return *u_.string_; - case array_type: return "array"; - case object_type: return "object"; - default: assert(0); -#ifdef _MSC_VER - __assume(0); -#endif - } - return std::string(); - } - - template <typename Iter> void copy(const std::string& s, Iter oi) { - std::copy(s.begin(), s.end(), oi); - } - - template <typename Iter> void serialize_str(const std::string& s, Iter oi) { - *oi++ = '"'; - for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { - switch (*i) { -#define MAP(val, sym) case val: copy(sym, oi); break - MAP('"', "\\\""); - MAP('\\', "\\\\"); - MAP('/', "\\/"); - MAP('\b', "\\b"); - MAP('\f', "\\f"); - MAP('\n', "\\n"); - MAP('\r', "\\r"); - MAP('\t', "\\t"); -#undef MAP - default: - if ((unsigned char)*i < 0x20 || *i == 0x7f) { - char buf[7]; - SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); - copy(buf, buf + 6, oi); - } else { - *oi++ = *i; - } - break; - } - } - *oi++ = '"'; - } - - template <typename Iter> void value::serialize(Iter oi) const { - switch (type_) { - case string_type: - serialize_str(*u_.string_, oi); - break; - case array_type: { - *oi++ = '['; - for (array::const_iterator i = u_.array_->begin(); - i != u_.array_->end(); - ++i) { - if (i != u_.array_->begin()) { - *oi++ = ','; - } - i->serialize(oi); - } - *oi++ = ']'; - break; - } - case object_type: { - *oi++ = '{'; - for (object::const_iterator i = u_.object_->begin(); - i != u_.object_->end(); - ++i) { - if (i != u_.object_->begin()) { - *oi++ = ','; - } - serialize_str(i->first, oi); - *oi++ = ':'; - i->second.serialize(oi); - } - *oi++ = '}'; - break; - } - default: - copy(to_str(), oi); - break; - } - } - - inline std::string value::serialize() const { - std::string s; - serialize(std::back_inserter(s)); - return s; - } - - template <typename Iter> class input { - protected: - Iter cur_, end_; - int last_ch_; - bool ungot_; - int line_; - public: - input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {} - int getc() { - if (ungot_) { - ungot_ = false; - return last_ch_; - } - if (cur_ == end_) { - last_ch_ = -1; - return -1; - } - if (last_ch_ == '\n') { - line_++; - } - last_ch_ = *cur_++ & 0xff; - return last_ch_; - } - void ungetc() { - if (last_ch_ != -1) { - assert(! ungot_); - ungot_ = true; - } - } - Iter cur() const { return cur_; } - int line() const { return line_; } - void skip_ws() { - while (1) { - int ch = getc(); - if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { - ungetc(); - break; - } - } - } - bool expect(int expect) { - skip_ws(); - if (getc() != expect) { - ungetc(); - return false; - } - return true; - } - bool match(const std::string& pattern) { - for (std::string::const_iterator pi(pattern.begin()); - pi != pattern.end(); - ++pi) { - if (getc() != *pi) { - ungetc(); - return false; - } - } - return true; - } - }; - - template<typename Iter> inline int _parse_quadhex(input<Iter> &in) { - int uni_ch = 0, hex; - for (int i = 0; i < 4; i++) { - if ((hex = in.getc()) == -1) { - return -1; - } - if ('0' <= hex && hex <= '9') { - hex -= '0'; - } else if ('A' <= hex && hex <= 'F') { - hex -= 'A' - 0xa; - } else if ('a' <= hex && hex <= 'f') { - hex -= 'a' - 0xa; - } else { - in.ungetc(); - return -1; - } - uni_ch = uni_ch * 16 + hex; - } - return uni_ch; - } - - template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in) { - int uni_ch; - if ((uni_ch = _parse_quadhex(in)) == -1) { - return false; - } - if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { - if (0xdc00 <= uni_ch) { - // a second 16-bit of a surrogate pair appeared - return false; - } - // first 16-bit of surrogate pair, get the next one - if (in.getc() != '\\' || in.getc() != 'u') { - in.ungetc(); - return false; - } - int second = _parse_quadhex(in); - if (! (0xdc00 <= second && second <= 0xdfff)) { - return false; - } - uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); - uni_ch += 0x10000; - } - if (uni_ch < 0x80) { - out.push_back(uni_ch); - } else { - if (uni_ch < 0x800) { - out.push_back(0xc0 | (uni_ch >> 6)); - } else { - if (uni_ch < 0x10000) { - out.push_back(0xe0 | (uni_ch >> 12)); - } else { - out.push_back(0xf0 | (uni_ch >> 18)); - out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); - } - out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); - } - out.push_back(0x80 | (uni_ch & 0x3f)); - } - return true; - } - - template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in) { - while (1) { - int ch = in.getc(); - if (ch < ' ') { - in.ungetc(); - return false; - } else if (ch == '"') { - return true; - } else if (ch == '\\') { - if ((ch = in.getc()) == -1) { - return false; - } - switch (ch) { -#define MAP(sym, val) case sym: out.push_back(val); break - MAP('"', '\"'); - MAP('\\', '\\'); - MAP('/', '/'); - MAP('b', '\b'); - MAP('f', '\f'); - MAP('n', '\n'); - MAP('r', '\r'); - MAP('t', '\t'); -#undef MAP - case 'u': - if (! _parse_codepoint(out, in)) { - return false; - } - break; - default: - return false; - } - } else { - out.push_back(ch); - } - } - return false; - } - - template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in) { - if (! ctx.parse_array_start()) { - return false; - } - size_t idx = 0; - if (in.expect(']')) { - return ctx.parse_array_stop(idx); - } - do { - if (! ctx.parse_array_item(in, idx)) { - return false; - } - idx++; - } while (in.expect(',')); - return in.expect(']') && ctx.parse_array_stop(idx); - } - - template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in) { - if (! ctx.parse_object_start()) { - return false; - } - if (in.expect('}')) { - return true; - } - do { - std::string key; - if (! in.expect('"') - || ! _parse_string(key, in) - || ! in.expect(':')) { - return false; - } - if (! ctx.parse_object_item(in, key)) { - return false; - } - } while (in.expect(',')); - return in.expect('}'); - } - - template <typename Iter> inline bool _parse_number(double& out, input<Iter>& in) { - std::string num_str; - while (1) { - int ch = in.getc(); - if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.' - || ch == 'e' || ch == 'E') { - num_str.push_back(ch); - } else { - in.ungetc(); - break; - } - } - char* endp; - out = strtod(num_str.c_str(), &endp); - return endp == num_str.c_str() + num_str.size(); - } - - template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in) { - in.skip_ws(); - int ch = in.getc(); - switch (ch) { -#define IS(ch, text, op) case ch: \ - if (in.match(text) && op) { \ - return true; \ - } else { \ - return false; \ - } - IS('n', "ull", ctx.set_null()); - IS('f', "alse", ctx.set_bool(false)); - IS('t', "rue", ctx.set_bool(true)); -#undef IS - case '"': - return ctx.parse_string(in); - case '[': - return _parse_array(ctx, in); - case '{': - return _parse_object(ctx, in); - default: - if (('0' <= ch && ch <= '9') || ch == '-') { - in.ungetc(); - double f; - if (_parse_number(f, in)) { - ctx.set_number(f); - return true; - } else { - return false; - } - } - break; - } - in.ungetc(); - return false; - } - - class deny_parse_context { - public: - bool set_null() { return false; } - bool set_bool(bool) { return false; } - bool set_number(double) { return false; } - template <typename Iter> bool parse_string(input<Iter>&) { return false; } - bool parse_array_start() { return false; } - template <typename Iter> bool parse_array_item(input<Iter>&, size_t) { - return false; - } - bool parse_array_stop(size_t) { return false; } - bool parse_object_start() { return false; } - template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&) { - return false; - } - }; - - class default_parse_context { - protected: - value* out_; - public: - default_parse_context(value* out) : out_(out) {} - bool set_null() { - *out_ = value(); - return true; - } - bool set_bool(bool b) { - *out_ = value(b); - return true; - } - bool set_number(double f) { - *out_ = value(f); - return true; - } - template<typename Iter> bool parse_string(input<Iter>& in) { - *out_ = value(string_type, false); - return _parse_string(out_->get<std::string>(), in); - } - bool parse_array_start() { - *out_ = value(array_type, false); - return true; - } - template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) { - array& a = out_->get<array>(); - a.push_back(value()); - default_parse_context ctx(&a.back()); - return _parse(ctx, in); - } - bool parse_array_stop(size_t) { return true; } - bool parse_object_start() { - *out_ = value(object_type, false); - return true; - } - template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key) { - object& o = out_->get<object>(); - default_parse_context ctx(&o[key]); - return _parse(ctx, in); - } - private: - default_parse_context(const default_parse_context&); - default_parse_context& operator=(const default_parse_context&); - }; - - class null_parse_context { - public: - struct dummy_str { - void push_back(int) {} - }; - public: - null_parse_context() {} - bool set_null() { return true; } - bool set_bool(bool) { return true; } - bool set_number(double) { return true; } - template <typename Iter> bool parse_string(input<Iter>& in) { - dummy_str s; - return _parse_string(s, in); - } - bool parse_array_start() { return true; } - template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) { - return _parse(*this, in); - } - bool parse_array_stop(size_t) { return true; } - bool parse_object_start() { return true; } - template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&) { - return _parse(*this, in); - } - private: - null_parse_context(const null_parse_context&); - null_parse_context& operator=(const null_parse_context&); - }; - - // obsolete, use the version below - template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) { - std::string err; - pos = parse(out, pos, last, &err); - return err; - } - - template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { - input<Iter> in(first, last); - if (! _parse(ctx, in) && err != NULL) { - char buf[64]; - SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); - *err = buf; - while (1) { - int ch = in.getc(); - if (ch == -1 || ch == '\n') { - break; - } else if (ch >= ' ') { - err->push_back(ch); - } - } - } - return in.cur(); - } - - template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) { - default_parse_context ctx(&out); - return _parse(ctx, first, last, err); - } - - inline std::string parse(value& out, std::istream& is) { - std::string err; - parse(out, std::istreambuf_iterator<char>(is.rdbuf()), - std::istreambuf_iterator<char>(), &err); - return err; - } - - template <typename T> struct last_error_t { - static std::string s; - }; - template <typename T> std::string last_error_t<T>::s; - - inline void set_last_error(const std::string& s) { - last_error_t<bool>::s = s; - } - - inline const std::string& get_last_error() { - return last_error_t<bool>::s; - } - - inline bool operator==(const value& x, const value& y) { - if (x.is<null>()) - return y.is<null>(); -#define PICOJSON_CMP(type) \ - if (x.is<type>()) \ - return y.is<type>() && x.get<type>() == y.get<type>() - PICOJSON_CMP(bool); - PICOJSON_CMP(double); - PICOJSON_CMP(std::string); - PICOJSON_CMP(array); - PICOJSON_CMP(object); -#undef PICOJSON_CMP - assert(0); -#ifdef _MSC_VER - __assume(0); -#endif - return false; - } - - inline bool operator!=(const value& x, const value& y) { - return ! (x == y); - } -} - -namespace std { - template<> inline void swap(picojson::value& x, picojson::value& y) - { - x.swap(y); - } -} - -inline std::istream& operator>>(std::istream& is, picojson::value& x) -{ - picojson::set_last_error(std::string()); - std::string err = picojson::parse(x, is); - if (! err.empty()) { - picojson::set_last_error(err); - is.setstate(std::ios::failbit); - } - return is; -} - -inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) -{ - x.serialize(std::ostream_iterator<char>(os)); - return os; -} -#ifdef _MSC_VER - #pragma warning(pop) -#endif - -#endif -#ifdef TEST_PICOJSON -#ifdef _MSC_VER - #pragma warning(disable : 4127) // conditional expression is constant -#endif - -using namespace std; - -static void plan(int num) -{ - printf("1..%d\n", num); -} - -static bool success = true; - -static void ok(bool b, const char* name = "") -{ - static int n = 1; - if (! b) - success = false; - printf("%s %d - %s\n", b ? "ok" : "ng", n++, name); -} - -template <typename T> void is(const T& x, const T& y, const char* name = "") -{ - if (x == y) { - ok(true, name); - } else { - ok(false, name); - } -} - -#include <algorithm> -#include <sstream> -#include <float.h> -#include <limits.h> - -int main(void) -{ - plan(85); - - // constructors -#define TEST(expr, expected) \ - is(picojson::value expr .serialize(), string(expected), "picojson::value" #expr) - - TEST( (true), "true"); - TEST( (false), "false"); - TEST( (42.0), "42"); - TEST( (string("hello")), "\"hello\""); - TEST( ("hello"), "\"hello\""); - TEST( ("hello", 4), "\"hell\""); - - { - double a = 1; - for (int i = 0; i < 1024; i++) { - picojson::value vi(a); - std::stringstream ss; - ss << vi; - picojson::value vo; - ss >> vo; - double b = vo.get<double>(); - if ((i < 53 && a != b) || fabs(a - b) / b > 1e-8) { - printf("ng i=%d a=%.18e b=%.18e\n", i, a, b); - } - a *= 2; - } - } - -#undef TEST - -#define TEST(in, type, cmp, serialize_test) { \ - picojson::value v; \ - const char* s = in; \ - string err = picojson::parse(v, s, s + strlen(s)); \ - ok(err.empty(), in " no error"); \ - ok(v.is<type>(), in " check type"); \ - is<type>(v.get<type>(), cmp, in " correct output"); \ - is(*s, '\0', in " read to eof"); \ - if (serialize_test) { \ - is(v.serialize(), string(in), in " serialize"); \ - } \ - } - TEST("false", bool, false, true); - TEST("true", bool, true, true); - TEST("90.5", double, 90.5, false); - TEST("1.7976931348623157e+308", double, DBL_MAX, false); - TEST("\"hello\"", string, string("hello"), true); - TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"), - true); - TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string, - string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false); - TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false); -#undef TEST - -#define TEST(type, expr) { \ - picojson::value v; \ - const char *s = expr; \ - string err = picojson::parse(v, s, s + strlen(s)); \ - ok(err.empty(), "empty " #type " no error"); \ - ok(v.is<picojson::type>(), "empty " #type " check type"); \ - ok(v.get<picojson::type>().empty(), "check " #type " array size"); \ - } - TEST(array, "[]"); - TEST(object, "{}"); -#undef TEST - - { - picojson::value v; - const char *s = "[1,true,\"hello\"]"; - string err = picojson::parse(v, s, s + strlen(s)); - ok(err.empty(), "array no error"); - ok(v.is<picojson::array>(), "array check type"); - is(v.get<picojson::array>().size(), size_t(3), "check array size"); - ok(v.contains(0), "check contains array[0]"); - ok(v.get(0).is<double>(), "check array[0] type"); - is(v.get(0).get<double>(), 1.0, "check array[0] value"); - ok(v.contains(1), "check contains array[1]"); - ok(v.get(1).is<bool>(), "check array[1] type"); - ok(v.get(1).get<bool>(), "check array[1] value"); - ok(v.contains(2), "check contains array[2]"); - ok(v.get(2).is<string>(), "check array[2] type"); - is(v.get(2).get<string>(), string("hello"), "check array[2] value"); - ok(!v.contains(3), "check not contains array[3]"); - } - - { - picojson::value v; - const char *s = "{ \"a\": true }"; - string err = picojson::parse(v, s, s + strlen(s)); - ok(err.empty(), "object no error"); - ok(v.is<picojson::object>(), "object check type"); - is(v.get<picojson::object>().size(), size_t(1), "check object size"); - ok(v.contains("a"), "check contains property"); - ok(v.get("a").is<bool>(), "check bool property exists"); - is(v.get("a").get<bool>(), true, "check bool property value"); - is(v.serialize(), string("{\"a\":true}"), "serialize object"); - ok(!v.contains("z"), "check not contains property"); - } - -#define TEST(json, msg) do { \ - picojson::value v; \ - const char *s = json; \ - string err = picojson::parse(v, s, s + strlen(s)); \ - is(err, string("syntax error at line " msg), msg); \ - } while (0) - TEST("falsoa", "1 near: oa"); - TEST("{]", "1 near: ]"); - TEST("\n\bbell", "2 near: bell"); - TEST("\"abc\nd\"", "1 near: "); -#undef TEST - - { - picojson::value v1, v2; - const char *s; - string err; - s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; - err = picojson::parse(v1, s, s + strlen(s)); - s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }"; - err = picojson::parse(v2, s, s + strlen(s)); - ok((v1 == v2), "check == operator in deep comparison"); - } - - { - picojson::value v1, v2; - const char *s; - string err; - s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; - err = picojson::parse(v1, s, s + strlen(s)); - s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }"; - err = picojson::parse(v2, s, s + strlen(s)); - ok((v1 != v2), "check != operator for array in deep comparison"); - } - - { - picojson::value v1, v2; - const char *s; - string err; - s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; - err = picojson::parse(v1, s, s + strlen(s)); - s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }"; - err = picojson::parse(v2, s, s + strlen(s)); - ok((v1 != v2), "check != operator for object in deep comparison"); - } - - { - picojson::value v1, v2; - const char *s; - string err; - s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; - err = picojson::parse(v1, s, s + strlen(s)); - picojson::object& o = v1.get<picojson::object>(); - o.erase("b"); - picojson::array& a = o["a"].get<picojson::array>(); - picojson::array::iterator i; - i = std::remove(a.begin(), a.end(), picojson::value(std::string("three"))); - a.erase(i, a.end()); - s = "{ \"a\": [1,2], \"d\": 2 }"; - err = picojson::parse(v2, s, s + strlen(s)); - ok((v1 == v2), "check erase()"); - } - - ok(picojson::value(3.0).serialize() == "3", - "integral number should be serialized as a integer"); - - { - const char* s = "{ \"a\": [1,2], \"d\": 2 }"; - picojson::null_parse_context ctx; - string err; - picojson::_parse(ctx, s, s + strlen(s), &err); - ok(err.empty(), "null_parse_context"); - } - - { - picojson::value v1, v2; - v1 = picojson::value(true); - swap(v1, v2); - ok(v1.is<picojson::null>(), "swap (null)"); - ok(v2.get<bool>() == true, "swap (bool)"); - - v1 = picojson::value("a"); - v2 = picojson::value(1.0); - swap(v1, v2); - ok(v1.get<double>() == 1.0, "swap (dobule)"); - ok(v2.get<string>() == "a", "swap (string)"); - - v1 = picojson::value(picojson::object()); - v2 = picojson::value(picojson::array()); - swap(v1, v2); - ok(v1.is<picojson::array>(), "swap (array)"); - ok(v2.is<picojson::object>(), "swap (object)"); - } - - return success ? 0 : 1; -} - -#endif diff --git a/_example/mod_vtable/sqlite3_mod_vtable.cc b/_example/mod_vtable/sqlite3_mod_vtable.cc deleted file mode 100644 index 4caf484..0000000 --- a/_example/mod_vtable/sqlite3_mod_vtable.cc +++ /dev/null @@ -1,238 +0,0 @@ -#include <string> -#include <sstream> -#include <sqlite3.h> -#include <sqlite3ext.h> -#include <curl/curl.h> -#include "picojson.h" - -#ifdef _WIN32 -# define EXPORT __declspec(dllexport) -#else -# define EXPORT -#endif - -SQLITE_EXTENSION_INIT1; - -typedef struct { - char* data; // response data from server - size_t size; // response size of data -} MEMFILE; - -MEMFILE* -memfopen() { - MEMFILE* mf = (MEMFILE*) malloc(sizeof(MEMFILE)); - if (mf) { - mf->data = NULL; - mf->size = 0; - } - return mf; -} - -void -memfclose(MEMFILE* mf) { - if (mf->data) free(mf->data); - free(mf); -} - -size_t -memfwrite(char* ptr, size_t size, size_t nmemb, void* stream) { - MEMFILE* mf = (MEMFILE*) stream; - int block = size * nmemb; - if (!mf) return block; // through - if (!mf->data) - mf->data = (char*) malloc(block); - else - mf->data = (char*) realloc(mf->data, mf->size + block); - if (mf->data) { - memcpy(mf->data + mf->size, ptr, block); - mf->size += block; - } - return block; -} - -char* -memfstrdup(MEMFILE* mf) { - char* buf; - if (mf->size == 0) return NULL; - buf = (char*) malloc(mf->size + 1); - memcpy(buf, mf->data, mf->size); - buf[mf->size] = 0; - return buf; -} - -static int -my_connect(sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **c) { - std::stringstream ss; - ss << "CREATE TABLE " << argv[0] - << "(id int, full_name text, description text, html_url text)"; - int rc = sqlite3_declare_vtab(db, ss.str().c_str()); - *ppVTab = (sqlite3_vtab *) sqlite3_malloc(sizeof(sqlite3_vtab)); - memset(*ppVTab, 0, sizeof(sqlite3_vtab)); - return rc; -} - -static int -my_create(sqlite3 *db, void *pAux, int argc, const char * const * argv, sqlite3_vtab **ppVTab, char **c) { - return my_connect(db, pAux, argc, argv, ppVTab, c); -} - -static int my_disconnect(sqlite3_vtab *pVTab) { - sqlite3_free(pVTab); - return SQLITE_OK; -} - -static int -my_destroy(sqlite3_vtab *pVTab) { - sqlite3_free(pVTab); - return SQLITE_OK; -} - -typedef struct { - sqlite3_vtab_cursor base; - int index; - picojson::value* rows; -} cursor; - -static int -my_open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) { - MEMFILE* mf; - CURL* curl; - char* json; - CURLcode res = CURLE_OK; - char error[CURL_ERROR_SIZE] = {0}; - char* cert_file = getenv("SSL_CERT_FILE"); - - mf = memfopen(); - curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.29.0"); - curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repositories"); - if (cert_file) - curl_easy_setopt(curl, CURLOPT_CAINFO, cert_file); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); - if (res != CURLE_OK) { - std::cerr << error << std::endl; - return SQLITE_FAIL; - } - - picojson::value* v = new picojson::value; - std::string err; - picojson::parse(*v, mf->data, mf->data + mf->size, &err); - memfclose(mf); - - if (!err.empty()) { - delete v; - std::cerr << err << std::endl; - return SQLITE_FAIL; - } - - cursor *c = (cursor *)sqlite3_malloc(sizeof(cursor)); - c->rows = v; - c->index = 0; - *ppCursor = &c->base; - return SQLITE_OK; -} - -static int -my_close(cursor *c) { - delete c->rows; - sqlite3_free(c); - return SQLITE_OK; -} - -static int -my_filter(cursor *c, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) { - c->index = 0; - return SQLITE_OK; -} - -static int -my_next(cursor *c) { - c->index++; - return SQLITE_OK; -} - -static int -my_eof(cursor *c) { - return c->index >= c->rows->get<picojson::array>().size() ? 1 : 0; -} - -static int -my_column(cursor *c, sqlite3_context *ctxt, int i) { - picojson::value v = c->rows->get<picojson::array>()[c->index]; - picojson::object row = v.get<picojson::object>(); - const char* p = NULL; - switch (i) { - case 0: - p = row["id"].to_str().c_str(); - break; - case 1: - p = row["full_name"].to_str().c_str(); - break; - case 2: - p = row["description"].to_str().c_str(); - break; - case 3: - p = row["html_url"].to_str().c_str(); - break; - } - sqlite3_result_text(ctxt, strdup(p), strlen(p), free); - return SQLITE_OK; -} - -static int -my_rowid(cursor *c, sqlite3_int64 *pRowid) { - *pRowid = c->index; - return SQLITE_OK; -} - -static int -my_bestindex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) { - return SQLITE_OK; -} - -static const sqlite3_module module = { - 0, - my_create, - my_connect, - my_bestindex, - my_disconnect, - my_destroy, - my_open, - (int (*)(sqlite3_vtab_cursor *)) my_close, - (int (*)(sqlite3_vtab_cursor *, int, char const *, int, sqlite3_value **)) my_filter, - (int (*)(sqlite3_vtab_cursor *)) my_next, - (int (*)(sqlite3_vtab_cursor *)) my_eof, - (int (*)(sqlite3_vtab_cursor *, sqlite3_context *, int)) my_column, - (int (*)(sqlite3_vtab_cursor *, sqlite3_int64 *)) my_rowid, - NULL, // my_update - NULL, // my_begin - NULL, // my_sync - NULL, // my_commit - NULL, // my_rollback - NULL, // my_findfunction - NULL, // my_rename -}; - -static void -destructor(void *arg) { - return; -} - - -extern "C" { - -EXPORT int -sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) { - SQLITE_EXTENSION_INIT2(api); - sqlite3_create_module_v2(db, "github", &module, NULL, destructor); - return 0; -} - -} diff --git a/_example/simple/Dockerfile b/_example/simple/Dockerfile deleted file mode 100644 index 8ed0473..0000000 --- a/_example/simple/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================= -# Multi-stage Dockerfile Example -# ============================================================================= -# This is a simple Dockerfile that will build an image of scratch-base image. -# Usage: -# docker build -t simple:local . && docker run --rm simple:local -# ============================================================================= - -# ----------------------------------------------------------------------------- -# Build Stage -# ----------------------------------------------------------------------------- -FROM golang:alpine3.18 AS build - -# Important: -# Because this is a CGO enabled package, you are required to set it as 1. -ENV CGO_ENABLED=1 - -RUN apk add --no-cache \ - # Important: required for go-sqlite3 - gcc \ - # Required for Alpine - musl-dev - -WORKDIR /workspace - -COPY . /workspace/ - -RUN \ - cd _example/simple && \ - go mod init github.com/mattn/sample && \ - go mod edit -replace=github.com/mattn/go-sqlite3=../.. && \ - go mod tidy && \ - go install -ldflags='-s -w -extldflags "-static"' ./simple.go - -RUN \ - # Smoke test - set -o pipefail; \ - /go/bin/simple | grep 99\ こんにちは世界099 - -# ----------------------------------------------------------------------------- -# Main Stage -# ----------------------------------------------------------------------------- -FROM scratch - -COPY --from=build /go/bin/simple /usr/local/bin/simple - -ENTRYPOINT [ "/usr/local/bin/simple" ] diff --git a/_example/simple/simple.go b/_example/simple/simple.go deleted file mode 100644 index 0c34791..0000000 --- a/_example/simple/simple.go +++ /dev/null @@ -1,109 +0,0 @@ -package main - -import ( - "database/sql" - "fmt" - _ "github.com/mattn/go-sqlite3" - "log" - "os" -) - -func main() { - os.Remove("./foo.db") - - db, err := sql.Open("sqlite3", "./foo.db") - if err != nil { - log.Fatal(err) - } - defer db.Close() - - sqlStmt := ` - create table foo (id integer not null primary key, name text); - delete from foo; - ` - _, err = db.Exec(sqlStmt) - if err != nil { - log.Printf("%q: %s\n", err, sqlStmt) - return - } - - tx, err := db.Begin() - if err != nil { - log.Fatal(err) - } - stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)") - if err != nil { - log.Fatal(err) - } - defer stmt.Close() - for i := 0; i < 100; i++ { - _, err = stmt.Exec(i, fmt.Sprintf("こんにちは世界%03d", i)) - if err != nil { - log.Fatal(err) - } - } - err = tx.Commit() - if err != nil { - log.Fatal(err) - } - - rows, err := db.Query("select id, name from foo") - if err != nil { - log.Fatal(err) - } - defer rows.Close() - for rows.Next() { - var id int - var name string - 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 { - log.Fatal(err) - } - defer stmt.Close() - var name string - err = stmt.QueryRow("3").Scan(&name) - if err != nil { - log.Fatal(err) - } - fmt.Println(name) - - _, err = db.Exec("delete from foo") - if err != nil { - log.Fatal(err) - } - - _, err = db.Exec("insert into foo(id, name) values(1, 'foo'), (2, 'bar'), (3, 'baz')") - if err != nil { - log.Fatal(err) - } - - rows, err = db.Query("select id, name from foo") - if err != nil { - log.Fatal(err) - } - defer rows.Close() - for rows.Next() { - var id int - var name string - err = rows.Scan(&id, &name) - if err != nil { - log.Fatal(err) - } - fmt.Println(id, name) - } - err = rows.Err() - if err != nil { - log.Fatal(err) - } -} diff --git a/_example/trace/main.go b/_example/trace/main.go deleted file mode 100644 index bef3d15..0000000 --- a/_example/trace/main.go +++ /dev/null @@ -1,264 +0,0 @@ -package main - -import ( - "database/sql" - "fmt" - "log" - "os" - - sqlite3 "github.com/mattn/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: 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) -} diff --git a/_example/vtable/main.go b/_example/vtable/main.go deleted file mode 100644 index aad8dda..0000000 --- a/_example/vtable/main.go +++ /dev/null @@ -1,38 +0,0 @@ -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("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, 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 deleted file mode 100644 index c65535b..0000000 --- a/_example/vtable/vtable.go +++ /dev/null @@ -1,116 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "github.com/mattn/go-sqlite3" -) - -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 - } - - var repos []githubRepo - if err := json.Unmarshal(body, &repos); err != nil { - return nil, err - } - return &ghRepoCursor{0, repos}, nil -} - -func (v *ghRepoTable) BestIndex(csts []sqlite3.InfoConstraint, ob []sqlite3.InfoOrderBy) (*sqlite3.IndexResult, error) { - used := make([]bool, len(csts)) - return &sqlite3.IndexResult{ - IdxNum: 0, - IdxStr: "default", - Used: used, - }, 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.SQLiteContext, 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 []any) 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 -} diff --git a/_example/vtable_eponymous_only/main.go b/_example/vtable_eponymous_only/main.go deleted file mode 100644 index 17b58af..0000000 --- a/_example/vtable_eponymous_only/main.go +++ /dev/null @@ -1,33 +0,0 @@ -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) - } -} diff --git a/_example/vtable_eponymous_only/vtable.go b/_example/vtable_eponymous_only/vtable.go deleted file mode 100644 index 9f22ebc..0000000 --- a/_example/vtable_eponymous_only/vtable.go +++ /dev/null @@ -1,118 +0,0 @@ -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 []any) 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 -} |