go-sqlite3-1.1.0/000077500000000000000000000000001257260042200135005ustar00rootroot00000000000000go-sqlite3-1.1.0/.gitignore000066400000000000000000000000211257260042200154610ustar00rootroot00000000000000*.db *.exe *.dll go-sqlite3-1.1.0/.travis.yml000066400000000000000000000003631257260042200156130ustar00rootroot00000000000000language: go go: - tip before_install: - go get github.com/axw/gocov/gocov - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover script: - $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx go-sqlite3-1.1.0/LICENSE000066400000000000000000000020751257260042200145110ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Yasuhiro Matsumoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. go-sqlite3-1.1.0/README.md000066400000000000000000000036561257260042200147710ustar00rootroot00000000000000go-sqlite3 ========== [![Build Status](https://travis-ci.org/mattn/go-sqlite3.png?branch=master)](https://travis-ci.org/mattn/go-sqlite3) [![Coverage Status](https://coveralls.io/repos/mattn/go-sqlite3/badge.png?branch=master)](https://coveralls.io/r/mattn/go-sqlite3?branch=master) Description ----------- sqlite3 driver conforming to the built-in database/sql interface Installation ------------ This package can be installed with the go get command: go get github.com/mattn/go-sqlite3 Documentation ------------- API documentation can be found here: http://godoc.org/github.com/mattn/go-sqlite3 Examples can be found under the `./_example` directory FAQ --- * Want to build go-sqlite3 with libsqlite3 on my linux. Use `go build --tags "libsqlite3 linux"` * Want to build go-sqlite3 with icu extension. Use `go build --tags "icu"` * Can't build go-sqlite3 on windows 64bit. > Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit. > See: https://github.com/mattn/go-sqlite3/issues/27 * Getting insert error while query is opened. > You can pass some arguments into the connection string, for example, a URI. > See: https://github.com/mattn/go-sqlite3/issues/39 * Do you want cross compiling? mingw on Linux or Mac? > See: https://github.com/mattn/go-sqlite3/issues/106 > See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html * Want to get time.Time with current locale Use `loc=auto` in SQLite3 filename schema like `file:foo.db?loc=auto`. License ------- MIT: http://mattn.mit-license.org/2012 sqlite3-binding.c, sqlite3-binding.h, sqlite3ext.h The -binding suffix was added to avoid build failures under gccgo. In this repository, those files are amalgamation code that copied from SQLite3. The license of those codes are depend on the license of SQLite3. Author ------ Yasuhiro Matsumoto (a.k.a mattn) go-sqlite3-1.1.0/_example/000077500000000000000000000000001257260042200152725ustar00rootroot00000000000000go-sqlite3-1.1.0/_example/hook/000077500000000000000000000000001257260042200162325ustar00rootroot00000000000000go-sqlite3-1.1.0/_example/hook/hook.go000066400000000000000000000025501257260042200175230ustar00rootroot00000000000000package main import ( "database/sql" "github.com/mattn/go-sqlite3" "log" "os" ) func main() { sqlite3conn := []*sqlite3.SQLiteConn{} sql.Register("sqlite3_with_hook_example", &sqlite3.SQLiteDriver{ ConnectHook: func(conn *sqlite3.SQLiteConn) error { sqlite3conn = append(sqlite3conn, conn) return nil }, }) os.Remove("./foo.db") os.Remove("./bar.db") destDb, err := sql.Open("sqlite3_with_hook_example", "./foo.db") if err != nil { log.Fatal(err) } defer destDb.Close() destDb.Ping() _, err = destDb.Exec("create table foo(id int, value text)") if err != nil { log.Fatal(err) } _, err = destDb.Exec("insert into foo values(1, 'foo')") if err != nil { log.Fatal(err) } _, err = destDb.Exec("insert into foo values(2, 'bar')") if err != nil { log.Fatal(err) } _, err = destDb.Query("select * from foo") if err != nil { log.Fatal(err) } srcDb, err := sql.Open("sqlite3_with_hook_example", "./bar.db") if err != nil { log.Fatal(err) } defer srcDb.Close() srcDb.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() } go-sqlite3-1.1.0/_example/mod_regexp/000077500000000000000000000000001257260042200174235ustar00rootroot00000000000000go-sqlite3-1.1.0/_example/mod_regexp/Makefile000066400000000000000000000005121257260042200210610ustar00rootroot00000000000000ifeq ($(OS),Windows_NT) EXE=extension.exe EXT=sqlite3_mod_regexp.dll RM=cmd /c del LDFLAG= else EXE=extension EXT=sqlite3_mod_regexp.so RM=rm LDFLAG=-fPIC endif all : $(EXE) $(EXT) $(EXE) : extension.go go build $< $(EXT) : sqlite3_mod_regexp.c gcc $(LDFLAG) -shared -o $@ $< -lsqlite3 -lpcre clean : @-$(RM) $(EXE) $(EXT) go-sqlite3-1.1.0/_example/mod_regexp/extension.go000066400000000000000000000014361257260042200217720ustar00rootroot00000000000000package main import ( "database/sql" "fmt" "github.com/mattn/go-sqlite3" "log" ) func main() { sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{ Extensions: []string{ "sqlite3_mod_regexp", }, }) db, err := sql.Open("sqlite3_with_extensions", ":memory:") if err != nil { log.Fatal(err) } defer db.Close() // Force db to make a new connection in pool // by putting the original in a transaction tx, err := db.Begin() if err != nil { log.Fatal(err) } defer tx.Commit() // New connection works (hopefully!) rows, err := db.Query("select 'hello world' where 'hello world' regexp '^hello.*d$'") if err != nil { log.Fatal(err) } defer rows.Close() for rows.Next() { var helloworld string rows.Scan(&helloworld) fmt.Println(helloworld) } } go-sqlite3-1.1.0/_example/mod_regexp/sqlite3_mod_regexp.c000066400000000000000000000017021257260042200233640ustar00rootroot00000000000000#include #include #include #include SQLITE_EXTENSION_INIT1 static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) { if (argc >= 2) { const char *target = (const char *)sqlite3_value_text(argv[1]); const char *pattern = (const char *)sqlite3_value_text(argv[0]); const char* errstr = NULL; int erroff = 0; int vec[500]; int n, rc; pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL); rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500); if (rc <= 0) { sqlite3_result_error(context, errstr, 0); return; } sqlite3_result_int(context, 1); } } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) { SQLITE_EXTENSION_INIT2(api); return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, (void*)db, regexp_func, NULL, NULL); } go-sqlite3-1.1.0/_example/mod_vtable/000077500000000000000000000000001257260042200174065ustar00rootroot00000000000000go-sqlite3-1.1.0/_example/mod_vtable/Makefile000066400000000000000000000005601257260042200210470ustar00rootroot00000000000000ifeq ($(OS),Windows_NT) EXE=extension.exe EXT=sqlite3_mod_vtable.dll RM=cmd /c del LIBCURL=-lcurldll LDFLAG= else EXE=extension EXT=sqlite3_mod_vtable.so RM=rm LDFLAG=-fPIC LIBCURL=-lcurl endif all : $(EXE) $(EXT) $(EXE) : extension.go go build $< $(EXT) : sqlite3_mod_vtable.cc g++ $(LDFLAG) -shared -o $@ $< -lsqlite3 $(LIBCURL) clean : @-$(RM) $(EXE) $(EXT) go-sqlite3-1.1.0/_example/mod_vtable/extension.go000066400000000000000000000014121257260042200217470ustar00rootroot00000000000000package main import ( "database/sql" "fmt" "github.com/mattn/go-sqlite3" "log" ) 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, 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) } } go-sqlite3-1.1.0/_example/mod_vtable/picojson.h000066400000000000000000000665741257260042200214250ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #include #include #include #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 array; typedef std::map 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 bool is() const; template const T& get() const; template 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 void serialize(Iter os) const; std::string serialize() const; private: template 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() 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() const { \ assert("type mismatch! call vis() before get()" \ && is()); \ return var; \ } \ template <> inline ctype& value::get() { \ assert("type mismatch! call is() before get()" \ && is()); \ 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()); 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::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()); return idx < u_.array_->size(); } inline bool value::contains(const std::string& key) const { assert(is()); 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 void copy(const std::string& s, Iter oi) { std::copy(s.begin(), s.end(), oi); } template 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 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 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 inline int _parse_quadhex(input &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 inline bool _parse_codepoint(String& out, input& 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 inline bool _parse_string(String& out, input& 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 inline bool _parse_array(Context& ctx, input& 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 inline bool _parse_object(Context& ctx, input& 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 inline bool _parse_number(double& out, input& 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 inline bool _parse(Context& ctx, input& 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 bool parse_string(input&) { return false; } bool parse_array_start() { return false; } template bool parse_array_item(input&, size_t) { return false; } bool parse_array_stop(size_t) { return false; } bool parse_object_start() { return false; } template bool parse_object_item(input&, 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 bool parse_string(input& in) { *out_ = value(string_type, false); return _parse_string(out_->get(), in); } bool parse_array_start() { *out_ = value(array_type, false); return true; } template bool parse_array_item(input& in, size_t) { array& a = out_->get(); 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 bool parse_object_item(input& in, const std::string& key) { object& o = out_->get(); 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 bool parse_string(input& in) { dummy_str s; return _parse_string(s, in); } bool parse_array_start() { return true; } template bool parse_array_item(input& in, size_t) { return _parse(*this, in); } bool parse_array_stop(size_t) { return true; } bool parse_object_start() { return true; } template bool parse_object_item(input& 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 inline std::string parse(value& out, Iter& pos, const Iter& last) { std::string err; pos = parse(out, pos, last, &err); return err; } template inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { input 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 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(is.rdbuf()), std::istreambuf_iterator(), &err); return err; } template struct last_error_t { static std::string s; }; template std::string last_error_t::s; inline void set_last_error(const std::string& s) { last_error_t::s = s; } inline const std::string& get_last_error() { return last_error_t::s; } inline bool operator==(const value& x, const value& y) { if (x.is()) return y.is(); #define PICOJSON_CMP(type) \ if (x.is()) \ return y.is() && x.get() == y.get() 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(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 void is(const T& x, const T& y, const char* name = "") { if (x == y) { ok(true, name); } else { ok(false, name); } } #include #include #include #include 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(); 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(), in " check type"); \ is(v.get(), 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(), "empty " #type " check type"); \ ok(v.get().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(), "array check type"); is(v.get().size(), size_t(3), "check array size"); ok(v.contains(0), "check contains array[0]"); ok(v.get(0).is(), "check array[0] type"); is(v.get(0).get(), 1.0, "check array[0] value"); ok(v.contains(1), "check contains array[1]"); ok(v.get(1).is(), "check array[1] type"); ok(v.get(1).get(), "check array[1] value"); ok(v.contains(2), "check contains array[2]"); ok(v.get(2).is(), "check array[2] type"); is(v.get(2).get(), 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(), "object check type"); is(v.get().size(), size_t(1), "check object size"); ok(v.contains("a"), "check contains property"); ok(v.get("a").is(), "check bool property exists"); is(v.get("a").get(), 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(); o.erase("b"); picojson::array& a = o["a"].get(); 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(), "swap (null)"); ok(v2.get() == true, "swap (bool)"); v1 = picojson::value("a"); v2 = picojson::value(1.0); swap(v1, v2); ok(v1.get() == 1.0, "swap (dobule)"); ok(v2.get() == "a", "swap (string)"); v1 = picojson::value(picojson::object()); v2 = picojson::value(picojson::array()); swap(v1, v2); ok(v1.is(), "swap (array)"); ok(v2.is(), "swap (object)"); } return success ? 0 : 1; } #endif go-sqlite3-1.1.0/_example/mod_vtable/sqlite3_mod_vtable.cc000066400000000000000000000125151257260042200235010ustar00rootroot00000000000000#include #include #include #include #include #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().size() ? 1 : 0; } static int my_column(cursor *c, sqlite3_context *ctxt, int i) { picojson::value v = c->rows->get()[c->index]; picojson::object row = v.get(); 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; } } go-sqlite3-1.1.0/_example/simple/000077500000000000000000000000001257260042200165635ustar00rootroot00000000000000go-sqlite3-1.1.0/_example/simple/simple.go000066400000000000000000000031211257260042200204000ustar00rootroot00000000000000package 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) } } tx.Commit() 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 rows.Scan(&id, &name) fmt.Println(id, name) } 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 rows.Scan(&id, &name) fmt.Println(id, name) } } go-sqlite3-1.1.0/backup.go000066400000000000000000000033161257260042200152770ustar00rootroot00000000000000// 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 /* #include #include */ import "C" import ( "runtime" "unsafe" ) type SQLiteBackup struct { b *C.sqlite3_backup } func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*SQLiteBackup, error) { destptr := C.CString(dest) defer C.free(unsafe.Pointer(destptr)) srcptr := C.CString(src) defer C.free(unsafe.Pointer(srcptr)) if b := C.sqlite3_backup_init(c.db, destptr, conn.db, srcptr); b != nil { bb := &SQLiteBackup{b: b} runtime.SetFinalizer(bb, (*SQLiteBackup).Finish) return bb, nil } return nil, c.lastError() } // Backs up for one step. Calls the underlying `sqlite3_backup_step` function. // This function returns a boolean indicating if the backup is done and // an error signalling any other error. Done is returned if the underlying C // function returns SQLITE_DONE (Code 101) func (b *SQLiteBackup) Step(p int) (bool, error) { ret := C.sqlite3_backup_step(b.b, C.int(p)) if ret == C.SQLITE_DONE { return true, nil } else if ret != 0 && ret != C.SQLITE_LOCKED && ret != C.SQLITE_BUSY { return false, Error{Code: ErrNo(ret)} } return false, nil } func (b *SQLiteBackup) Remaining() int { return int(C.sqlite3_backup_remaining(b.b)) } func (b *SQLiteBackup) PageCount() int { return int(C.sqlite3_backup_pagecount(b.b)) } func (b *SQLiteBackup) Finish() error { return b.Close() } func (b *SQLiteBackup) Close() error { ret := C.sqlite3_backup_finish(b.b) if ret != 0 { return Error{Code: ErrNo(ret)} } b.b = nil runtime.SetFinalizer(b, nil) return nil } go-sqlite3-1.1.0/doc.go000066400000000000000000000052201257260042200145730ustar00rootroot00000000000000/* Package sqlite3 provides interface to SQLite3 databases. This works as driver for database/sql. Installation go get github.com/mattn/go-sqlite3 Supported Types Currently, go-sqlite3 support following data types. +------------------------------+ |go | sqlite3 | |----------|-------------------| |nil | null | |int | integer | |int64 | integer | |float64 | float | |bool | integer | |[]byte | blob | |string | text | |time.Time | timestamp/datetime| +------------------------------+ SQLite3 Extension You can write your own extension module for sqlite3. For example, below is a extension for Regexp matcher operation. #include #include #include #include SQLITE_EXTENSION_INIT1 static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) { if (argc >= 2) { const char *target = (const char *)sqlite3_value_text(argv[1]); const char *pattern = (const char *)sqlite3_value_text(argv[0]); const char* errstr = NULL; int erroff = 0; int vec[500]; int n, rc; pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL); rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500); if (rc <= 0) { sqlite3_result_error(context, errstr, 0); return; } sqlite3_result_int(context, 1); } } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) { SQLITE_EXTENSION_INIT2(api); return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, (void*)db, regexp_func, NULL, NULL); } It need to build as so/dll shared library. And you need to register extension module like below. sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{ Extensions: []string{ "sqlite3_mod_regexp", }, }) Then, you can use this extension. rows, err := db.Query("select text from mytable where name regexp '^golang'") Connection Hook You can hook and inject your codes when connection established. database/sql doesn't provide the way to get native go-sqlite3 interfaces. So if you want, you need to hook ConnectHook and get the SQLiteConn. sql.Register("sqlite3_with_hook_example", &sqlite3.SQLiteDriver{ ConnectHook: func(conn *sqlite3.SQLiteConn) error { sqlite3conn = append(sqlite3conn, conn) return nil }, }) */ package sqlite3 go-sqlite3-1.1.0/error.go000066400000000000000000000126171257260042200151670ustar00rootroot00000000000000// 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 import "C" type ErrNo int const ErrNoMask C.int = 0xff type ErrNoExtended int type Error struct { Code ErrNo /* The error code returned by SQLite */ ExtendedCode ErrNoExtended /* The extended error code returned by SQLite */ err string /* The error string returned by sqlite3_errmsg(), this usually contains more specific details. */ } // result codes from http://www.sqlite.org/c3ref/c_abort.html var ( ErrError = ErrNo(1) /* SQL error or missing database */ ErrInternal = ErrNo(2) /* Internal logic error in SQLite */ ErrPerm = ErrNo(3) /* Access permission denied */ ErrAbort = ErrNo(4) /* Callback routine requested an abort */ ErrBusy = ErrNo(5) /* The database file is locked */ ErrLocked = ErrNo(6) /* A table in the database is locked */ ErrNomem = ErrNo(7) /* A malloc() failed */ ErrReadonly = ErrNo(8) /* Attempt to write a readonly database */ ErrInterrupt = ErrNo(9) /* Operation terminated by sqlite3_interrupt() */ ErrIoErr = ErrNo(10) /* Some kind of disk I/O error occurred */ ErrCorrupt = ErrNo(11) /* The database disk image is malformed */ ErrNotFound = ErrNo(12) /* Unknown opcode in sqlite3_file_control() */ ErrFull = ErrNo(13) /* Insertion failed because database is full */ ErrCantOpen = ErrNo(14) /* Unable to open the database file */ ErrProtocol = ErrNo(15) /* Database lock protocol error */ ErrEmpty = ErrNo(16) /* Database is empty */ ErrSchema = ErrNo(17) /* The database schema changed */ ErrTooBig = ErrNo(18) /* String or BLOB exceeds size limit */ ErrConstraint = ErrNo(19) /* Abort due to constraint violation */ ErrMismatch = ErrNo(20) /* Data type mismatch */ ErrMisuse = ErrNo(21) /* Library used incorrectly */ ErrNoLFS = ErrNo(22) /* Uses OS features not supported on host */ ErrAuth = ErrNo(23) /* Authorization denied */ ErrFormat = ErrNo(24) /* Auxiliary database format error */ ErrRange = ErrNo(25) /* 2nd parameter to sqlite3_bind out of range */ ErrNotADB = ErrNo(26) /* File opened that is not a database file */ ErrNotice = ErrNo(27) /* Notifications from sqlite3_log() */ ErrWarning = ErrNo(28) /* Warnings from sqlite3_log() */ ) func (err ErrNo) Error() string { return Error{Code: err}.Error() } func (err ErrNo) Extend(by int) ErrNoExtended { return ErrNoExtended(int(err) | (by << 8)) } func (err ErrNoExtended) Error() string { return Error{Code: ErrNo(C.int(err) & ErrNoMask), ExtendedCode: err}.Error() } func (err Error) Error() string { if err.err != "" { return err.err } return errorString(err) } // result codes from http://www.sqlite.org/c3ref/c_abort_rollback.html var ( ErrIoErrRead = ErrIoErr.Extend(1) ErrIoErrShortRead = ErrIoErr.Extend(2) ErrIoErrWrite = ErrIoErr.Extend(3) ErrIoErrFsync = ErrIoErr.Extend(4) ErrIoErrDirFsync = ErrIoErr.Extend(5) ErrIoErrTruncate = ErrIoErr.Extend(6) ErrIoErrFstat = ErrIoErr.Extend(7) ErrIoErrUnlock = ErrIoErr.Extend(8) ErrIoErrRDlock = ErrIoErr.Extend(9) ErrIoErrDelete = ErrIoErr.Extend(10) ErrIoErrBlocked = ErrIoErr.Extend(11) ErrIoErrNoMem = ErrIoErr.Extend(12) ErrIoErrAccess = ErrIoErr.Extend(13) ErrIoErrCheckReservedLock = ErrIoErr.Extend(14) ErrIoErrLock = ErrIoErr.Extend(15) ErrIoErrClose = ErrIoErr.Extend(16) ErrIoErrDirClose = ErrIoErr.Extend(17) ErrIoErrSHMOpen = ErrIoErr.Extend(18) ErrIoErrSHMSize = ErrIoErr.Extend(19) ErrIoErrSHMLock = ErrIoErr.Extend(20) ErrIoErrSHMMap = ErrIoErr.Extend(21) ErrIoErrSeek = ErrIoErr.Extend(22) ErrIoErrDeleteNoent = ErrIoErr.Extend(23) ErrIoErrMMap = ErrIoErr.Extend(24) ErrIoErrGetTempPath = ErrIoErr.Extend(25) ErrIoErrConvPath = ErrIoErr.Extend(26) ErrLockedSharedCache = ErrLocked.Extend(1) ErrBusyRecovery = ErrBusy.Extend(1) ErrBusySnapshot = ErrBusy.Extend(2) ErrCantOpenNoTempDir = ErrCantOpen.Extend(1) ErrCantOpenIsDir = ErrCantOpen.Extend(2) ErrCantOpenFullPath = ErrCantOpen.Extend(3) ErrCantOpenConvPath = ErrCantOpen.Extend(4) ErrCorruptVTab = ErrCorrupt.Extend(1) ErrReadonlyRecovery = ErrReadonly.Extend(1) ErrReadonlyCantLock = ErrReadonly.Extend(2) ErrReadonlyRollback = ErrReadonly.Extend(3) ErrReadonlyDbMoved = ErrReadonly.Extend(4) ErrAbortRollback = ErrAbort.Extend(2) ErrConstraintCheck = ErrConstraint.Extend(1) ErrConstraintCommitHook = ErrConstraint.Extend(2) ErrConstraintForeignKey = ErrConstraint.Extend(3) ErrConstraintFunction = ErrConstraint.Extend(4) ErrConstraintNotNull = ErrConstraint.Extend(5) ErrConstraintPrimaryKey = ErrConstraint.Extend(6) ErrConstraintTrigger = ErrConstraint.Extend(7) ErrConstraintUnique = ErrConstraint.Extend(8) ErrConstraintVTab = ErrConstraint.Extend(9) ErrConstraintRowId = ErrConstraint.Extend(10) ErrNoticeRecoverWAL = ErrNotice.Extend(1) ErrNoticeRecoverRollback = ErrNotice.Extend(2) ErrWarningAutoIndex = ErrWarning.Extend(1) ) go-sqlite3-1.1.0/error_test.go000066400000000000000000000125241257260042200162230ustar00rootroot00000000000000// 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 import ( "database/sql" "io/ioutil" "os" "path" "testing" ) func TestSimpleError(t *testing.T) { e := ErrError.Error() if e != "SQL logic error or missing database" { t.Error("wrong error code:" + e) } } func TestCorruptDbErrors(t *testing.T) { dirName, err := ioutil.TempDir("", "sqlite3") if err != nil { t.Fatal(err) } defer os.RemoveAll(dirName) dbFileName := path.Join(dirName, "test.db") f, err := os.Create(dbFileName) if err != nil { t.Error(err) } f.Write([]byte{1, 2, 3, 4, 5}) f.Close() db, err := sql.Open("sqlite3", dbFileName) if err == nil { _, err = db.Exec("drop table foo") } sqliteErr := err.(Error) if sqliteErr.Code != ErrNotADB { t.Error("wrong error code for corrupted DB") } if err.Error() == "" { t.Error("wrong error string for corrupted DB") } db.Close() } func TestSqlLogicErrors(t *testing.T) { dirName, err := ioutil.TempDir("", "sqlite3") if err != nil { t.Fatal(err) } defer os.RemoveAll(dirName) dbFileName := path.Join(dirName, "test.db") db, err := sql.Open("sqlite3", dbFileName) if err != nil { t.Error(err) } defer db.Close() _, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)") if err != nil { t.Error(err) } const expectedErr = "table Foo already exists" _, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)") if err.Error() != expectedErr { t.Errorf("Unexpected error: %s, expected %s", err.Error(), expectedErr) } } func TestExtendedErrorCodes_ForeignKey(t *testing.T) { dirName, err := ioutil.TempDir("", "sqlite3-err") if err != nil { t.Fatal(err) } defer os.RemoveAll(dirName) dbFileName := path.Join(dirName, "test.db") db, err := sql.Open("sqlite3", dbFileName) if err != nil { t.Error(err) } defer db.Close() _, err = db.Exec("PRAGMA foreign_keys=ON;") if err != nil { t.Errorf("PRAGMA foreign_keys=ON: %v", err) } _, err = db.Exec(`CREATE TABLE Foo ( id INTEGER PRIMARY KEY AUTOINCREMENT, value INTEGER NOT NULL, ref INTEGER NULL REFERENCES Foo (id), UNIQUE(value) );`) if err != nil { t.Error(err) } _, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (100, 100);") if err == nil { t.Error("No error!") } else { sqliteErr := err.(Error) if sqliteErr.Code != ErrConstraint { t.Errorf("Wrong basic error code: %d != %d", sqliteErr.Code, ErrConstraint) } if sqliteErr.ExtendedCode != ErrConstraintForeignKey { t.Errorf("Wrong extended error code: %d != %d", sqliteErr.ExtendedCode, ErrConstraintForeignKey) } } } func TestExtendedErrorCodes_NotNull(t *testing.T) { dirName, err := ioutil.TempDir("", "sqlite3-err") if err != nil { t.Fatal(err) } defer os.RemoveAll(dirName) dbFileName := path.Join(dirName, "test.db") db, err := sql.Open("sqlite3", dbFileName) if err != nil { t.Error(err) } defer db.Close() _, err = db.Exec("PRAGMA foreign_keys=ON;") if err != nil { t.Errorf("PRAGMA foreign_keys=ON: %v", err) } _, err = db.Exec(`CREATE TABLE Foo ( id INTEGER PRIMARY KEY AUTOINCREMENT, value INTEGER NOT NULL, ref INTEGER NULL REFERENCES Foo (id), UNIQUE(value) );`) if err != nil { t.Error(err) } res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);") if err != nil { t.Fatalf("Creating first row: %v", err) } id, err := res.LastInsertId() if err != nil { t.Fatalf("Retrieving last insert id: %v", err) } _, err = db.Exec("INSERT INTO Foo (ref) VALUES (?);", id) if err == nil { t.Error("No error!") } else { sqliteErr := err.(Error) if sqliteErr.Code != ErrConstraint { t.Errorf("Wrong basic error code: %d != %d", sqliteErr.Code, ErrConstraint) } if sqliteErr.ExtendedCode != ErrConstraintNotNull { t.Errorf("Wrong extended error code: %d != %d", sqliteErr.ExtendedCode, ErrConstraintNotNull) } } } func TestExtendedErrorCodes_Unique(t *testing.T) { dirName, err := ioutil.TempDir("", "sqlite3-err") if err != nil { t.Fatal(err) } defer os.RemoveAll(dirName) dbFileName := path.Join(dirName, "test.db") db, err := sql.Open("sqlite3", dbFileName) if err != nil { t.Error(err) } defer db.Close() _, err = db.Exec("PRAGMA foreign_keys=ON;") if err != nil { t.Errorf("PRAGMA foreign_keys=ON: %v", err) } _, err = db.Exec(`CREATE TABLE Foo ( id INTEGER PRIMARY KEY AUTOINCREMENT, value INTEGER NOT NULL, ref INTEGER NULL REFERENCES Foo (id), UNIQUE(value) );`) if err != nil { t.Error(err) } res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);") if err != nil { t.Fatalf("Creating first row: %v", err) } id, err := res.LastInsertId() if err != nil { t.Fatalf("Retrieving last insert id: %v", err) } _, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (?, 100);", id) if err == nil { t.Error("No error!") } else { sqliteErr := err.(Error) if sqliteErr.Code != ErrConstraint { t.Errorf("Wrong basic error code: %d != %d", sqliteErr.Code, ErrConstraint) } if sqliteErr.ExtendedCode != ErrConstraintUnique { t.Errorf("Wrong extended error code: %d != %d", sqliteErr.ExtendedCode, ErrConstraintUnique) } extended := sqliteErr.Code.Extend(3).Error() expected := "constraint failed" if extended != expected { t.Errorf("Wrong basic error code: %q != %q", extended, expected) } } } go-sqlite3-1.1.0/sqlite3-binding.c000066400000000000000000000001021257260042200166310ustar00rootroot00000000000000#ifndef USE_LIBSQLITE3 # include "code/sqlite3-binding.c" #endif go-sqlite3-1.1.0/sqlite3-binding.h000066400000000000000000000001331257260042200166420ustar00rootroot00000000000000#ifndef USE_LIBSQLITE3 #include "code/sqlite3-binding.h" #else #include #endif go-sqlite3-1.1.0/sqlite3.go000066400000000000000000000363051257260042200154220ustar00rootroot00000000000000// 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 /* #cgo CFLAGS: -std=gnu99 #cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE #cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS #include #include #include #ifdef __CYGWIN__ # include #endif #ifndef SQLITE_OPEN_READWRITE # define SQLITE_OPEN_READWRITE 0 #endif #ifndef SQLITE_OPEN_FULLMUTEX # define SQLITE_OPEN_FULLMUTEX 0 #endif static int _sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs) { #ifdef SQLITE_OPEN_URI return sqlite3_open_v2(filename, ppDb, flags | SQLITE_OPEN_URI, zVfs); #else return sqlite3_open_v2(filename, ppDb, flags, zVfs); #endif } static int _sqlite3_bind_text(sqlite3_stmt *stmt, int n, char *p, int np) { return sqlite3_bind_text(stmt, n, p, np, SQLITE_TRANSIENT); } static int _sqlite3_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) { return sqlite3_bind_blob(stmt, n, p, np, SQLITE_TRANSIENT); } #include #include static int _sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* changes) { int rv = sqlite3_exec(db, pcmd, 0, 0, 0); *rowid = (long long) sqlite3_last_insert_rowid(db); *changes = (long long) sqlite3_changes(db); return rv; } static int _sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes) { int rv = sqlite3_step(stmt); sqlite3* db = sqlite3_db_handle(stmt); *rowid = (long long) sqlite3_last_insert_rowid(db); *changes = (long long) sqlite3_changes(db); return rv; } */ import "C" import ( "database/sql" "database/sql/driver" "errors" "fmt" "io" "net/url" "runtime" "strconv" "strings" "time" "unsafe" ) // Timestamp formats understood by both this module and SQLite. // The first format in the slice will be used when saving time values // into the database. When parsing a string from a timestamp or // datetime column, the formats are tried in order. var SQLiteTimestampFormats = []string{ "2006-01-02 15:04:05.999999999", "2006-01-02T15:04:05.999999999", "2006-01-02 15:04:05", "2006-01-02T15:04:05", "2006-01-02 15:04", "2006-01-02T15:04", "2006-01-02", "2006-01-02 15:04:05-07:00", } func init() { sql.Register("sqlite3", &SQLiteDriver{}) } // Return SQLite library Version information. func Version() (libVersion string, libVersionNumber int, sourceId string) { libVersion = C.GoString(C.sqlite3_libversion()) libVersionNumber = int(C.sqlite3_libversion_number()) sourceId = C.GoString(C.sqlite3_sourceid()) return libVersion, libVersionNumber, sourceId } // Driver struct. type SQLiteDriver struct { Extensions []string ConnectHook func(*SQLiteConn) error } // Conn struct. type SQLiteConn struct { db *C.sqlite3 loc *time.Location txlock string } // Tx struct. type SQLiteTx struct { c *SQLiteConn } // Stmt struct. type SQLiteStmt struct { c *SQLiteConn s *C.sqlite3_stmt nv int nn []string t string closed bool cls bool } // Result struct. type SQLiteResult struct { id int64 changes int64 } // Rows struct. type SQLiteRows struct { s *SQLiteStmt nc int cols []string decltype []string cls bool } // Commit transaction. func (tx *SQLiteTx) Commit() error { _, err := tx.c.exec("COMMIT") return err } // Rollback transaction. func (tx *SQLiteTx) Rollback() error { _, err := tx.c.exec("ROLLBACK") return err } // AutoCommit return which currently auto commit or not. func (c *SQLiteConn) AutoCommit() bool { return int(C.sqlite3_get_autocommit(c.db)) != 0 } func (c *SQLiteConn) lastError() Error { return Error{ Code: ErrNo(C.sqlite3_errcode(c.db)), ExtendedCode: ErrNoExtended(C.sqlite3_extended_errcode(c.db)), err: C.GoString(C.sqlite3_errmsg(c.db)), } } // Implements Execer func (c *SQLiteConn) Exec(query string, args []driver.Value) (driver.Result, error) { if len(args) == 0 { return c.exec(query) } for { s, err := c.Prepare(query) if err != nil { return nil, err } var res driver.Result if s.(*SQLiteStmt).s != nil { na := s.NumInput() if len(args) < na { return nil, fmt.Errorf("Not enough args to execute query. Expected %d, got %d.", na, len(args)) } res, err = s.Exec(args[:na]) if err != nil && err != driver.ErrSkip { s.Close() return nil, err } args = args[na:] } tail := s.(*SQLiteStmt).t s.Close() if tail == "" { return res, nil } query = tail } } // Implements Queryer func (c *SQLiteConn) Query(query string, args []driver.Value) (driver.Rows, error) { for { s, err := c.Prepare(query) if err != nil { return nil, err } s.(*SQLiteStmt).cls = true na := s.NumInput() if len(args) < na { return nil, fmt.Errorf("Not enough args to execute query. Expected %d, got %d.", na, len(args)) } rows, err := s.Query(args[:na]) if err != nil && err != driver.ErrSkip { s.Close() return nil, err } args = args[na:] tail := s.(*SQLiteStmt).t if tail == "" { return rows, nil } rows.Close() s.Close() query = tail } } func (c *SQLiteConn) exec(cmd string) (driver.Result, error) { pcmd := C.CString(cmd) defer C.free(unsafe.Pointer(pcmd)) var rowid, changes C.longlong rv := C._sqlite3_exec(c.db, pcmd, &rowid, &changes) if rv != C.SQLITE_OK { return nil, c.lastError() } return &SQLiteResult{int64(rowid), int64(changes)}, nil } // Begin transaction. func (c *SQLiteConn) Begin() (driver.Tx, error) { if _, err := c.exec(c.txlock); err != nil { return nil, err } return &SQLiteTx{c}, nil } func errorString(err Error) string { return C.GoString(C.sqlite3_errstr(C.int(err.Code))) } // Open database and return a new connection. // You can specify DSN string with URI filename. // test.db // file:test.db?cache=shared&mode=memory // :memory: // file::memory: // go-sqlite handle especially query parameters. // _loc=XXX // Specify location of time format. It's possible to specify "auto". // _busy_timeout=XXX // Specify value for sqlite3_busy_timeout. // _txlock=XXX // Specify locking behavior for transactions. XXX can be "immediate", // "deferred", "exclusive". func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { if C.sqlite3_threadsafe() == 0 { return nil, errors.New("sqlite library was not compiled for thread-safe operation") } var loc *time.Location txlock := "BEGIN" busy_timeout := 5000 pos := strings.IndexRune(dsn, '?') if pos >= 1 { params, err := url.ParseQuery(dsn[pos+1:]) if err != nil { return nil, err } // _loc if val := params.Get("_loc"); val != "" { if val == "auto" { loc = time.Local } else { loc, err = time.LoadLocation(val) if err != nil { return nil, fmt.Errorf("Invalid _loc: %v: %v", val, err) } } } // _busy_timeout if val := params.Get("_busy_timeout"); val != "" { iv, err := strconv.ParseInt(val, 10, 64) if err != nil { return nil, fmt.Errorf("Invalid _busy_timeout: %v: %v", val, err) } busy_timeout = int(iv) } // _txlock if val := params.Get("_txlock"); val != "" { switch val { case "immediate": txlock = "BEGIN IMMEDIATE" case "exclusive": txlock = "BEGIN EXCLUSIVE" case "deferred": txlock = "BEGIN" default: return nil, fmt.Errorf("Invalid _txlock: %v", val) } } if !strings.HasPrefix(dsn, "file:") { dsn = dsn[:pos] } } var db *C.sqlite3 name := C.CString(dsn) defer C.free(unsafe.Pointer(name)) rv := C._sqlite3_open_v2(name, &db, C.SQLITE_OPEN_FULLMUTEX| C.SQLITE_OPEN_READWRITE| C.SQLITE_OPEN_CREATE, nil) if rv != 0 { return nil, Error{Code: ErrNo(rv)} } if db == nil { return nil, errors.New("sqlite succeeded without returning a database") } rv = C.sqlite3_busy_timeout(db, C.int(busy_timeout)) if rv != C.SQLITE_OK { return nil, Error{Code: ErrNo(rv)} } conn := &SQLiteConn{db: db, loc: loc, txlock: txlock} if len(d.Extensions) > 0 { if err := conn.loadExtensions(d.Extensions); err != nil { return nil, err } } if d.ConnectHook != nil { if err := d.ConnectHook(conn); err != nil { return nil, err } } runtime.SetFinalizer(conn, (*SQLiteConn).Close) return conn, nil } // Close the connection. func (c *SQLiteConn) Close() error { rv := C.sqlite3_close_v2(c.db) if rv != C.SQLITE_OK { return c.lastError() } c.db = nil runtime.SetFinalizer(c, nil) return nil } // Prepare query string. Return a new statement. func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) { pquery := C.CString(query) defer C.free(unsafe.Pointer(pquery)) var s *C.sqlite3_stmt var tail *C.char rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail) if rv != C.SQLITE_OK { return nil, c.lastError() } var t string if tail != nil && *tail != '\000' { t = strings.TrimSpace(C.GoString(tail)) } nv := int(C.sqlite3_bind_parameter_count(s)) var nn []string for i := 0; i < nv; i++ { pn := C.GoString(C.sqlite3_bind_parameter_name(s, C.int(i+1))) if len(pn) > 1 && pn[0] == '$' && 48 <= pn[1] && pn[1] <= 57 { nn = append(nn, C.GoString(C.sqlite3_bind_parameter_name(s, C.int(i+1)))) } } ss := &SQLiteStmt{c: c, s: s, nv: nv, nn: nn, t: t} runtime.SetFinalizer(ss, (*SQLiteStmt).Close) return ss, nil } // Close the statement. func (s *SQLiteStmt) Close() error { if s.closed { return nil } s.closed = true if s.c == nil || s.c.db == nil { return errors.New("sqlite statement with already closed database connection") } rv := C.sqlite3_finalize(s.s) if rv != C.SQLITE_OK { return s.c.lastError() } runtime.SetFinalizer(s, nil) return nil } // Return a number of parameters. func (s *SQLiteStmt) NumInput() int { return s.nv } type bindArg struct { n int v driver.Value } func (s *SQLiteStmt) bind(args []driver.Value) error { rv := C.sqlite3_reset(s.s) if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE { return s.c.lastError() } var vargs []bindArg narg := len(args) vargs = make([]bindArg, narg) if len(s.nn) > 0 { for i, v := range s.nn { if pi, err := strconv.Atoi(v[1:]); err == nil { vargs[i] = bindArg{pi, args[i]} } } } else { for i, v := range args { vargs[i] = bindArg{i + 1, v} } } for _, varg := range vargs { n := C.int(varg.n) v := varg.v switch v := v.(type) { case nil: rv = C.sqlite3_bind_null(s.s, n) case string: if len(v) == 0 { b := []byte{0} rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(0)) } else { b := []byte(v) rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b))) } case int64: rv = C.sqlite3_bind_int64(s.s, n, C.sqlite3_int64(v)) case bool: if bool(v) { rv = C.sqlite3_bind_int(s.s, n, 1) } else { rv = C.sqlite3_bind_int(s.s, n, 0) } case float64: rv = C.sqlite3_bind_double(s.s, n, C.double(v)) case []byte: var p *byte if len(v) > 0 { p = &v[0] } rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(p), C.int(len(v))) case time.Time: b := []byte(v.UTC().Format(SQLiteTimestampFormats[0])) rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b))) } if rv != C.SQLITE_OK { return s.c.lastError() } } return nil } // Query the statement with arguments. Return records. func (s *SQLiteStmt) Query(args []driver.Value) (driver.Rows, error) { if err := s.bind(args); err != nil { return nil, err } return &SQLiteRows{s, int(C.sqlite3_column_count(s.s)), nil, nil, s.cls}, nil } // Return last inserted ID. func (r *SQLiteResult) LastInsertId() (int64, error) { return r.id, nil } // Return how many rows affected. func (r *SQLiteResult) RowsAffected() (int64, error) { return r.changes, nil } // Execute the statement with arguments. Return result object. func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) { if err := s.bind(args); err != nil { C.sqlite3_reset(s.s) C.sqlite3_clear_bindings(s.s) return nil, err } var rowid, changes C.longlong rv := C._sqlite3_step(s.s, &rowid, &changes) if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE { err := s.c.lastError() C.sqlite3_reset(s.s) C.sqlite3_clear_bindings(s.s) return nil, err } return &SQLiteResult{int64(rowid), int64(changes)}, nil } // Close the rows. func (rc *SQLiteRows) Close() error { if rc.s.closed { return nil } if rc.cls { return rc.s.Close() } rv := C.sqlite3_reset(rc.s.s) if rv != C.SQLITE_OK { return rc.s.c.lastError() } return nil } // Return column names. func (rc *SQLiteRows) Columns() []string { if rc.nc != len(rc.cols) { rc.cols = make([]string, rc.nc) for i := 0; i < rc.nc; i++ { rc.cols[i] = C.GoString(C.sqlite3_column_name(rc.s.s, C.int(i))) } } return rc.cols } // Move cursor to next. func (rc *SQLiteRows) Next(dest []driver.Value) error { rv := C.sqlite3_step(rc.s.s) if rv == C.SQLITE_DONE { return io.EOF } if rv != C.SQLITE_ROW { rv = C.sqlite3_reset(rc.s.s) if rv != C.SQLITE_OK { return rc.s.c.lastError() } return nil } if rc.decltype == nil { rc.decltype = make([]string, rc.nc) for i := 0; i < rc.nc; i++ { rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i)))) } } for i := range dest { switch C.sqlite3_column_type(rc.s.s, C.int(i)) { case C.SQLITE_INTEGER: val := int64(C.sqlite3_column_int64(rc.s.s, C.int(i))) switch rc.decltype[i] { case "timestamp", "datetime", "date": unixTimestamp := strconv.FormatInt(val, 10) var t time.Time if len(unixTimestamp) == 13 { duration, err := time.ParseDuration(unixTimestamp + "ms") if err != nil { return fmt.Errorf("error parsing %s value %d, %s", rc.decltype[i], val, err) } epoch := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC) t = epoch.Add(duration) } else { t = time.Unix(val, 0) } if rc.s.c.loc != nil { t = t.In(rc.s.c.loc) } dest[i] = t case "boolean": dest[i] = val > 0 default: dest[i] = val } case C.SQLITE_FLOAT: dest[i] = float64(C.sqlite3_column_double(rc.s.s, C.int(i))) case C.SQLITE_BLOB: p := C.sqlite3_column_blob(rc.s.s, C.int(i)) if p == nil { dest[i] = nil continue } n := int(C.sqlite3_column_bytes(rc.s.s, C.int(i))) switch dest[i].(type) { case sql.RawBytes: dest[i] = (*[1 << 30]byte)(unsafe.Pointer(p))[0:n] default: slice := make([]byte, n) copy(slice[:], (*[1 << 30]byte)(unsafe.Pointer(p))[0:n]) dest[i] = slice } case C.SQLITE_NULL: dest[i] = nil case C.SQLITE_TEXT: var err error var timeVal time.Time n := int(C.sqlite3_column_bytes(rc.s.s, C.int(i))) s := C.GoStringN((*C.char)(unsafe.Pointer(C.sqlite3_column_text(rc.s.s, C.int(i)))), C.int(n)) switch rc.decltype[i] { case "timestamp", "datetime", "date": var t time.Time s = strings.TrimSuffix(s, "Z") for _, format := range SQLiteTimestampFormats { if timeVal, err = time.ParseInLocation(format, s, time.UTC); err == nil { t = timeVal break } } if err != nil { // The column is a time value, so return the zero time on parse failure. t = time.Time{} } if rc.s.c.loc != nil { t = t.In(rc.s.c.loc) } dest[i] = t default: dest[i] = []byte(s) } } } return nil } go-sqlite3-1.1.0/sqlite3_fts3_test.go000066400000000000000000000041451257260042200174150ustar00rootroot00000000000000// Copyright (C) 2015 Yasuhiro Matsumoto . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. package sqlite3 import ( "database/sql" "os" "testing" ) func TestFTS3(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("DROP TABLE foo") _, err = db.Exec("CREATE VIRTUAL TABLE foo USING fts3(id INTEGER PRIMARY KEY, value TEXT)") if err != nil { t.Fatal("Failed to create table:", err) } _, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 1, `今日の 晩御飯は 天麩羅よ`) if err != nil { t.Fatal("Failed to insert value:", err) } _, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 2, `今日は いい 天気だ`) if err != nil { t.Fatal("Failed to insert value:", err) } rows, err := db.Query("SELECT id, value FROM foo WHERE value MATCH '今日* 天*'") if err != nil { t.Fatal("Unable to query foo table:", err) } defer rows.Close() for rows.Next() { var id int var value string if err := rows.Scan(&id, &value); err != nil { t.Error("Unable to scan results:", err) continue } if id == 1 && value != `今日の 晩御飯は 天麩羅よ` { t.Error("Value for id 1 should be `今日の 晩御飯は 天麩羅よ`, but:", value) } else if id == 2 && value != `今日は いい 天気だ` { t.Error("Value for id 2 should be `今日は いい 天気だ`, but:", value) } } rows, err = db.Query("SELECT value FROM foo WHERE value MATCH '今日* 天麩羅*'") if err != nil { t.Fatal("Unable to query foo table:", err) } defer rows.Close() var value string if !rows.Next() { t.Fatal("Result should be only one") } if err := rows.Scan(&value); err != nil { t.Fatal("Unable to scan results:", err) } if value != `今日の 晩御飯は 天麩羅よ` { t.Fatal("Value should be `今日の 晩御飯は 天麩羅よ`, but:", value) } if rows.Next() { t.Fatal("Result should be only one") } } go-sqlite3-1.1.0/sqlite3_icu.go000066400000000000000000000004361257260042200162560ustar00rootroot00000000000000// 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. // +build icu package sqlite3 /* #cgo LDFLAGS: -licuuc -licui18n #cgo CFLAGS: -DSQLITE_ENABLE_ICU */ import "C" go-sqlite3-1.1.0/sqlite3_libsqlite3.go000066400000000000000000000004311257260042200175440ustar00rootroot00000000000000// 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. // +build libsqlite3 package sqlite3 /* #cgo CFLAGS: -DUSE_LIBSQLITE3 #cgo LDFLAGS: -lsqlite3 */ import "C" go-sqlite3-1.1.0/sqlite3_load_extension.go000066400000000000000000000016261257260042200205130ustar00rootroot00000000000000// 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. // +build !sqlite_omit_load_extension package sqlite3 /* #include #include */ import "C" import ( "errors" "unsafe" ) func (c *SQLiteConn) loadExtensions(extensions []string) error { rv := C.sqlite3_enable_load_extension(c.db, 1) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } for _, extension := range extensions { cext := C.CString(extension) defer C.free(unsafe.Pointer(cext)) rv = C.sqlite3_load_extension(c.db, cext, nil, nil) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } } rv = C.sqlite3_enable_load_extension(c.db, 0) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } return nil } go-sqlite3-1.1.0/sqlite3_omit_load_extension.go000066400000000000000000000006741257260042200215450ustar00rootroot00000000000000// 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. // +build sqlite_omit_load_extension package sqlite3 /* #cgo CFLAGS: -DSQLITE_OMIT_LOAD_EXTENSION */ import "C" import ( "errors" ) func (c *SQLiteConn) loadExtensions(extensions []string) error { return errors.New("Extensions have been disabled for static builds") } go-sqlite3-1.1.0/sqlite3_other.go000066400000000000000000000004131257260042200166120ustar00rootroot00000000000000// 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. // +build !windows package sqlite3 /* #cgo CFLAGS: -I. #cgo linux LDFLAGS: -ldl */ import "C" go-sqlite3-1.1.0/sqlite3_test.go000066400000000000000000000635461257260042200164700ustar00rootroot00000000000000// 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 import ( "crypto/rand" "database/sql" "database/sql/driver" "encoding/hex" "errors" "fmt" "net/url" "os" "path/filepath" "strings" "testing" "time" "github.com/mattn/go-sqlite3/sqlite3_test" ) func TempFilename() string { randBytes := make([]byte, 16) rand.Read(randBytes) return filepath.Join(os.TempDir(), "foo"+hex.EncodeToString(randBytes)+".db") } func doTestOpen(t *testing.T, option string) (string, error) { var url string tempFilename := TempFilename() if option != "" { url = tempFilename + option } else { url = tempFilename } db, err := sql.Open("sqlite3", url) if err != nil { return "Failed to open database:", err } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("drop table foo") _, err = db.Exec("create table foo (id integer)") if err != nil { return "Failed to create table:", err } if stat, err := os.Stat(tempFilename); err != nil || stat.IsDir() { return "Failed to create ./foo.db", nil } return "", nil } func TestOpen(t *testing.T) { cases := map[string]bool{ "": true, "?_txlock=immediate": true, "?_txlock=deferred": true, "?_txlock=exclusive": true, "?_txlock=bogus": false, } for option, expectedPass := range cases { result, err := doTestOpen(t, option) if result == "" { if !expectedPass { errmsg := fmt.Sprintf("_txlock error not caught at dbOpen with option: %s", option) t.Fatal(errmsg) } } else if expectedPass { if err == nil { t.Fatal(result) } else { t.Fatal(result, err) } } } } func TestClose(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) _, err = db.Exec("drop table foo") _, err = db.Exec("create table foo (id integer)") if err != nil { t.Fatal("Failed to create table:", err) } stmt, err := db.Prepare("select id from foo where id = ?") if err != nil { t.Fatal("Failed to select records:", err) } db.Close() _, err = stmt.Exec(1) if err == nil { t.Fatal("Failed to operate closed statement") } } func TestInsert(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("drop table foo") _, err = db.Exec("create table foo (id integer)") if err != nil { t.Fatal("Failed to create table:", err) } res, err := db.Exec("insert into foo(id) values(123)") if err != nil { t.Fatal("Failed to insert record:", err) } affected, _ := res.RowsAffected() if affected != 1 { t.Fatalf("Expected %d for affected rows, but %d:", 1, affected) } rows, err := db.Query("select id from foo") if err != nil { t.Fatal("Failed to select records:", err) } defer rows.Close() rows.Next() var result int rows.Scan(&result) if result != 123 { t.Errorf("Fetched %q; expected %q", 123, result) } } func TestUpdate(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("drop table foo") _, err = db.Exec("create table foo (id integer)") if err != nil { t.Fatal("Failed to create table:", err) } res, err := db.Exec("insert into foo(id) values(123)") if err != nil { t.Fatal("Failed to insert record:", err) } expected, err := res.LastInsertId() if err != nil { t.Fatal("Failed to get LastInsertId:", err) } affected, _ := res.RowsAffected() if err != nil { t.Fatal("Failed to get RowsAffected:", err) } if affected != 1 { t.Fatalf("Expected %d for affected rows, but %d:", 1, affected) } res, err = db.Exec("update foo set id = 234") if err != nil { t.Fatal("Failed to update record:", err) } lastId, err := res.LastInsertId() if err != nil { t.Fatal("Failed to get LastInsertId:", err) } if expected != lastId { t.Errorf("Expected %q for last Id, but %q:", expected, lastId) } affected, _ = res.RowsAffected() if err != nil { t.Fatal("Failed to get RowsAffected:", err) } if affected != 1 { t.Fatalf("Expected %d for affected rows, but %d:", 1, affected) } rows, err := db.Query("select id from foo") if err != nil { t.Fatal("Failed to select records:", err) } defer rows.Close() rows.Next() var result int rows.Scan(&result) if result != 234 { t.Errorf("Fetched %q; expected %q", 234, result) } } func TestDelete(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("drop table foo") _, err = db.Exec("create table foo (id integer)") if err != nil { t.Fatal("Failed to create table:", err) } res, err := db.Exec("insert into foo(id) values(123)") if err != nil { t.Fatal("Failed to insert record:", err) } expected, err := res.LastInsertId() if err != nil { t.Fatal("Failed to get LastInsertId:", err) } affected, err := res.RowsAffected() if err != nil { t.Fatal("Failed to get RowsAffected:", err) } if affected != 1 { t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected) } res, err = db.Exec("delete from foo where id = 123") if err != nil { t.Fatal("Failed to delete record:", err) } lastId, err := res.LastInsertId() if err != nil { t.Fatal("Failed to get LastInsertId:", err) } if expected != lastId { t.Errorf("Expected %q for last Id, but %q:", expected, lastId) } affected, err = res.RowsAffected() if err != nil { t.Fatal("Failed to get RowsAffected:", err) } if affected != 1 { t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected) } rows, err := db.Query("select id from foo") if err != nil { t.Fatal("Failed to select records:", err) } defer rows.Close() if rows.Next() { t.Error("Fetched row but expected not rows") } } func TestBooleanRoundtrip(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("DROP TABLE foo") _, err = db.Exec("CREATE TABLE foo(id INTEGER, value BOOL)") if err != nil { t.Fatal("Failed to create table:", err) } _, err = db.Exec("INSERT INTO foo(id, value) VALUES(1, ?)", true) if err != nil { t.Fatal("Failed to insert true value:", err) } _, err = db.Exec("INSERT INTO foo(id, value) VALUES(2, ?)", false) if err != nil { t.Fatal("Failed to insert false value:", err) } rows, err := db.Query("SELECT id, value FROM foo") if err != nil { t.Fatal("Unable to query foo table:", err) } defer rows.Close() for rows.Next() { var id int var value bool if err := rows.Scan(&id, &value); err != nil { t.Error("Unable to scan results:", err) continue } if id == 1 && !value { t.Error("Value for id 1 should be true, not false") } else if id == 2 && value { t.Error("Value for id 2 should be false, not true") } } } func TestTimestamp(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("DROP TABLE foo") _, err = db.Exec("CREATE TABLE foo(id INTEGER, ts timeSTAMP, dt DATETIME)") if err != nil { t.Fatal("Failed to create table:", err) } timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC) timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC) timestamp3 := time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC) tests := []struct { value interface{} expected time.Time }{ {"nonsense", time.Time{}}, {"0000-00-00 00:00:00", time.Time{}}, {timestamp1, timestamp1}, {timestamp1.Unix(), timestamp1}, {timestamp1.UnixNano() / int64(time.Millisecond), timestamp1}, {timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1}, {timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1}, {timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1}, {timestamp1.Format("2006-01-02 15:04:05"), timestamp1}, {timestamp1.Format("2006-01-02T15:04:05"), timestamp1}, {timestamp2, timestamp2}, {"2006-01-02 15:04:05.123456789", timestamp2}, {"2006-01-02T15:04:05.123456789", timestamp2}, {"2012-11-04", timestamp3}, {"2012-11-04 00:00", timestamp3}, {"2012-11-04 00:00:00", timestamp3}, {"2012-11-04 00:00:00.000", timestamp3}, {"2012-11-04T00:00", timestamp3}, {"2012-11-04T00:00:00", timestamp3}, {"2012-11-04T00:00:00.000", timestamp3}, } for i := range tests { _, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value) if err != nil { t.Fatal("Failed to insert timestamp:", err) } } rows, err := db.Query("SELECT id, ts, dt FROM foo ORDER BY id ASC") if err != nil { t.Fatal("Unable to query foo table:", err) } defer rows.Close() seen := 0 for rows.Next() { var id int var ts, dt time.Time if err := rows.Scan(&id, &ts, &dt); err != nil { t.Error("Unable to scan results:", err) continue } if id < 0 || id >= len(tests) { t.Error("Bad row id: ", id) continue } seen++ if !tests[id].expected.Equal(ts) { t.Errorf("Timestamp value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt) } if !tests[id].expected.Equal(dt) { t.Errorf("Datetime value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt) } } if seen != len(tests) { t.Errorf("Expected to see %d rows", len(tests)) } } func TestBoolean(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("CREATE TABLE foo(id INTEGER, fbool BOOLEAN)") if err != nil { t.Fatal("Failed to create table:", err) } bool1 := true _, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(1, ?)", bool1) if err != nil { t.Fatal("Failed to insert boolean:", err) } bool2 := false _, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(2, ?)", bool2) if err != nil { t.Fatal("Failed to insert boolean:", err) } bool3 := "nonsense" _, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(3, ?)", bool3) if err != nil { t.Fatal("Failed to insert nonsense:", err) } rows, err := db.Query("SELECT id, fbool FROM foo where fbool = ?", bool1) if err != nil { t.Fatal("Unable to query foo table:", err) } counter := 0 var id int var fbool bool for rows.Next() { if err := rows.Scan(&id, &fbool); err != nil { t.Fatal("Unable to scan results:", err) } counter++ } if counter != 1 { t.Fatalf("Expected 1 row but %v", counter) } if id != 1 && fbool != true { t.Fatalf("Value for id 1 should be %v, not %v", bool1, fbool) } rows, err = db.Query("SELECT id, fbool FROM foo where fbool = ?", bool2) if err != nil { t.Fatal("Unable to query foo table:", err) } counter = 0 for rows.Next() { if err := rows.Scan(&id, &fbool); err != nil { t.Fatal("Unable to scan results:", err) } counter++ } if counter != 1 { t.Fatalf("Expected 1 row but %v", counter) } if id != 2 && fbool != false { t.Fatalf("Value for id 2 should be %v, not %v", bool2, fbool) } // make sure "nonsense" triggered an error rows, err = db.Query("SELECT id, fbool FROM foo where id=?;", 3) if err != nil { t.Fatal("Unable to query foo table:", err) } rows.Next() err = rows.Scan(&id, &fbool) if err == nil { t.Error("Expected error from \"nonsense\" bool") } } func TestFloat32(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("CREATE TABLE foo(id INTEGER)") if err != nil { t.Fatal("Failed to create table:", err) } _, err = db.Exec("INSERT INTO foo(id) VALUES(null)") if err != nil { t.Fatal("Failed to insert null:", err) } rows, err := db.Query("SELECT id FROM foo") if err != nil { t.Fatal("Unable to query foo table:", err) } if !rows.Next() { t.Fatal("Unable to query results:", err) } var id interface{} if err := rows.Scan(&id); err != nil { t.Fatal("Unable to scan results:", err) } if id != nil { t.Error("Expected nil but not") } } func TestNull(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() rows, err := db.Query("SELECT 3.141592") if err != nil { t.Fatal("Unable to query foo table:", err) } if !rows.Next() { t.Fatal("Unable to query results:", err) } var v interface{} if err := rows.Scan(&v); err != nil { t.Fatal("Unable to scan results:", err) } f, ok := v.(float64) if !ok { t.Error("Expected float but not") } if f != 3.141592 { t.Error("Expected 3.141592 but not") } } func TestTransaction(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("CREATE TABLE foo(id INTEGER)") if err != nil { t.Fatal("Failed to create table:", err) } tx, err := db.Begin() if err != nil { t.Fatal("Failed to begin transaction:", err) } _, err = tx.Exec("INSERT INTO foo(id) VALUES(1)") if err != nil { t.Fatal("Failed to insert null:", err) } rows, err := tx.Query("SELECT id from foo") if err != nil { t.Fatal("Unable to query foo table:", err) } err = tx.Rollback() if err != nil { t.Fatal("Failed to rollback transaction:", err) } if rows.Next() { t.Fatal("Unable to query results:", err) } tx, err = db.Begin() if err != nil { t.Fatal("Failed to begin transaction:", err) } _, err = tx.Exec("INSERT INTO foo(id) VALUES(1)") if err != nil { t.Fatal("Failed to insert null:", err) } err = tx.Commit() if err != nil { t.Fatal("Failed to commit transaction:", err) } rows, err = tx.Query("SELECT id from foo") if err == nil { t.Fatal("Expected failure to query") } } func TestWAL(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() if _, err = db.Exec("PRAGMA journal_mode=WAL;"); err != nil { t.Fatal("Failed to Exec PRAGMA journal_mode:", err) } if _, err = db.Exec("PRAGMA locking_mode=EXCLUSIVE;"); err != nil { t.Fatal("Failed to Exec PRAGMA locking_mode:", err) } if _, err = db.Exec("CREATE TABLE test (id SERIAL, user TEXT NOT NULL, name TEXT NOT NULL);"); err != nil { t.Fatal("Failed to Exec CREATE TABLE:", err) } if _, err = db.Exec("INSERT INTO test (user, name) VALUES ('user','name');"); err != nil { t.Fatal("Failed to Exec INSERT:", err) } trans, err := db.Begin() if err != nil { t.Fatal("Failed to Begin:", err) } s, err := trans.Prepare("INSERT INTO test (user, name) VALUES (?, ?);") if err != nil { t.Fatal("Failed to Prepare:", err) } var count int if err = trans.QueryRow("SELECT count(user) FROM test;").Scan(&count); err != nil { t.Fatal("Failed to QueryRow:", err) } if _, err = s.Exec("bbbb", "aaaa"); err != nil { t.Fatal("Failed to Exec prepared statement:", err) } if err = s.Close(); err != nil { t.Fatal("Failed to Close prepared statement:", err) } if err = trans.Commit(); err != nil { t.Fatal("Failed to Commit:", err) } } func TestTimezoneConversion(t *testing.T) { zones := []string{"UTC", "US/Central", "US/Pacific", "Local"} for _, tz := range zones { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename+"?_loc="+url.QueryEscape(tz)) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec("DROP TABLE foo") _, err = db.Exec("CREATE TABLE foo(id INTEGER, ts TIMESTAMP, dt DATETIME)") if err != nil { t.Fatal("Failed to create table:", err) } loc, err := time.LoadLocation(tz) if err != nil { t.Fatal("Failed to load location:", err) } timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC) timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC) timestamp3 := time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC) tests := []struct { value interface{} expected time.Time }{ {"nonsense", time.Time{}.In(loc)}, {"0000-00-00 00:00:00", time.Time{}.In(loc)}, {timestamp1, timestamp1.In(loc)}, {timestamp1.Unix(), timestamp1.In(loc)}, {timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1.In(loc)}, {timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1.In(loc)}, {timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1.In(loc)}, {timestamp1.Format("2006-01-02 15:04:05"), timestamp1.In(loc)}, {timestamp1.Format("2006-01-02T15:04:05"), timestamp1.In(loc)}, {timestamp2, timestamp2.In(loc)}, {"2006-01-02 15:04:05.123456789", timestamp2.In(loc)}, {"2006-01-02T15:04:05.123456789", timestamp2.In(loc)}, {"2012-11-04", timestamp3.In(loc)}, {"2012-11-04 00:00", timestamp3.In(loc)}, {"2012-11-04 00:00:00", timestamp3.In(loc)}, {"2012-11-04 00:00:00.000", timestamp3.In(loc)}, {"2012-11-04T00:00", timestamp3.In(loc)}, {"2012-11-04T00:00:00", timestamp3.In(loc)}, {"2012-11-04T00:00:00.000", timestamp3.In(loc)}, } for i := range tests { _, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value) if err != nil { t.Fatal("Failed to insert timestamp:", err) } } rows, err := db.Query("SELECT id, ts, dt FROM foo ORDER BY id ASC") if err != nil { t.Fatal("Unable to query foo table:", err) } defer rows.Close() seen := 0 for rows.Next() { var id int var ts, dt time.Time if err := rows.Scan(&id, &ts, &dt); err != nil { t.Error("Unable to scan results:", err) continue } if id < 0 || id >= len(tests) { t.Error("Bad row id: ", id) continue } seen++ if !tests[id].expected.Equal(ts) { t.Errorf("Timestamp value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, ts) } if !tests[id].expected.Equal(dt) { t.Errorf("Datetime value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt) } if tests[id].expected.Location().String() != ts.Location().String() { t.Errorf("Location for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected.Location().String(), ts.Location().String()) } if tests[id].expected.Location().String() != dt.Location().String() { t.Errorf("Location for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected.Location().String(), dt.Location().String()) } } if seen != len(tests) { t.Errorf("Expected to see %d rows", len(tests)) } } } func TestSuite(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename+"?_busy_timeout=99999") if err != nil { t.Fatal(err) } defer os.Remove(tempFilename) defer db.Close() sqlite3_test.RunTests(t, db, sqlite3_test.SQLITE) } // TODO: Execer & Queryer currently disabled // https://github.com/mattn/go-sqlite3/issues/82 func TestExecer(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec(` create table foo (id integer); -- one comment insert into foo(id) values(?); insert into foo(id) values(?); insert into foo(id) values(?); -- another comment `, 1, 2, 3) if err != nil { t.Error("Failed to call db.Exec:", err) } } func TestQueryer(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec(` create table foo (id integer); `) if err != nil { t.Error("Failed to call db.Query:", err) } rows, err := db.Query(` insert into foo(id) values(?); insert into foo(id) values(?); insert into foo(id) values(?); select id from foo order by id; `, 3, 2, 1) if err != nil { t.Error("Failed to call db.Query:", err) } defer rows.Close() n := 1 if rows != nil { for rows.Next() { var id int err = rows.Scan(&id) if err != nil { t.Error("Failed to db.Query:", err) } if id != n { t.Error("Failed to db.Query: not matched results") } } } } func TestStress(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } db.Exec("CREATE TABLE foo (id int);") db.Exec("INSERT INTO foo VALUES(1);") db.Exec("INSERT INTO foo VALUES(2);") db.Close() for i := 0; i < 10000; i++ { db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } for j := 0; j < 3; j++ { rows, err := db.Query("select * from foo where id=1;") if err != nil { t.Error("Failed to call db.Query:", err) } for rows.Next() { var i int if err := rows.Scan(&i); err != nil { t.Errorf("Scan failed: %v\n", err) } } if err := rows.Err(); err != nil { t.Errorf("Post-scan failed: %v\n", err) } rows.Close() } db.Close() } } func TestDateTimeLocal(t *testing.T) { zone := "Asia/Tokyo" tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename+"?_loc="+zone) if err != nil { t.Fatal("Failed to open database:", err) } db.Exec("CREATE TABLE foo (dt datetime);") db.Exec("INSERT INTO foo VALUES('2015-03-05 15:16:17');") row := db.QueryRow("select * from foo") var d time.Time err = row.Scan(&d) if err != nil { t.Fatal("Failed to scan datetime:", err) } if d.Hour() == 15 || !strings.Contains(d.String(), "JST") { t.Fatal("Result should have timezone", d) } db.Close() db, err = sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } row = db.QueryRow("select * from foo") err = row.Scan(&d) if err != nil { t.Fatal("Failed to scan datetime:", err) } if d.UTC().Hour() != 15 || !strings.Contains(d.String(), "UTC") { t.Fatalf("Result should not have timezone %v %v", zone, d.String()) } _, err = db.Exec("DELETE FROM foo") if err != nil { t.Fatal("Failed to delete table:", err) } dt, err := time.Parse("2006/1/2 15/4/5 -0700 MST", "2015/3/5 15/16/17 +0900 JST") if err != nil { t.Fatal("Failed to parse datetime:", err) } db.Exec("INSERT INTO foo VALUES(?);", dt) db.Close() db, err = sql.Open("sqlite3", tempFilename+"?_loc="+zone) if err != nil { t.Fatal("Failed to open database:", err) } row = db.QueryRow("select * from foo") err = row.Scan(&d) if err != nil { t.Fatal("Failed to scan datetime:", err) } if d.Hour() != 15 || !strings.Contains(d.String(), "JST") { t.Fatalf("Result should have timezone %v %v", zone, d.String()) } } func TestVersion(t *testing.T) { s, n, id := Version() if s == "" || n == 0 || id == "" { t.Errorf("Version failed %q, %d, %q\n", s, n, id) } } func TestNumberNamedParams(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec(` create table foo (id integer, name text, extra text); `) if err != nil { t.Error("Failed to call db.Query:", err) } _, err = db.Exec(`insert into foo(id, name, extra) values($1, $2, $2)`, 1, "foo") if err != nil { t.Error("Failed to call db.Exec:", err) } row := db.QueryRow(`select id, extra from foo where id = $1 and extra = $2`, 1, "foo") if row == nil { t.Error("Failed to call db.QueryRow") } var id int var extra string err = row.Scan(&id, &extra) if err != nil { t.Error("Failed to db.Scan:", err) } if id != 1 || extra != "foo" { t.Error("Failed to db.QueryRow: not matched results") } } func TestStringContainingZero(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer os.Remove(tempFilename) defer db.Close() _, err = db.Exec(` create table foo (id integer, name, extra text); `) if err != nil { t.Error("Failed to call db.Query:", err) } const text = "foo\x00bar" _, err = db.Exec(`insert into foo(id, name, extra) values($1, $2, $2)`, 1, text) if err != nil { t.Error("Failed to call db.Exec:", err) } row := db.QueryRow(`select id, extra from foo where id = $1 and extra = $2`, 1, text) if row == nil { t.Error("Failed to call db.QueryRow") } var id int var extra string err = row.Scan(&id, &extra) if err != nil { t.Error("Failed to db.Scan:", err) } if id != 1 || extra != text { t.Error("Failed to db.QueryRow: not matched results") } } const CurrentTimeStamp = "2006-01-02 15:04:05" type TimeStamp struct{ *time.Time } func (t TimeStamp) Scan(value interface{}) error { var err error switch v := value.(type) { case string: *t.Time, err = time.Parse(CurrentTimeStamp, v) case []byte: *t.Time, err = time.Parse(CurrentTimeStamp, string(v)) default: err = errors.New("invalid type for current_timestamp") } return err } func (t TimeStamp) Value() (driver.Value, error) { return t.Time.Format(CurrentTimeStamp), nil } func TestDateTimeNow(t *testing.T) { tempFilename := TempFilename() db, err := sql.Open("sqlite3", tempFilename) if err != nil { t.Fatal("Failed to open database:", err) } defer db.Close() var d time.Time err = db.QueryRow("SELECT datetime('now')").Scan(TimeStamp{&d}) if err != nil { t.Fatal("Failed to scan datetime:", err) } } go-sqlite3-1.1.0/sqlite3_test/000077500000000000000000000000001257260042200161235ustar00rootroot00000000000000go-sqlite3-1.1.0/sqlite3_test/sqltest.go000066400000000000000000000210011257260042200201430ustar00rootroot00000000000000package sqlite3_test import ( "database/sql" "fmt" "math/rand" "regexp" "strconv" "sync" "testing" "time" ) type Dialect int const ( SQLITE Dialect = iota POSTGRESQL MYSQL ) type DB struct { *testing.T *sql.DB dialect Dialect once sync.Once } var db *DB // the following tables will be created and dropped during the test var testTables = []string{"foo", "bar", "t", "bench"} var tests = []testing.InternalTest{ {"TestBlobs", TestBlobs}, {"TestManyQueryRow", TestManyQueryRow}, {"TestTxQuery", TestTxQuery}, {"TestPreparedStmt", TestPreparedStmt}, } var benchmarks = []testing.InternalBenchmark{ {"BenchmarkExec", BenchmarkExec}, {"BenchmarkQuery", BenchmarkQuery}, {"BenchmarkParams", BenchmarkParams}, {"BenchmarkStmt", BenchmarkStmt}, {"BenchmarkRows", BenchmarkRows}, {"BenchmarkStmtRows", BenchmarkStmtRows}, } // RunTests runs the SQL test suite func RunTests(t *testing.T, d *sql.DB, dialect Dialect) { db = &DB{t, d, dialect, sync.Once{}} testing.RunTests(func(string, string) (bool, error) { return true, nil }, tests) if !testing.Short() { for _, b := range benchmarks { fmt.Printf("%-20s", b.Name) r := testing.Benchmark(b.F) fmt.Printf("%10d %10.0f req/s\n", r.N, float64(r.N)/r.T.Seconds()) } } db.tearDown() } func (db *DB) mustExec(sql string, args ...interface{}) sql.Result { res, err := db.Exec(sql, args...) if err != nil { db.Fatalf("Error running %q: %v", sql, err) } return res } func (db *DB) tearDown() { for _, tbl := range testTables { switch db.dialect { case SQLITE: db.mustExec("drop table if exists " + tbl) case MYSQL, POSTGRESQL: db.mustExec("drop table if exists " + tbl) default: db.Fatal("unkown dialect") } } } // q replaces ? parameters if needed func (db *DB) q(sql string) string { switch db.dialect { case POSTGRESQL: // repace with $1, $2, .. qrx := regexp.MustCompile(`\?`) n := 0 return qrx.ReplaceAllStringFunc(sql, func(string) string { n++ return "$" + strconv.Itoa(n) }) } return sql } func (db *DB) blobType(size int) string { switch db.dialect { case SQLITE: return fmt.Sprintf("blob[%d]", size) case POSTGRESQL: return "bytea" case MYSQL: return fmt.Sprintf("VARBINARY(%d)", size) } panic("unkown dialect") } func (db *DB) serialPK() string { switch db.dialect { case SQLITE: return "integer primary key autoincrement" case POSTGRESQL: return "serial primary key" case MYSQL: return "integer primary key auto_increment" } panic("unkown dialect") } func (db *DB) now() string { switch db.dialect { case SQLITE: return "datetime('now')" case POSTGRESQL: return "now()" case MYSQL: return "now()" } panic("unkown dialect") } func makeBench() { if _, err := db.Exec("create table bench (n varchar(32), i integer, d double, s varchar(32), t datetime)"); err != nil { panic(err) } st, err := db.Prepare("insert into bench values (?, ?, ?, ?, ?)") if err != nil { panic(err) } defer st.Close() for i := 0; i < 100; i++ { if _, err = st.Exec(nil, i, float64(i), fmt.Sprintf("%d", i), time.Now()); err != nil { panic(err) } } } func TestResult(t *testing.T) { db.tearDown() db.mustExec("create temporary table test (id " + db.serialPK() + ", name varchar(10))") for i := 1; i < 3; i++ { r := db.mustExec(db.q("insert into test (name) values (?)"), fmt.Sprintf("row %d", i)) n, err := r.RowsAffected() if err != nil { t.Fatal(err) } if n != 1 { t.Errorf("got %v, want %v", n, 1) } n, err = r.LastInsertId() if err != nil { t.Fatal(err) } if n != int64(i) { t.Errorf("got %v, want %v", n, i) } } if _, err := db.Exec("error!"); err == nil { t.Fatalf("expected error") } } func TestBlobs(t *testing.T) { db.tearDown() var blob = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} db.mustExec("create table foo (id integer primary key, bar " + db.blobType(16) + ")") db.mustExec(db.q("insert into foo (id, bar) values(?,?)"), 0, blob) want := fmt.Sprintf("%x", blob) b := make([]byte, 16) err := db.QueryRow(db.q("select bar from foo where id = ?"), 0).Scan(&b) got := fmt.Sprintf("%x", b) if err != nil { t.Errorf("[]byte scan: %v", err) } else if got != want { t.Errorf("for []byte, got %q; want %q", got, want) } err = db.QueryRow(db.q("select bar from foo where id = ?"), 0).Scan(&got) want = string(blob) if err != nil { t.Errorf("string scan: %v", err) } else if got != want { t.Errorf("for string, got %q; want %q", got, want) } } func TestManyQueryRow(t *testing.T) { if testing.Short() { t.Log("skipping in short mode") return } db.tearDown() db.mustExec("create table foo (id integer primary key, name varchar(50))") db.mustExec(db.q("insert into foo (id, name) values(?,?)"), 1, "bob") var name string for i := 0; i < 10000; i++ { err := db.QueryRow(db.q("select name from foo where id = ?"), 1).Scan(&name) if err != nil || name != "bob" { t.Fatalf("on query %d: err=%v, name=%q", i, err, name) } } } func TestTxQuery(t *testing.T) { db.tearDown() tx, err := db.Begin() if err != nil { t.Fatal(err) } defer tx.Rollback() _, err = tx.Exec("create table foo (id integer primary key, name varchar(50))") if err != nil { t.Fatal(err) } _, err = tx.Exec(db.q("insert into foo (id, name) values(?,?)"), 1, "bob") if err != nil { t.Fatal(err) } r, err := tx.Query(db.q("select name from foo where id = ?"), 1) if err != nil { t.Fatal(err) } defer r.Close() if !r.Next() { if r.Err() != nil { t.Fatal(err) } t.Fatal("expected one rows") } var name string err = r.Scan(&name) if err != nil { t.Fatal(err) } } func TestPreparedStmt(t *testing.T) { db.tearDown() db.mustExec("CREATE TABLE t (count INT)") sel, err := db.Prepare("SELECT count FROM t ORDER BY count DESC") if err != nil { t.Fatalf("prepare 1: %v", err) } ins, err := db.Prepare(db.q("INSERT INTO t (count) VALUES (?)")) if err != nil { t.Fatalf("prepare 2: %v", err) } for n := 1; n <= 3; n++ { if _, err := ins.Exec(n); err != nil { t.Fatalf("insert(%d) = %v", n, err) } } const nRuns = 10 ch := make(chan bool) for i := 0; i < nRuns; i++ { go func() { defer func() { ch <- true }() for j := 0; j < 10; j++ { count := 0 if err := sel.QueryRow().Scan(&count); err != nil && err != sql.ErrNoRows { t.Errorf("Query: %v", err) return } if _, err := ins.Exec(rand.Intn(100)); err != nil { t.Errorf("Insert: %v", err) return } } }() } for i := 0; i < nRuns; i++ { <-ch } } // Benchmarks need to use panic() since b.Error errors are lost when // running via testing.Benchmark() I would like to run these via go // test -bench but calling Benchmark() from a benchmark test // currently hangs go. func BenchmarkExec(b *testing.B) { for i := 0; i < b.N; i++ { if _, err := db.Exec("select 1"); err != nil { panic(err) } } } func BenchmarkQuery(b *testing.B) { for i := 0; i < b.N; i++ { var n sql.NullString var i int var f float64 var s string // var t time.Time if err := db.QueryRow("select null, 1, 1.1, 'foo'").Scan(&n, &i, &f, &s); err != nil { panic(err) } } } func BenchmarkParams(b *testing.B) { for i := 0; i < b.N; i++ { var n sql.NullString var i int var f float64 var s string // var t time.Time if err := db.QueryRow("select ?, ?, ?, ?", nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil { panic(err) } } } func BenchmarkStmt(b *testing.B) { st, err := db.Prepare("select ?, ?, ?, ?") if err != nil { panic(err) } defer st.Close() for n := 0; n < b.N; n++ { var n sql.NullString var i int var f float64 var s string // var t time.Time if err := st.QueryRow(nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil { panic(err) } } } func BenchmarkRows(b *testing.B) { db.once.Do(makeBench) for n := 0; n < b.N; n++ { var n sql.NullString var i int var f float64 var s string var t time.Time r, err := db.Query("select * from bench") if err != nil { panic(err) } for r.Next() { if err = r.Scan(&n, &i, &f, &s, &t); err != nil { panic(err) } } if err = r.Err(); err != nil { panic(err) } } } func BenchmarkStmtRows(b *testing.B) { db.once.Do(makeBench) st, err := db.Prepare("select * from bench") if err != nil { panic(err) } defer st.Close() for n := 0; n < b.N; n++ { var n sql.NullString var i int var f float64 var s string var t time.Time r, err := st.Query() if err != nil { panic(err) } for r.Next() { if err = r.Scan(&n, &i, &f, &s, &t); err != nil { panic(err) } } if err = r.Err(); err != nil { panic(err) } } } go-sqlite3-1.1.0/sqlite3_windows.go000066400000000000000000000006001257260042200171610ustar00rootroot00000000000000// 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. // +build windows package sqlite3 /* #cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe #cgo windows,386 CFLAGS: -D_localtime32=localtime #cgo LDFLAGS: -lmingwex -lmingw32 */ import "C"