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 055d58fc fix(go/adbc): don't include NUL in error messages (#998)
055d58fc is described below
commit 055d58fcf8866c5d63d3fe04827e2d1e28787f26
Author: David Li <[email protected]>
AuthorDate: Tue Aug 29 08:51:53 2023 -0400
fix(go/adbc): don't include NUL in error messages (#998)
Fixes #997.
---
.github/workflows/integration.yml | 4 +-
.github/workflows/java.yml | 2 +-
.github/workflows/native-unix.yml | 4 +-
c/driver/postgresql/README.md | 4 +-
c/driver_manager/adbc_driver_manager.cc | 8 +-
ci/docker/flightsql-test.dockerfile | 20 +++
docker-compose.yml | 36 +++--
go/adbc/adbc.go | 7 +-
go/adbc/driver/flightsql/cmd/testserver/main.go | 161 +++++++++++++++++++++++
go/adbc/drivermgr/adbc_driver_manager.cc | 8 +-
go/adbc/pkg/_tmpl/driver.go.tmpl | 2 +-
go/adbc/pkg/_tmpl/utils.h.tmpl | 5 +-
go/adbc/pkg/flightsql/driver.go | 2 +-
go/adbc/pkg/flightsql/utils.h | 7 +-
go/adbc/pkg/panicdummy/driver.go | 2 +-
go/adbc/pkg/panicdummy/utils.h | 5 +-
go/adbc/pkg/snowflake/driver.go | 2 +-
go/adbc/pkg/snowflake/utils.h | 7 +-
python/adbc_driver_flightsql/tests/conftest.py | 10 ++
python/adbc_driver_flightsql/tests/test_dbapi.py | 15 +++
20 files changed, 282 insertions(+), 29 deletions(-)
diff --git a/.github/workflows/integration.yml
b/.github/workflows/integration.yml
index c293e0f0..c8cf5cdd 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -137,7 +137,7 @@ jobs:
- name: Start SQLite server and Dremio
shell: bash -l {0}
run: |
- docker-compose up -d golang-sqlite-flightsql dremio dremio-init
+ docker-compose up -d flightsql-test flightsql-sqlite-test dremio
dremio-init
- name: Build FlightSQL Driver
shell: bash -l {0}
@@ -155,6 +155,7 @@ jobs:
ADBC_DREMIO_FLIGHTSQL_USER: "dremio"
ADBC_DREMIO_FLIGHTSQL_PASS: "dremio123"
ADBC_SQLITE_FLIGHTSQL_URI: "grpc+tcp://localhost:8080"
+ ADBC_TEST_FLIGHTSQL_URI: "grpc+tcp://localhost:41414"
run: |
./ci/scripts/cpp_build.sh "$(pwd)" "$(pwd)/build"
./ci/scripts/cpp_test.sh "$(pwd)/build"
@@ -174,6 +175,7 @@ jobs:
ADBC_DREMIO_FLIGHTSQL_URI: "grpc+tcp://localhost:32010"
ADBC_DREMIO_FLIGHTSQL_USER: "dremio"
ADBC_DREMIO_FLIGHTSQL_PASS: "dremio123"
+ ADBC_TEST_FLIGHTSQL_URI: "grpc+tcp://localhost:41414"
run: |
./ci/scripts/python_test.sh "$(pwd)" "$(pwd)/build"
- name: Stop SQLite server and Dremio
diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml
index 10b98e1c..d955ab2d 100644
--- a/.github/workflows/java.yml
+++ b/.github/workflows/java.yml
@@ -69,7 +69,7 @@ jobs:
- name: Start SQLite server
shell: bash -l {0}
run: |
- docker-compose up -d golang-sqlite-flightsql
+ docker-compose up -d flightsql-sqlite-test
- name: Build/Test
env:
ADBC_SQLITE_FLIGHTSQL_URI: "grpc+tcp://localhost:8080"
diff --git a/.github/workflows/native-unix.yml
b/.github/workflows/native-unix.yml
index b12aa46d..e3a1bac3 100644
--- a/.github/workflows/native-unix.yml
+++ b/.github/workflows/native-unix.yml
@@ -658,7 +658,7 @@ jobs:
if: matrix.config.pkg == 'adbcpostgresql' && runner.os == 'Linux'
run: |
cd r/adbcpostgresql
- docker compose up --detach postgres_test
+ docker compose up --detach postgres-test
ADBC_POSTGRESQL_TEST_URI="postgresql://localhost:5432/postgres?user=postgres&password=password"
echo "ADBC_POSTGRESQL_TEST_URI=${ADBC_POSTGRESQL_TEST_URI}" >>
$GITHUB_ENV
@@ -666,7 +666,7 @@ jobs:
if: matrix.config.pkg == 'adbcflightsql' && runner.os == 'Linux'
run: |
cd r/adbcpostgresql
- docker compose up --detach golang-sqlite-flightsql
+ docker compose up --detach flightsql-sqlite-test
ADBC_FLIGHTSQL_TEST_URI="grpc://localhost:8080"
echo "ADBC_FLIGHTSQL_TEST_URI=${ADBC_FLIGHTSQL_TEST_URI}" >>
$GITHUB_ENV
diff --git a/c/driver/postgresql/README.md b/c/driver/postgresql/README.md
index cc5a3dfe..8ccffb68 100644
--- a/c/driver/postgresql/README.md
+++ b/c/driver/postgresql/README.md
@@ -54,9 +54,9 @@ Alternatively use the `docker compose` provided by ADBC to
manage the test
database container.
```shell
-$ docker compose up postgres_test
+$ docker compose up postgres-test
# When finished:
-# docker compose down postgres_test
+# docker compose down postgres-test
```
Then, to run the tests, set the environment variable specifying the
diff --git a/c/driver_manager/adbc_driver_manager.cc
b/c/driver_manager/adbc_driver_manager.cc
index 516bf9bb..e4287534 100644
--- a/c/driver_manager/adbc_driver_manager.cc
+++ b/c/driver_manager/adbc_driver_manager.cc
@@ -642,8 +642,12 @@ const struct AdbcError* AdbcErrorFromArrayStream(struct
ArrowArrayStream* stream
return nullptr;
}
auto* private_data = reinterpret_cast<struct
ErrorArrayStream*>(stream->private_data);
- return
private_data->private_driver->ErrorFromArrayStream(&private_data->stream,
- status);
+ auto* error =
+
private_data->private_driver->ErrorFromArrayStream(&private_data->stream,
status);
+ if (error) {
+ const_cast<struct AdbcError*>(error)->private_driver =
private_data->private_driver;
+ }
+ return error;
}
#define INIT_ERROR(ERROR, SOURCE) \
diff --git a/ci/docker/flightsql-test.dockerfile
b/ci/docker/flightsql-test.dockerfile
new file mode 100644
index 00000000..7c67b065
--- /dev/null
+++ b/ci/docker/flightsql-test.dockerfile
@@ -0,0 +1,20 @@
+# 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.
+
+ARG GO
+FROM golang:${GO}
+EXPOSE 41414
diff --git a/docker-compose.yml b/docker-compose.yml
index dd0ef2f5..2c77d721 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -107,15 +107,6 @@ services:
###################### Test database environments
############################
- postgres_test:
- container_name: adbc_postgres_test
- image: postgres:latest
- environment:
- POSTGRES_USER: postgres
- POSTGRES_PASSWORD: password
- ports:
- - "5432:5432"
-
dremio:
container_name: adbc-dremio
image: dremio/dremio-oss:latest
@@ -150,7 +141,23 @@ services:
volumes:
- "./ci/scripts/integration/dremio:/init"
- golang-sqlite-flightsql:
+ flightsql-test:
+ image: ${REPO}:adbc-flightsql-test
+ build:
+ context: .
+ cache_from:
+ - ${REPO}:adbc-flightsql-test
+ dockerfile: ci/docker/flightsql-test.dockerfile
+ args:
+ GO: ${GO}
+ ports:
+ - "41414:41414"
+ volumes:
+ - .:/adbc:delegated
+ command: >-
+ /bin/bash -c "cd /adbc/go/adbc && go run
./driver/flightsql/cmd/testserver -host 0.0.0.0 -port 41414"
+
+ flightsql-sqlite-test:
image: ${REPO}:golang-${GO}-sqlite-flightsql
build:
context: .
@@ -162,3 +169,12 @@ services:
ARROW_MAJOR_VERSION: ${ARROW_MAJOR_VERSION}
ports:
- 8080:8080
+
+ postgres-test:
+ container_name: adbc_postgres_test
+ image: postgres:latest
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: password
+ ports:
+ - "5432:5432"
diff --git a/go/adbc/adbc.go b/go/adbc/adbc.go
index ad6194f2..b0737fe0 100644
--- a/go/adbc/adbc.go
+++ b/go/adbc/adbc.go
@@ -131,7 +131,12 @@ type Error struct {
}
func (e Error) Error() string {
- return fmt.Sprintf("%s: SqlState: %s, msg: %s", e.Code,
string(e.SqlState[:]), e.Msg)
+ // Don't include a NUL in the string since C Data Interface uses char*
(and
+ // don't include the extra cruft if not needed in the first place)
+ if e.SqlState[0] != 0 {
+ return fmt.Sprintf("%s: %s (%s)", e.Code, e.Msg,
string(e.SqlState[:]))
+ }
+ return fmt.Sprintf("%s: %s", e.Code, e.Msg)
}
// Status represents an error code for operations that may fail
diff --git a/go/adbc/driver/flightsql/cmd/testserver/main.go
b/go/adbc/driver/flightsql/cmd/testserver/main.go
new file mode 100644
index 00000000..6e0ca4ff
--- /dev/null
+++ b/go/adbc/driver/flightsql/cmd/testserver/main.go
@@ -0,0 +1,161 @@
+// 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.
+
+// A server intended specifically for testing the Flight SQL driver. Unlike
+// the upstream SQLite example, which tries to be functional, this server
+// tries to be useful.
+
+package main
+
+import (
+ "bytes"
+ "context"
+ "flag"
+ "fmt"
+ "log"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/apache/arrow/go/v13/arrow"
+ "github.com/apache/arrow/go/v13/arrow/array"
+ "github.com/apache/arrow/go/v13/arrow/flight"
+ "github.com/apache/arrow/go/v13/arrow/flight/flightsql"
+ "github.com/apache/arrow/go/v13/arrow/memory"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type ExampleServer struct {
+ flightsql.BaseServer
+}
+
+func (srv *ExampleServer) ClosePreparedStatement(ctx context.Context, request
flightsql.ActionClosePreparedStatementRequest) error {
+ return nil
+}
+
+func (srv *ExampleServer) CreatePreparedStatement(ctx context.Context, req
flightsql.ActionCreatePreparedStatementRequest) (result
flightsql.ActionCreatePreparedStatementResult, err error) {
+ result.Handle = []byte(req.GetQuery())
+ return
+}
+
+func (srv *ExampleServer) GetFlightInfoPreparedStatement(_ context.Context,
cmd flightsql.PreparedStatementQuery, desc *flight.FlightDescriptor)
(*flight.FlightInfo, error) {
+ if bytes.Equal(cmd.GetPreparedStatementHandle(),
[]byte("error_do_get")) || bytes.Equal(cmd.GetPreparedStatementHandle(),
[]byte("error_do_get_stream")) {
+ schema := arrow.NewSchema([]arrow.Field{{Name: "ints", Type:
arrow.PrimitiveTypes.Int32, Nullable: true}}, nil)
+ return &flight.FlightInfo{
+ Endpoint: []*flight.FlightEndpoint{{Ticket:
&flight.Ticket{Ticket: desc.Cmd}}},
+ FlightDescriptor: desc,
+ TotalRecords: -1,
+ TotalBytes: -1,
+ Schema: flight.SerializeSchema(schema,
srv.Alloc),
+ }, nil
+ }
+
+ return &flight.FlightInfo{
+ Endpoint: []*flight.FlightEndpoint{{Ticket:
&flight.Ticket{Ticket: desc.Cmd}}},
+ FlightDescriptor: desc,
+ TotalRecords: -1,
+ TotalBytes: -1,
+ }, nil
+}
+
+func (srv *ExampleServer) GetFlightInfoStatement(ctx context.Context, cmd
flightsql.StatementQuery, desc *flight.FlightDescriptor) (*flight.FlightInfo,
error) {
+ ticket, err := flightsql.CreateStatementQueryTicket(desc.Cmd)
+ if err != nil {
+ return nil, err
+ }
+
+ return &flight.FlightInfo{
+ Endpoint: []*flight.FlightEndpoint{{Ticket:
&flight.Ticket{Ticket: ticket}}},
+ FlightDescriptor: desc,
+ TotalRecords: -1,
+ TotalBytes: -1,
+ }, nil
+}
+
+func (srv *ExampleServer) DoGetPreparedStatement(ctx context.Context, cmd
flightsql.PreparedStatementQuery) (schema *arrow.Schema, out <-chan
flight.StreamChunk, err error) {
+ log.Printf("DoGetPreparedStatement: %v",
cmd.GetPreparedStatementHandle())
+ if bytes.Equal(cmd.GetPreparedStatementHandle(),
[]byte("error_do_get")) {
+ err = status.Error(codes.InvalidArgument, "expected error")
+ return
+ }
+
+ schema = arrow.NewSchema([]arrow.Field{{Name: "ints", Type:
arrow.PrimitiveTypes.Int32, Nullable: true}}, nil)
+ rec, _, err := array.RecordFromJSON(memory.DefaultAllocator, schema,
strings.NewReader(`[{"a": 5}]`))
+
+ ch := make(chan flight.StreamChunk)
+ go func() {
+ defer close(ch)
+ ch <- flight.StreamChunk{
+ Data: rec,
+ Desc: nil,
+ Err: nil,
+ }
+ if bytes.Equal(cmd.GetPreparedStatementHandle(),
[]byte("error_do_get_stream")) {
+ ch <- flight.StreamChunk{
+ Data: nil,
+ Desc: nil,
+ Err: status.Error(codes.InvalidArgument,
"expected error"),
+ }
+ }
+ }()
+ out = ch
+ return
+}
+
+func (srv *ExampleServer) DoGetStatement(ctx context.Context, cmd
flightsql.StatementQueryTicket) (schema *arrow.Schema, out <-chan
flight.StreamChunk, err error) {
+ schema = arrow.NewSchema([]arrow.Field{{Name: "ints", Type:
arrow.PrimitiveTypes.Int32, Nullable: true}}, nil)
+ rec, _, err := array.RecordFromJSON(memory.DefaultAllocator, schema,
strings.NewReader(`[{"ints": 5}]`))
+
+ ch := make(chan flight.StreamChunk)
+ go func() {
+ defer close(ch)
+ ch <- flight.StreamChunk{
+ Data: rec,
+ Desc: nil,
+ Err: nil,
+ }
+ }()
+ out = ch
+ return
+}
+
+func main() {
+ var (
+ host = flag.String("host", "localhost", "hostname to bind to")
+ port = flag.Int("port", 0, "port to bind to")
+ )
+
+ flag.Parse()
+
+ srv := &ExampleServer{}
+ srv.Alloc = memory.DefaultAllocator
+
+ server := flight.NewServerWithMiddleware(nil)
+ server.RegisterFlightService(flightsql.NewFlightServer(srv))
+ if err := server.Init(net.JoinHostPort(*host, strconv.Itoa(*port)));
err != nil {
+ log.Fatal(err)
+ }
+ server.SetShutdownOnSignals(os.Interrupt, os.Kill)
+
+ fmt.Println("Starting testing Flight SQL Server on", server.Addr(),
"...")
+
+ if err := server.Serve(); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/go/adbc/drivermgr/adbc_driver_manager.cc
b/go/adbc/drivermgr/adbc_driver_manager.cc
index 516bf9bb..e4287534 100644
--- a/go/adbc/drivermgr/adbc_driver_manager.cc
+++ b/go/adbc/drivermgr/adbc_driver_manager.cc
@@ -642,8 +642,12 @@ const struct AdbcError* AdbcErrorFromArrayStream(struct
ArrowArrayStream* stream
return nullptr;
}
auto* private_data = reinterpret_cast<struct
ErrorArrayStream*>(stream->private_data);
- return
private_data->private_driver->ErrorFromArrayStream(&private_data->stream,
- status);
+ auto* error =
+
private_data->private_driver->ErrorFromArrayStream(&private_data->stream,
status);
+ if (error) {
+ const_cast<struct AdbcError*>(error)->private_driver =
private_data->private_driver;
+ }
+ return error;
}
#define INIT_ERROR(ERROR, SOURCE) \
diff --git a/go/adbc/pkg/_tmpl/driver.go.tmpl b/go/adbc/pkg/_tmpl/driver.go.tmpl
index fc489a40..24c15f39 100644
--- a/go/adbc/pkg/_tmpl/driver.go.tmpl
+++ b/go/adbc/pkg/_tmpl/driver.go.tmpl
@@ -263,7 +263,7 @@ func (cStream *cArrayStream) maybeError() C.int {
if cStream.adbcErr != nil {
C.{{.Prefix}}errRelease(cStream.adbcErr)
} else {
- cStream.adbcErr =
(*C.struct_AdbcError)(C.malloc(C.ADBC_ERROR_1_1_0_SIZE))
+ cStream.adbcErr = (*C.struct_AdbcError)(C.calloc(1,
C.ADBC_ERROR_1_1_0_SIZE))
}
cStream.adbcErr.vendor_code =
C.ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA
cStream.status = C.AdbcStatusCode(errToAdbcErr(cStream.adbcErr,
err))
diff --git a/go/adbc/pkg/_tmpl/utils.h.tmpl b/go/adbc/pkg/_tmpl/utils.h.tmpl
index ce3dba9d..d73f4bad 100644
--- a/go/adbc/pkg/_tmpl/utils.h.tmpl
+++ b/go/adbc/pkg/_tmpl/utils.h.tmpl
@@ -83,7 +83,10 @@ AdbcStatusCode {{.Prefix}}StatementSetSubstraitPlan(struct
AdbcStatement* stmt,
AdbcStatusCode {{.Prefix}}DriverInit(int version, void* rawDriver, struct
AdbcError* err);
static inline void {{.Prefix}}errRelease(struct AdbcError* error) {
- error->release(error);
+ if (error->release) {
+ error->release(error);
+ error->release = NULL;
+ }
}
void {{.Prefix}}_release_error(struct AdbcError* error);
diff --git a/go/adbc/pkg/flightsql/driver.go b/go/adbc/pkg/flightsql/driver.go
index 925fd865..46e09695 100644
--- a/go/adbc/pkg/flightsql/driver.go
+++ b/go/adbc/pkg/flightsql/driver.go
@@ -267,7 +267,7 @@ func (cStream *cArrayStream) maybeError() C.int {
if cStream.adbcErr != nil {
C.FlightSQLerrRelease(cStream.adbcErr)
} else {
- cStream.adbcErr =
(*C.struct_AdbcError)(C.malloc(C.ADBC_ERROR_1_1_0_SIZE))
+ cStream.adbcErr = (*C.struct_AdbcError)(C.calloc(1,
C.ADBC_ERROR_1_1_0_SIZE))
}
cStream.adbcErr.vendor_code =
C.ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA
cStream.status = C.AdbcStatusCode(errToAdbcErr(cStream.adbcErr,
err))
diff --git a/go/adbc/pkg/flightsql/utils.h b/go/adbc/pkg/flightsql/utils.h
index e3b22fb7..fbdbe89a 100644
--- a/go/adbc/pkg/flightsql/utils.h
+++ b/go/adbc/pkg/flightsql/utils.h
@@ -153,7 +153,12 @@ AdbcStatusCode FlightSQLStatementSetSubstraitPlan(struct
AdbcStatement* stmt,
AdbcStatusCode FlightSQLDriverInit(int version, void* rawDriver, struct
AdbcError* err);
-static inline void FlightSQLerrRelease(struct AdbcError* error) {
error->release(error); }
+static inline void FlightSQLerrRelease(struct AdbcError* error) {
+ if (error->release) {
+ error->release(error);
+ error->release = NULL;
+ }
+}
void FlightSQL_release_error(struct AdbcError* error);
diff --git a/go/adbc/pkg/panicdummy/driver.go b/go/adbc/pkg/panicdummy/driver.go
index d1c143a7..c99153cc 100644
--- a/go/adbc/pkg/panicdummy/driver.go
+++ b/go/adbc/pkg/panicdummy/driver.go
@@ -267,7 +267,7 @@ func (cStream *cArrayStream) maybeError() C.int {
if cStream.adbcErr != nil {
C.PanicDummyerrRelease(cStream.adbcErr)
} else {
- cStream.adbcErr =
(*C.struct_AdbcError)(C.malloc(C.ADBC_ERROR_1_1_0_SIZE))
+ cStream.adbcErr = (*C.struct_AdbcError)(C.calloc(1,
C.ADBC_ERROR_1_1_0_SIZE))
}
cStream.adbcErr.vendor_code =
C.ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA
cStream.status = C.AdbcStatusCode(errToAdbcErr(cStream.adbcErr,
err))
diff --git a/go/adbc/pkg/panicdummy/utils.h b/go/adbc/pkg/panicdummy/utils.h
index 91d8294c..b8db59c2 100644
--- a/go/adbc/pkg/panicdummy/utils.h
+++ b/go/adbc/pkg/panicdummy/utils.h
@@ -156,7 +156,10 @@ AdbcStatusCode PanicDummyStatementSetSubstraitPlan(struct
AdbcStatement* stmt,
AdbcStatusCode PanicDummyDriverInit(int version, void* rawDriver, struct
AdbcError* err);
static inline void PanicDummyerrRelease(struct AdbcError* error) {
- error->release(error);
+ if (error->release) {
+ error->release(error);
+ error->release = NULL;
+ }
}
void PanicDummy_release_error(struct AdbcError* error);
diff --git a/go/adbc/pkg/snowflake/driver.go b/go/adbc/pkg/snowflake/driver.go
index 6ca09646..4804e32e 100644
--- a/go/adbc/pkg/snowflake/driver.go
+++ b/go/adbc/pkg/snowflake/driver.go
@@ -267,7 +267,7 @@ func (cStream *cArrayStream) maybeError() C.int {
if cStream.adbcErr != nil {
C.SnowflakeerrRelease(cStream.adbcErr)
} else {
- cStream.adbcErr =
(*C.struct_AdbcError)(C.malloc(C.ADBC_ERROR_1_1_0_SIZE))
+ cStream.adbcErr = (*C.struct_AdbcError)(C.calloc(1,
C.ADBC_ERROR_1_1_0_SIZE))
}
cStream.adbcErr.vendor_code =
C.ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA
cStream.status = C.AdbcStatusCode(errToAdbcErr(cStream.adbcErr,
err))
diff --git a/go/adbc/pkg/snowflake/utils.h b/go/adbc/pkg/snowflake/utils.h
index 23391dfd..c6793162 100644
--- a/go/adbc/pkg/snowflake/utils.h
+++ b/go/adbc/pkg/snowflake/utils.h
@@ -153,7 +153,12 @@ AdbcStatusCode SnowflakeStatementSetSubstraitPlan(struct
AdbcStatement* stmt,
AdbcStatusCode SnowflakeDriverInit(int version, void* rawDriver, struct
AdbcError* err);
-static inline void SnowflakeerrRelease(struct AdbcError* error) {
error->release(error); }
+static inline void SnowflakeerrRelease(struct AdbcError* error) {
+ if (error->release) {
+ error->release(error);
+ error->release = NULL;
+ }
+}
void Snowflake_release_error(struct AdbcError* error);
diff --git a/python/adbc_driver_flightsql/tests/conftest.py
b/python/adbc_driver_flightsql/tests/conftest.py
index 4ca9508d..b4eb1811 100644
--- a/python/adbc_driver_flightsql/tests/conftest.py
+++ b/python/adbc_driver_flightsql/tests/conftest.py
@@ -71,3 +71,13 @@ def dremio_dbapi(dremio_uri, dremio_user, dremio_pass):
},
) as conn:
yield conn
+
+
[email protected]
+def test_dbapi():
+ uri = os.environ.get("ADBC_TEST_FLIGHTSQL_URI")
+ if not uri:
+ pytest.skip("Set ADBC_TEST_FLIGHTSQL_URI to run tests")
+
+ with adbc_driver_flightsql.dbapi.connect(uri) as conn:
+ yield conn
diff --git a/python/adbc_driver_flightsql/tests/test_dbapi.py
b/python/adbc_driver_flightsql/tests/test_dbapi.py
index 0918fc7a..e1990354 100644
--- a/python/adbc_driver_flightsql/tests/test_dbapi.py
+++ b/python/adbc_driver_flightsql/tests/test_dbapi.py
@@ -33,6 +33,21 @@ def test_query_error(dremio_dbapi):
assert exc.args[0].startswith("INVALID_ARGUMENT: [FlightSQL] ")
+def test_query_error_fetch(test_dbapi):
+ with test_dbapi.cursor() as cur:
+ cur.execute("error_do_get")
+ with pytest.raises(Exception, match="expected error"):
+ cur.fetch_arrow_table()
+
+
+def test_query_error_stream(test_dbapi):
+ with test_dbapi.cursor() as cur:
+ cur.execute("error_do_get_stream")
+ with pytest.raises(Exception, match="expected error"):
+ cur.fetchone()
+ cur.fetchone()
+
+
def test_query_trivial(dremio_dbapi):
with dremio_dbapi.cursor() as cur:
cur.execute("SELECT 1")