diff options
Diffstat (limited to 'tests/functional')
-rw-r--r-- | tests/functional/extension.go | 79 | ||||
-rw-r--r-- | tests/functional/json.go | 96 | ||||
-rw-r--r-- | tests/functional/libbuild.go | 19 | ||||
-rw-r--r-- | tests/functional/limit.go | 102 | ||||
-rw-r--r-- | tests/functional/streq.c | 36 |
5 files changed, 332 insertions, 0 deletions
diff --git a/tests/functional/extension.go b/tests/functional/extension.go new file mode 100644 index 0000000..81c4494 --- /dev/null +++ b/tests/functional/extension.go @@ -0,0 +1,79 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + "os" + "reflect" + + "golite" +) + + + +func fatalif(err error) { + if err != nil { + log.Fatal(err) + } +} + +func eq(given any, expected any) { + if !reflect.DeepEqual(given, expected) { + fmt.Fprintf(os.Stderr, "given != expected\n") + fmt.Fprintf(os.Stderr, "given: %#v\n", given) + fmt.Fprintf(os.Stderr, "expected: %#v\n", expected) + } +} + + + +func main() { + driver := golite.SQLiteDriver{ + Extensions: []string{ + "streq", + }, + } + sql.Register("sqlite3-streq", &driver) + + db, err := sql.Open("sqlite3-streq", ":memory:") + fatalif(err) + defer db.Close() + + rows, err := db.Query(` + SELECT str, n FROM ( + SELECT 'hello' as str, 1 as n + UNION + SELECT 'not' as str, 2 as n + UNION + SELECT 'hello' as str, 3 as n + ) WHERE streq(str, 'hello'); + `) + fatalif(err) + defer rows.Close() + + type pairT struct{ + str string + id int + } + var pairs []pairT + for rows.Next() { + var pair pairT + err := rows.Scan(&pair.str, &pair.id) + fatalif(err) + pairs = append(pairs, pair) + } + fatalif(rows.Err()) + + expected := []pairT{ + pairT{ + str: "hello", + id: 1, + }, + pairT{ + str: "hello", + id: 3, + }, + } + eq(pairs, expected) +} diff --git a/tests/functional/json.go b/tests/functional/json.go new file mode 100644 index 0000000..54954f7 --- /dev/null +++ b/tests/functional/json.go @@ -0,0 +1,96 @@ +package main + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + "errors" + "log" + "os" + + _ "golite" +) + +type Tag struct { + Name string `json:"name"` + Place string `json:"place"` +} + +func (t *Tag) Scan(value interface{}) error { + return json.Unmarshal([]byte(value.(string)), t) +} + +func (t *Tag) Value() (driver.Value, error) { + b, err := json.Marshal(t) + return string(b), err +} + +func main() { + os.Remove("json.db") + defer os.Remove("json.db") + + db, err := sql.Open("sqlite3", "json.db") + if err != nil { + log.Fatal(err) + } + defer db.Close() + + _, err = db.Exec(`create table myjsontable (tag jsonb)`) + if err != nil { + log.Fatal(err) + } + + stmt, err := db.Prepare("insert into myjsontable(tag) values(?)") + if err != nil { + log.Fatal(err) + } + defer stmt.Close() + + _, err = stmt.Exec(`{"name": "name1", "place": "right-here"}`) + if err != nil { + log.Fatal(err) + } + + _, err = stmt.Exec(`{"name": "michael", "place": "usa"}`) + if err != nil { + log.Fatal(err) + } + + var place string + err = db.QueryRow("select tag->>'place' from myjsontable where tag->>'name' = 'name1'").Scan(&place) + if err != nil { + log.Fatal(err) + } + + if place != "right-here" { + log.Fatal(errors.New("expected right-here, got: " + place)) + } + + var tag Tag + err = db.QueryRow("select tag from myjsontable where tag->>'name' = 'name1'").Scan(&tag) + if err != nil { + log.Fatal(err) + } + + if tag.Name != "name1" { + log.Fatal(errors.New("expected name1, got: " + tag.Name)) + } + if tag.Place != "right-here" { + log.Fatal(errors.New("expected right-here, got: " + tag.Place)) + } + + tag.Place = "日本" + _, err = db.Exec(`update myjsontable set tag = ? where tag->>'name' == 'name1'`, &tag) + if err != nil { + log.Fatal(err) + } + + err = db.QueryRow("select tag->>'place' from myjsontable where tag->>'name' = 'name1'").Scan(&place) + if err != nil { + log.Fatal(err) + } + + if place != "日本" { + log.Fatal(errors.New("expected 日本, got: " + place)) + } +} diff --git a/tests/functional/libbuild.go b/tests/functional/libbuild.go new file mode 100644 index 0000000..3de29ae --- /dev/null +++ b/tests/functional/libbuild.go @@ -0,0 +1,19 @@ +package main + +import ( + "database/sql" + + _ "golite" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + + err = db.Close() + if err != nil { + panic(err) + } +} diff --git a/tests/functional/limit.go b/tests/functional/limit.go new file mode 100644 index 0000000..8c65a25 --- /dev/null +++ b/tests/functional/limit.go @@ -0,0 +1,102 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + "os" + "strings" + + "golite" +) + +func createBulkInsertQuery(n int, start int) (string, []any) { + values := make([]string, n) + args := make([]any, n*2) + pos := 0 + for i := 0; i < n; i++ { + values[i] = "(?, ?)" + args[pos] = start + i + args[pos+1] = fmt.Sprintf("こんにちは世界%03d", i) + pos += 2 + } + query := fmt.Sprintf( + "insert into mylimittable(id, name) values %s", + strings.Join(values, ", "), + ) + return query, args +} + +func bulkInsert(db *sql.DB, query string, args []any) error { + stmt, err := db.Prepare(query) + if err != nil { + return err + } + + _, err = stmt.Exec(args...) + return err +} + +func main() { + const ( + num = 400 + smallLimit = 100 + bigLimit = 999999 + ) + + const SQL = ` + create table mylimittable (id integer not null primary key, name text); + delete from mylimittable; + ` + + var conn *golite.SQLiteConn + sql.Register("sqlite3_with_limit", &golite.SQLiteDriver{ + ConnectHook: func(c *golite.SQLiteConn) error { + conn = c + return nil + }, + }) + + os.Remove("limit.db") + defer os.Remove("limit.db") + db, err := sql.Open("sqlite3_with_limit", "limit.db") + if err != nil { + log.Fatal(err) + } + defer db.Close() + + _, err = db.Exec(SQL) + if err != nil { + log.Fatal(err) + } + + if conn == nil { + log.Fatal("not set sqlite3 connection") + } + + { + query, args := createBulkInsertQuery(num, 0) + err := bulkInsert(db, query, args) + if err != nil { + log.Fatal(err) + } + } + + conn.SetLimit(golite.SQLITE_LIMIT_VARIABLE_NUMBER, smallLimit) + { + query, args := createBulkInsertQuery(num, num) + err := bulkInsert(db, query, args) + if err == nil { + log.Fatal("expected failure didn't happen") + } + } + + conn.SetLimit(golite.SQLITE_LIMIT_VARIABLE_NUMBER, bigLimit) + { + query, args := createBulkInsertQuery(500, num+num) + err := bulkInsert(db, query, args) + if err != nil { + log.Fatal(err) + } + } +} diff --git a/tests/functional/streq.c b/tests/functional/streq.c new file mode 100644 index 0000000..bbf3763 --- /dev/null +++ b/tests/functional/streq.c @@ -0,0 +1,36 @@ +#include <assert.h> +#include <stdbool.h> +#include <string.h> +#include <sqlite3ext.h> + + + +SQLITE_EXTENSION_INIT1 +static void +streq(sqlite3_context *const ctx, const int argc, sqlite3_value **const argv) { + assert(argc == 2); + const char *const str1 = (const char *)sqlite3_value_text(argv[0]); + const char *const str2 = (const char *)sqlite3_value_text(argv[1]); + const bool equal = strcmp(str1, str2) == 0; + const int result = equal ? 1 : 0; + sqlite3_result_int(ctx, result); +} + +int +sqlite3_extension_init( + sqlite3 *const db, + const char *const *const errmsg, + const sqlite3_api_routines *const api +) { + SQLITE_EXTENSION_INIT2(api); + return sqlite3_create_function( + db, + "streq", + 2, + SQLITE_UTF8, + (void *)db, + streq, + NULL, + NULL + ); +} |