This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new e023d77 feat(go/adbc/sqldriver): add simple FlightSQL database/sql
driver wrapper (#480)
e023d77 is described below
commit e023d7782783c079a22dca66d90e600ca079b81c
Author: Jacob Marble <[email protected]>
AuthorDate: Thu Mar 2 07:27:44 2023 -0800
feat(go/adbc/sqldriver): add simple FlightSQL database/sql driver wrapper
(#480)
Helps https://github.com/apache/arrow/issues/34332
Golang/FlightSQL docs should be updated to point here for the canonical
`database/sql` wrapper.
---------
Co-authored-by: Matt Topol <[email protected]>
---
go/adbc/sqldriver/doc.go | 36 ++++++++
go/adbc/sqldriver/driver.go | 19 ++--
go/adbc/sqldriver/flightsql/README.md | 61 +++++++++++++
go/adbc/sqldriver/flightsql/flightsql.go | 30 +++++++
go/adbc/sqldriver/flightsql/flightsql_test.go | 125 ++++++++++++++++++++++++++
5 files changed, 257 insertions(+), 14 deletions(-)
diff --git a/go/adbc/sqldriver/doc.go b/go/adbc/sqldriver/doc.go
new file mode 100644
index 0000000..edddb33
--- /dev/null
+++ b/go/adbc/sqldriver/doc.go
@@ -0,0 +1,36 @@
+// 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 sqldriver is a wrapper around the ADBC (Arrow Database
+// Connectivity) interfaces to support the standard golang database/sql
+// package, described here: https://go.dev/src/database/sql/doc.txt
+//
+// This allows any ADBC driver implementation to also be used as-is
+// with the database/sql package of the standard library rather than
+// having to implement drivers for both separately.
+//
+// Registering the driver can be done by importing this and then running
+//
+// sql.Register("drivername", sqldriver.Driver{adbcdriver})
+//
+// Additionally, the sqldriver/flightsql package simplifies registration
+// of the FlightSQL ADBC driver implementation, so that only a single
+// import statement is needed. See the example in that package.
+//
+// EXPERIMENTAL. The ADBC interfaces are subject to change and as such
+// this wrapper is also subject to change based on that.
+package sqldriver
diff --git a/go/adbc/sqldriver/driver.go b/go/adbc/sqldriver/driver.go
index e838db7..6cf65f4 100644
--- a/go/adbc/sqldriver/driver.go
+++ b/go/adbc/sqldriver/driver.go
@@ -15,20 +15,6 @@
// specific language governing permissions and limitations
// under the License.
-// Package sqldriver is a wrapper around the ADBC (Arrow Database
-// Connectivity) interfaces to support the standard golang database/sql
-// package.
-//
-// This allows any ADBC driver implementation to also be used as-is
-// with the database/sql package of the standard library rather than
-// having to implement drivers for both separately.
-//
-// Registering the driver can be done by importing this and then running
-//
-// sql.Register("drivername", sqldriver.Driver{adbcdriver})
-//
-// EXPERIMENTAL. The ADBC interfaces are subject to change and as such
-// this wrapper is also subject to change based on that.
package sqldriver
import (
@@ -267,6 +253,11 @@ func (c *conn) PrepareContext(ctx context.Context, query
string) (driver.Stmt, e
return nil, err
}
+ if err := s.Prepare(ctx); err != nil {
+ s.Close()
+ return nil, err
+ }
+
paramSchema, err := s.GetParameterSchema()
var adbcErr adbc.Error
if errors.As(err, &adbcErr) {
diff --git a/go/adbc/sqldriver/flightsql/README.md
b/go/adbc/sqldriver/flightsql/README.md
new file mode 100644
index 0000000..a9d3579
--- /dev/null
+++ b/go/adbc/sqldriver/flightsql/README.md
@@ -0,0 +1,61 @@
+<!---
+ 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.
+-->
+
+# flightsql - A FlightSQL driver for the database/sql package
+
+[](https://pkg.go.dev/github.com/apache/arrow-adbc/go/adbc/sqldriver/flightsql)
+
+Golang database/sql driver for
[FlightSQL](https://arrow.apache.org/docs/format/FlightSql.html).
+
+> Arrow Flight SQL is a protocol for interacting with SQL databases using
+> the Arrow in-memory format and the Flight RPC framework.
+
+## Technical Details
+
+This package is a thin wrapper over the
+[ADBC database/sql driver
wrapper](https://pkg.go.dev/github.com/apache/arrow-adbc/go/adbc/sqldriver),
+which is itself database/sql wrapper driver for any
+[ADBC](https://arrow.apache.org/docs/format/ADBC.html) driver.
+
+This package simply registers the
+[FlightSQL ADBC
driver](https://pkg.go.dev/github.com/apache/arrow-adbc/go/adbc/driver/flightsql)
+with the database/sql package.
+Understanding ADBC is not necessary to use this driver.
+
+## Example
+
+```golang
+package main
+
+import (
+ "database/sql"
+ _ "github.com/apache/arrow-adbc/go/adbc/sqldriver/flightsql"
+)
+
+func main() {
+ db, err := sql.Open("flightsql", "uri=grpc://localhost:12345")
+ if err != nil {
+ panic(err)
+ }
+
+ if err = db.Ping(); err != nil {
+ panic(err)
+ }
+}
+```
diff --git a/go/adbc/sqldriver/flightsql/flightsql.go
b/go/adbc/sqldriver/flightsql/flightsql.go
new file mode 100644
index 0000000..f318cbb
--- /dev/null
+++ b/go/adbc/sqldriver/flightsql/flightsql.go
@@ -0,0 +1,30 @@
+// 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 flightsql
+
+import (
+ "database/sql"
+ "github.com/apache/arrow-adbc/go/adbc/driver/flightsql"
+ "github.com/apache/arrow-adbc/go/adbc/sqldriver"
+)
+
+func init() {
+ sql.Register("flightsql", sqldriver.Driver{
+ Driver: flightsql.Driver{},
+ })
+}
diff --git a/go/adbc/sqldriver/flightsql/flightsql_test.go
b/go/adbc/sqldriver/flightsql/flightsql_test.go
new file mode 100644
index 0000000..86fdee3
--- /dev/null
+++ b/go/adbc/sqldriver/flightsql/flightsql_test.go
@@ -0,0 +1,125 @@
+// 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 flightsql_test
+
+import (
+ "database/sql"
+ "os"
+ "testing"
+
+ _ "github.com/apache/arrow-adbc/go/adbc/sqldriver/flightsql"
+ "github.com/apache/arrow/go/v12/arrow/flight"
+ "github.com/apache/arrow/go/v12/arrow/flight/flightsql"
+ "github.com/apache/arrow/go/v12/arrow/flight/flightsql/example"
+ "github.com/apache/arrow/go/v12/arrow/memory"
+ "github.com/stretchr/testify/suite"
+ "google.golang.org/grpc"
+)
+
+func Example() {
+ // Be sure to import the driver first:
+ // import _ "github.com/apache/arrow-adbc/go/adbc/sqldriver/flightsql"
+
+ db, err := sql.Open("flightsql", "uri=grpc://localhost:12345")
+ if err != nil {
+ panic(err)
+ }
+
+ if err = db.Ping(); err != nil {
+ panic(err)
+ }
+}
+
+type SQLDriverFlightSQLSuite struct {
+ suite.Suite
+
+ srv *example.SQLiteFlightSQLServer
+ s flight.Server
+ opts []grpc.ServerOption
+ sqliteDB *sql.DB
+
+ done chan bool
+ mem *memory.CheckedAllocator
+}
+
+func (suite *SQLDriverFlightSQLSuite) SetupTest() {
+ var err error
+
+ suite.sqliteDB, err = example.CreateDB()
+ suite.Require().NoError(err)
+
+ suite.mem = memory.NewCheckedAllocator(memory.DefaultAllocator)
+ suite.s = flight.NewServerWithMiddleware(nil, suite.opts...)
+ suite.Require().NoError(err)
+ suite.srv, err = example.NewSQLiteFlightSQLServer(suite.sqliteDB)
+ suite.Require().NoError(err)
+ suite.srv.Alloc = suite.mem
+
+ suite.s.RegisterFlightService(flightsql.NewFlightServer(suite.srv))
+ suite.Require().NoError(suite.s.Init("localhost:0"))
+ suite.s.SetShutdownOnSignals(os.Interrupt, os.Kill)
+ suite.done = make(chan bool)
+ go func() {
+ defer close(suite.done)
+ _ = suite.s.Serve()
+ }()
+}
+
+func (suite *SQLDriverFlightSQLSuite) TearDownTest() {
+ if suite.done == nil {
+ return
+ }
+
+ suite.s.Shutdown()
+ <-suite.done
+ suite.srv = nil
+ suite.mem.AssertSize(suite.T(), 0)
+ _ = suite.sqliteDB.Close()
+ suite.done = nil
+}
+
+func (suite *SQLDriverFlightSQLSuite) dsn() string {
+ return "uri=grpc+tcp://" + suite.s.Addr().String()
+}
+
+func (suite *SQLDriverFlightSQLSuite) TestQuery() {
+ db, err := sql.Open("flightsql", suite.dsn())
+ suite.Require().NoError(err)
+ defer db.Close()
+
+ _, err = db.Exec("CREATE TABLE t (k, v)")
+ suite.Require().NoError(err)
+ result, err := db.Exec("INSERT INTO t (k, v) VALUES ('one', 'alpha'),
('two', 'bravo')")
+ suite.Require().NoError(err)
+
+ n, err := result.RowsAffected()
+ suite.Require().NoError(err)
+ suite.EqualValues(2, n)
+
+ var expected int = 2
+ var actual int
+ row := db.QueryRow("SELECT count(*) FROM t")
+ err = row.Scan(&actual)
+ if suite.NoError(err) {
+ suite.Equal(expected, actual)
+ }
+}
+
+func TestSQLDriverFlightSQL(t *testing.T) {
+ suite.Run(t, new(SQLDriverFlightSQLSuite))
+}