This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git
The following commit(s) were added to refs/heads/main by this push:
new 4c36d2e2 fix(flightsql): isolate example SQLite databases (#1067)
4c36d2e2 is described below
commit 4c36d2e21997801a22901e61c8563ba0a4d44ef1
Author: Minh Vu <[email protected]>
AuthorDate: Wed Aug 5 19:50:22 2026 +0200
fix(flightsql): isolate example SQLite databases (#1067)
Fixes #916
## Problem
CreateDB always opened the same named in-memory SQLite database with
`cache=shared`. Independent server instances created in the same process
therefore shared tables and data unexpectedly.
## Change
Generate a unique database name for each CreateDB call while retaining
`cache=shared`. Connections obtained from the same `sql.DB` still share
one in-memory database, but separate CreateDB calls are isolated.
## Coverage
The regression test verifies both sides of the contract:
- two CreateDB calls cannot see each other’s tables
- two connections from one `sql.DB` see the same data
## Validation
`go test ./arrow/flight/flightsql/example`
---
arrow/flight/flightsql/example/sqlite_server.go | 6 +-
.../flight/flightsql/example/sqlite_server_test.go | 67 ++++++++++++++++++++++
2 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/arrow/flight/flightsql/example/sqlite_server.go
b/arrow/flight/flightsql/example/sqlite_server.go
index 0b818a2e..4a1441c2 100644
--- a/arrow/flight/flightsql/example/sqlite_server.go
+++ b/arrow/flight/flightsql/example/sqlite_server.go
@@ -44,6 +44,7 @@ import (
"math/rand"
"strings"
"sync"
+ "sync/atomic"
"github.com/apache/arrow-go/v18/arrow"
"github.com/apache/arrow-go/v18/arrow/array"
@@ -59,6 +60,8 @@ import (
_ "modernc.org/sqlite"
)
+var dbSequence atomic.Uint64
+
func genRandomString() []byte {
const length = 16
max := int('z')
@@ -146,7 +149,8 @@ func prepareQueryForGetKeys(filter string) string {
}
func CreateDB() (*sql.DB, error) {
- db, err := sql.Open("sqlite", "file::memory:?cache=shared")
+ dsn :=
fmt.Sprintf("file:arrow-go-flightsql-%d?mode=memory&cache=shared",
dbSequence.Add(1))
+ db, err := sql.Open("sqlite", dsn)
if err != nil {
return nil, err
}
diff --git a/arrow/flight/flightsql/example/sqlite_server_test.go
b/arrow/flight/flightsql/example/sqlite_server_test.go
new file mode 100644
index 00000000..f0ded995
--- /dev/null
+++ b/arrow/flight/flightsql/example/sqlite_server_test.go
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package example
+
+import (
+ "context"
+ "testing"
+)
+
+func TestCreateDBIsolation(t *testing.T) {
+ db1, err := CreateDB()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer db1.Close()
+
+ db2, err := CreateDB()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer db2.Close()
+
+ if _, err := db1.Exec("CREATE TABLE sentinel (value INTEGER)"); err !=
nil {
+ t.Fatal(err)
+ }
+ if _, err := db2.Exec("SELECT * FROM sentinel"); err == nil {
+ t.Fatal("separate CreateDB calls unexpectedly shared state")
+ }
+
+ ctx := context.Background()
+ conn1, err := db1.Conn(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn1.Close()
+ conn2, err := db1.Conn(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn2.Close()
+
+ if _, err := conn1.ExecContext(ctx, "INSERT INTO sentinel VALUES
(42)"); err != nil {
+ t.Fatal(err)
+ }
+ var value int
+ if err := conn2.QueryRowContext(ctx, "SELECT value FROM
sentinel").Scan(&value); err != nil {
+ t.Fatal(err)
+ }
+ if value != 42 {
+ t.Fatalf("unexpected sentinel value: got %d, want 42", value)
+ }
+}