diff --git a/mongo/collection.go b/mongo/collection.go index 223e6ebd91137fa7a9b98ab1782f96668c73b651..fdd7685e7d6f3750d0d87c7694d5f8368bacc3d8 100644 --- a/mongo/collection.go +++ b/mongo/collection.go @@ -240,9 +240,11 @@ func (col *Collection) Append(item interface{}) (interface{}, error) { } // And other interfaces? - if setter, ok := item.(ObjectIdIDSetter); ok { - if err := setter.SetID(id); err != nil { - return nil, err + if _, ok := id.(bson.ObjectId); ok { + if setter, ok := item.(ObjectIdIDSetter); ok { + if err := setter.SetID(id.(bson.ObjectId)); err != nil { + return nil, err + } } } @@ -260,8 +262,9 @@ func (col *Collection) Exists() bool { } // Fetches object _id or generates a new one if object doesn't have one or the one it has is invalid -func getID(item interface{}) bson.ObjectId { - v := reflect.ValueOf(item) +func getID(item interface{}) interface{} { + v := reflect.ValueOf(item) // convert interface to Value + v = reflect.Indirect(v) // convert pointers switch v.Kind() { case reflect.Map: @@ -312,6 +315,8 @@ func getID(item interface{}) bson.ObjectId { if bsonID.Valid() { return bsonID } + } else { + return v.FieldByName(fieldName).Interface() } } } diff --git a/mongo/database.go b/mongo/database.go index 705f727eafd847eceeabfd61c8f11fb50aae800f..7a0a0acca746f7f1630e87fb80139ec4f5657fa1 100644 --- a/mongo/database.go +++ b/mongo/database.go @@ -249,6 +249,11 @@ func (s *Source) versionAtLeast(version ...int) bool { s.version = buildInfo.VersionArray } + // Check major version first + if s.version[0] > version[0] { + return true + } + for i := range version { if i == len(s.version) { return false diff --git a/mongo/database_test.go b/mongo/database_test.go index 57336d667003f489f28c00c5a30e21a9fbe3cb76..7144cee00110edd7be0a837ac8386c0d7713d4d1 100644 --- a/mongo/database_test.go +++ b/mongo/database_test.go @@ -365,6 +365,42 @@ func TestAppend(t *testing.T) { t.Fatalf("Expecting a valid bson.ObjectId.") } + // Appending a pointer to a struct + id, err = artist.Append(&struct { + ArtistName string `bson:"name"` + }{ + "Metallica", + }) + + if id == nil { + t.Fatalf("Expecting an ID.") + } + + if _, ok := id.(bson.ObjectId); ok != true { + t.Fatalf("Expecting a bson.ObjectId.") + } + + if id.(bson.ObjectId).Valid() != true { + t.Fatalf("Expecting a valid bson.ObjectId.") + } + + // Appending a pointer to a map + id, err = artist.Append(&map[string]string{ + "name": "Freddie", + }) + + if id == nil { + t.Fatalf("Expecting an ID.") + } + + if _, ok := id.(bson.ObjectId); ok != true { + t.Fatalf("Expecting a bson.ObjectId.") + } + + if id.(bson.ObjectId).Valid() != true { + t.Fatalf("Expecting a valid bson.ObjectId.") + } + // Attempt to append and update a private key itemStruct3 := artistWithObjectIdKey{ Name: "Janus", @@ -380,13 +416,13 @@ func TestAppend(t *testing.T) { var total uint64 - // Counting elements, must be exactly 4 elements. + // Counting elements, must be exactly 6 elements. if total, err = artist.Find().Count(); err != nil { t.Fatal(err) } - if total != 4 { - t.Fatalf("Expecting exactly 4 rows.") + if total != 6 { + t.Fatalf("Expecting exactly 6 rows.") } } diff --git a/mysql/benchmark_test.go b/mysql/benchmark_test.go index 01a5daa1b0d94c0f335d1e1d4521178f04d38766..57ad6cc995fa81a4d3f81fbc35d7e99c5eb44a08 100644 --- a/mysql/benchmark_test.go +++ b/mysql/benchmark_test.go @@ -324,6 +324,7 @@ func BenchmarkUpperAppendTransaction(b *testing.B) { if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } + defer tx.Close() var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { @@ -366,6 +367,7 @@ func BenchmarkUpperAppendTransactionWithMap(b *testing.B) { if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } + defer tx.Close() var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { @@ -766,6 +768,8 @@ func BenchmarkUpperCommitManyTransactions(b *testing.B) { if err = tx.Commit(); err != nil { b.Fatal(err) } + + tx.Close() } } @@ -808,5 +812,7 @@ func BenchmarkUpperRollbackManyTransactions(b *testing.B) { if err = tx.Rollback(); err != nil { b.Fatal(err) } + + tx.Close() } } diff --git a/mysql/database.go b/mysql/database.go index 6133837c381f19e2cf34b2891abb18952a1ed72c..b3fe31a3f7d682f141ae8242d12ef756895d7040 100644 --- a/mysql/database.go +++ b/mysql/database.go @@ -201,6 +201,9 @@ func (d *database) Ping() error { // Close terminates the current database session. func (d *database) Close() error { if d.session != nil { + if d.tx != nil && !d.tx.Done() { + d.tx.Rollback() + } d.cachedStatements.Clear() return d.session.Close() } diff --git a/mysql/database_test.go b/mysql/database_test.go index aefe295b853439e0cd7a3d534d6d4fe512028b65..2f356e827d2fb68f3d9e7cbf2aef2b34c13869c6 100644 --- a/mysql/database_test.go +++ b/mysql/database_test.go @@ -1194,6 +1194,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Illegal, transaction has already been commited.") } + tx.Close() + // Use another transaction. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1240,6 +1242,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Expecting only one element.") } + tx.Close() + // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1281,6 +1285,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Expecting only one element.") } + tx.Close() + // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1478,8 +1484,8 @@ func TestExhaustConnections(t *testing.T) { // lasts 3 seconds. time.Sleep(time.Second * 3) - if err := tx.Rollback(); err != nil { - panic(err.Error()) + if err := tx.Close(); err != nil { + t.Fatal(err) } t.Logf("Tx %d: Done", i) diff --git a/mysql/tx.go b/mysql/tx.go index 43fabe279c80195d9bb3c05901bff4779e7b315e..0d0d1738318278d32df108d70d7a356414af0e22 100644 --- a/mysql/tx.go +++ b/mysql/tx.go @@ -38,20 +38,18 @@ func (t *tx) Driver() interface{} { return nil } -// Commit commits the current transaction and frees up the connection. +// Commit commits the current transaction. func (t *tx) Commit() error { if err := t.Tx.Commit(); err != nil { return err } - t.database.Close() return nil } -// Rollback discards the current transaction and frees up the connection. +// Rollback discards the current transaction. func (t *tx) Rollback() error { if err := t.Tx.Rollback(); err != nil { return err } - t.database.Close() return nil } diff --git a/postgresql/benchmark_test.go b/postgresql/benchmark_test.go index 24be8f4ce1498cbd75fe74aee67cad61438ea4fc..1402f590443aff1f93108eed5a0cd4b8e7bfade2 100644 --- a/postgresql/benchmark_test.go +++ b/postgresql/benchmark_test.go @@ -336,6 +336,7 @@ func BenchmarkUpperAppendTransaction(b *testing.B) { if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } + defer tx.Close() var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { @@ -378,6 +379,7 @@ func BenchmarkUpperAppendTransactionWithMap(b *testing.B) { if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } + defer tx.Close() var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { @@ -778,6 +780,8 @@ func BenchmarkUpperCommitManyTransactions(b *testing.B) { if err = tx.Commit(); err != nil { b.Fatal(err) } + + tx.Close() } } @@ -820,5 +824,7 @@ func BenchmarkUpperRollbackManyTransactions(b *testing.B) { if err = tx.Rollback(); err != nil { b.Fatal(err) } + + tx.Close() } } diff --git a/postgresql/database.go b/postgresql/database.go index 1dd8acd84fdb3c9345dd10f366c7c5b7601245c0..75f84f8970d692a91c7c9b6d282abab78257ccda 100644 --- a/postgresql/database.go +++ b/postgresql/database.go @@ -193,6 +193,9 @@ func (d *database) Ping() error { // Close terminates the current database session. func (d *database) Close() error { if d.session != nil { + if d.tx != nil && !d.tx.Done() { + d.tx.Rollback() + } d.cachedStatements.Clear() return d.session.Close() } diff --git a/postgresql/database_test.go b/postgresql/database_test.go index 94053effbea249a3089c8ce22ee09aacfa80c1dc..9586da2001cd7fabaf39b19c665efbc5ce786bdf 100644 --- a/postgresql/database_test.go +++ b/postgresql/database_test.go @@ -1169,6 +1169,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Illegal, transaction has already been commited.") } + tx.Close() + // Use another transaction. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1215,6 +1217,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Expecting only one element.") } + tx.Close() + // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1256,6 +1260,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Expecting only one element.") } + tx.Close() + // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1727,7 +1733,7 @@ func TestExhaustConnections(t *testing.T) { // lasts 3 seconds. time.Sleep(time.Second * 3) - if err := tx.Rollback(); err != nil { + if err := tx.Close(); err != nil { t.Fatal(err) } diff --git a/postgresql/tx.go b/postgresql/tx.go index f91ed16fb3cac99a1eca3873be9498dd73b34e00..5392c922d67e220cd53fefd32b59d825cc553f01 100644 --- a/postgresql/tx.go +++ b/postgresql/tx.go @@ -38,20 +38,18 @@ func (t *tx) Driver() interface{} { return nil } -// Commit commits the current transaction and frees up the connection. +// Commit commits the current transaction. func (t *tx) Commit() error { if err := t.Tx.Commit(); err != nil { return err } - t.database.Close() return nil } -// Rollback discards the current transaction and frees up the connection. +// Rollback discards the current transaction. func (t *tx) Rollback() error { if err := t.Tx.Rollback(); err != nil { return err } - t.database.Close() return nil } diff --git a/ql/benchmark_test.go b/ql/benchmark_test.go index 72f0ef840fc410422d96779b94d9610054097371..f763f7b298a9cb63ff0aa3341a57b433a91154af 100644 --- a/ql/benchmark_test.go +++ b/ql/benchmark_test.go @@ -402,6 +402,7 @@ func BenchmarkUpperAppendTransaction(b *testing.B) { if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } + defer tx.Close() var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { @@ -444,6 +445,7 @@ func BenchmarkUpperAppendTransactionWithMap(b *testing.B) { if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } + defer tx.Close() var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { @@ -873,6 +875,8 @@ func BenchmarkUpperCommitManyTransactions(b *testing.B) { if err = tx.Commit(); err != nil { b.Fatal(err) } + + tx.Close() } } @@ -915,5 +919,7 @@ func BenchmarkUpperRollbackManyTransactions(b *testing.B) { if err = tx.Rollback(); err != nil { b.Fatal(err) } + + tx.Close() } } diff --git a/ql/database.go b/ql/database.go index 710332cef3e1a0944c2f4dc5feaf05c695bd497b..69a6f8619d25a8989257b98df67ea1f3bd60be95 100644 --- a/ql/database.go +++ b/ql/database.go @@ -206,14 +206,17 @@ func (d *database) Ping() error { // Close terminates the current database session. func (d *database) Close() error { if d.session != nil { + if d.tx != nil && !d.tx.Done() { + d.tx.Rollback() + } if err := d.session.Close(); err != nil { - panic(err.Error()) + return err } + d.cachedStatements.Clear() d.session = nil if atomic.AddInt32(&fileOpenCount, -1) < 0 { return errors.New(`Close() without Open()?`) } - return nil } return nil } diff --git a/ql/database_test.go b/ql/database_test.go index 15ebc557f14853e3e8ce4c52a5509a269f35d366..bd6abdb0f193f53624467378b76d0c691837197e 100644 --- a/ql/database_test.go +++ b/ql/database_test.go @@ -1018,6 +1018,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Illegal, transaction has already been commited.") } + tx.Close() + // Use another transaction. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1064,6 +1066,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Expecting only one element.") } + tx.Close() + // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1105,6 +1109,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Expecting only one element.") } + tx.Close() + // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1304,7 +1310,7 @@ func TestExhaustConnections(t *testing.T) { // We have to use a shorten time here. time.Sleep(time.Millisecond * 500) - if err := tx.Rollback(); err != nil { + if err := tx.Close(); err != nil { panic(err.Error()) } diff --git a/ql/tx.go b/ql/tx.go index db5d234b35e535a15071ae59d19b5d55c2ad77be..b6659a487ba63008c535deeaaec70da67b8c2a39 100644 --- a/ql/tx.go +++ b/ql/tx.go @@ -38,20 +38,18 @@ func (t *tx) Driver() interface{} { return nil } -// Commit commits the current transaction and frees up the connection. +// Commit commits the current transaction. func (t *tx) Commit() error { if err := t.Tx.Commit(); err != nil { return err } - t.database.Close() return nil } -// Rollback discards the current transaction and frees up the connection. +// Rollback discards the current transaction. func (t *tx) Rollback() error { if err := t.Tx.Rollback(); err != nil { return err } - t.database.Close() return nil } diff --git a/sqlite/benchmark_test.go b/sqlite/benchmark_test.go index 5c823d8e08e936495c688ec86a62cdbf07cbf459..b52339a42238fc294989097834131ea398ab5a91 100644 --- a/sqlite/benchmark_test.go +++ b/sqlite/benchmark_test.go @@ -324,6 +324,7 @@ func BenchmarkUpperAppendTransaction(b *testing.B) { if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } + defer tx.Close() var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { @@ -366,6 +367,7 @@ func BenchmarkUpperAppendTransactionWithMap(b *testing.B) { if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } + defer tx.Close() var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { @@ -766,6 +768,8 @@ func BenchmarkUpperCommitManyTransactions(b *testing.B) { if err = tx.Commit(); err != nil { b.Fatal(err) } + + tx.Close() } } @@ -808,5 +812,7 @@ func BenchmarkUpperRollbackManyTransactions(b *testing.B) { if err = tx.Rollback(); err != nil { b.Fatal(err) } + + tx.Close() } } diff --git a/sqlite/database.go b/sqlite/database.go index e1afe4a374a393fb8942a3467cacd2176c7a89ae..052f672d4d13461453d4bb86e641a65a7818664b 100644 --- a/sqlite/database.go +++ b/sqlite/database.go @@ -203,14 +203,17 @@ func (d *database) Ping() error { // Close terminates the current database session. func (d *database) Close() error { if d.session != nil { + if d.tx != nil && !d.tx.Done() { + d.tx.Rollback() + } + d.cachedStatements.Clear() if err := d.session.Close(); err != nil { - panic(err.Error()) + return err } d.session = nil if atomic.AddInt32(&fileOpenCount, -1) < 0 { return errors.New(`Close() without Open()?`) } - return nil } return nil } diff --git a/sqlite/database_test.go b/sqlite/database_test.go index 9ef909dab2567012e7f4ad2335f372705fb446ca..321753c100d448f8ba248c12d3f7c78af0f63a91 100644 --- a/sqlite/database_test.go +++ b/sqlite/database_test.go @@ -1125,6 +1125,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Illegal, transaction has already been commited.") } + tx.Close() + // Use another transaction. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1171,6 +1173,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Expecting only one element, got %d.", count) } + tx.Close() + // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1212,6 +1216,8 @@ func TestTransactionsAndRollback(t *testing.T) { t.Fatalf("Expecting only one element.") } + tx.Close() + // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) @@ -1426,7 +1432,7 @@ func TestExhaustConnections(t *testing.T) { // lasts 3 seconds. time.Sleep(time.Second * 3) - if err := tx.Rollback(); err != nil { + if err := tx.Close(); err != nil { panic(err.Error()) } diff --git a/sqlite/tx.go b/sqlite/tx.go index 5b9182b454e09037c4edda1efd921108da5dddcf..99bbe9f9ddcf77a0bfe59cf709516c7efb2f2743 100644 --- a/sqlite/tx.go +++ b/sqlite/tx.go @@ -38,20 +38,18 @@ func (t *tx) Driver() interface{} { return nil } -// Commit commits the current transaction and frees up the connection. +// Commit commits the current transaction. func (t *tx) Commit() error { if err := t.Tx.Commit(); err != nil { return err } - t.database.Close() return nil } -// Rollback discards the current transaction and frees up the connection. +// Rollback discards the current transaction. func (t *tx) Rollback() error { if err := t.Tx.Rollback(); err != nil { return err } - t.database.Close() return nil } diff --git a/util/sqlutil/scanner.go b/util/sqlutil/scanner.go index de01fa540d082a0d6d6843d65bb5b6d988f5048d..5fed1f4324fb2fd2d23e17ca4d5babf3e871bfe0 100644 --- a/util/sqlutil/scanner.go +++ b/util/sqlutil/scanner.go @@ -148,16 +148,21 @@ func (a *Int64Array) Scan(src interface{}) error { if !ok { return errors.New("Scan source was not []bytes") } + if len(b) == 0 { + return nil + } s := string(b)[1 : len(b)-1] - parts := strings.Split(s, ",") results := make([]int64, 0) - for _, n := range parts { - i, err := strconv.ParseInt(n, 10, 64) - if err != nil { - return err + if s != "" { + parts := strings.Split(s, ",") + for _, n := range parts { + i, err := strconv.ParseInt(n, 10, 64) + if err != nil { + return err + } + results = append(results, i) } - results = append(results, i) } *a = Int64Array(results) return nil