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 a618cfb Add C driver validation suite (#28)
a618cfb is described below
commit a618cfbb14e4a7d9e1ae239587873ff79870891f
Author: David Li <[email protected]>
AuthorDate: Fri Jul 8 13:52:31 2022 -0400
Add C driver validation suite (#28)
---
adbc_driver_manager/CMakeLists.txt | 2 +
adbc_driver_manager/adbc_driver_manager.cc | 8 +-
adbc_driver_manager/adbc_driver_manager_test.cc | 24 ++
drivers/sqlite/CMakeLists.txt | 2 +
drivers/sqlite/sqlite.cc | 19 +-
drivers/sqlite/sqlite_test.cc | 14 +
validation/adbc_validation.c | 378 ++++++++++++++++++++++++
validation/adbc_validation.h | 46 +++
8 files changed, 489 insertions(+), 4 deletions(-)
diff --git a/adbc_driver_manager/CMakeLists.txt
b/adbc_driver_manager/CMakeLists.txt
index f77ebc1..b9ba012 100644
--- a/adbc_driver_manager/CMakeLists.txt
+++ b/adbc_driver_manager/CMakeLists.txt
@@ -47,12 +47,14 @@ if(ADBC_BUILD_TESTS)
else()
set(TEST_LINK_LIBS adbc_driver_manager_static arrow_static)
endif()
+ include_directories(SYSTEM ${REPOSITORY_ROOT}/validation)
add_test_case(driver_manager_test
PREFIX
adbc
SOURCES
adbc_driver_manager_test.cc
+ ../validation/adbc_validation.c
EXTRA_LINK_LIBS
${TEST_LINK_LIBS})
endif()
diff --git a/adbc_driver_manager/adbc_driver_manager.cc
b/adbc_driver_manager/adbc_driver_manager.cc
index 96f0bf2..1a9dc53 100644
--- a/adbc_driver_manager/adbc_driver_manager.cc
+++ b/adbc_driver_manager/adbc_driver_manager.cc
@@ -288,14 +288,17 @@ AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase*
database,
TempDatabase* args =
reinterpret_cast<TempDatabase*>(database->private_data);
delete args;
database->private_data = nullptr;
+ return ADBC_STATUS_OK;
}
- return ADBC_STATUS_OK;
+ return ADBC_STATUS_INVALID_STATE;
}
auto status = database->private_driver->DatabaseRelease(database, error);
if (database->private_driver->release) {
database->private_driver->release(database->private_driver, error);
}
delete database->private_driver;
+ database->private_data = nullptr;
+ database->private_driver = nullptr;
return status;
}
@@ -345,8 +348,9 @@ AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection*
connection,
TempConnection* args =
reinterpret_cast<TempConnection*>(connection->private_data);
delete args;
connection->private_data = nullptr;
+ return ADBC_STATUS_OK;
}
- return ADBC_STATUS_OK;
+ return ADBC_STATUS_INVALID_STATE;
}
auto status = connection->private_driver->ConnectionRelease(connection,
error);
connection->private_driver = nullptr;
diff --git a/adbc_driver_manager/adbc_driver_manager_test.cc
b/adbc_driver_manager/adbc_driver_manager_test.cc
index 5858594..74126c9 100644
--- a/adbc_driver_manager/adbc_driver_manager_test.cc
+++ b/adbc_driver_manager/adbc_driver_manager_test.cc
@@ -29,6 +29,7 @@
#include "adbc.h"
#include "adbc_driver_manager.h"
+#include "adbc_validation.h"
#include "drivers/test_util.h"
// Tests of the SQLite example driver, except using the driver manager
@@ -255,4 +256,27 @@ TEST_F(DriverManager, Transactions) {
ASSERT_EQ(ADBC_STATUS_INVALID_STATE, AdbcConnectionRollback(&connection,
&error));
}
+AdbcStatusCode SetupDatabase(struct AdbcDatabase* database, struct AdbcError*
error) {
+ AdbcStatusCode status;
+ if ((status = AdbcDatabaseSetOption(database, "driver",
"adbc_driver_sqlite", error)) !=
+ ADBC_STATUS_OK) {
+ return status;
+ }
+ return AdbcDatabaseSetOption(database, "entrypoint", "AdbcSqliteDriverInit",
error);
+}
+
+TEST_F(DriverManager, ValidationSuite) {
+ struct AdbcValidateTestContext ctx;
+ std::memset(&ctx, 0, sizeof(ctx));
+ ctx.setup_database = &SetupDatabase;
+ AdbcValidateDatabaseNewRelease(&ctx);
+ AdbcValidateConnectionNewRelease(&ctx);
+ AdbcValidateConnectionAutocommit(&ctx);
+ AdbcValidateStatementNewRelease(&ctx);
+ AdbcValidateStatementSqlExecute(&ctx);
+ AdbcValidateStatementSqlPrepare(&ctx);
+ ASSERT_EQ(ctx.failed, 0);
+ ASSERT_EQ(ctx.total, ctx.passed);
+}
+
} // namespace adbc
diff --git a/drivers/sqlite/CMakeLists.txt b/drivers/sqlite/CMakeLists.txt
index 0872486..fb4a782 100644
--- a/drivers/sqlite/CMakeLists.txt
+++ b/drivers/sqlite/CMakeLists.txt
@@ -53,11 +53,13 @@ else()
endif()
if(ADBC_BUILD_TESTS)
+ include_directories(SYSTEM ${REPOSITORY_ROOT}/validation)
add_test_case(driver_sqlite_test
PREFIX
adbc
SOURCES
sqlite_test.cc
+ ../../validation/adbc_validation.c
EXTRA_LINK_LIBS
${TEST_LINK_LIBS})
endif()
diff --git a/drivers/sqlite/sqlite.cc b/drivers/sqlite/sqlite.cc
index 493675a..8703e66 100644
--- a/drivers/sqlite/sqlite.cc
+++ b/drivers/sqlite/sqlite.cc
@@ -284,6 +284,7 @@ class SqliteConnectionImpl {
}
AdbcStatusCode Release(struct AdbcError* error) {
+ if (!database_) return ADBC_STATUS_OK;
return database_->Disconnect(db_, error);
}
@@ -580,6 +581,19 @@ class SqliteStatementImpl {
return ADBC_STATUS_INVALID_STATE;
}
+ AdbcStatusCode Prepare(const std::shared_ptr<SqliteStatementImpl>& self,
+ struct AdbcError* error) {
+ if (stmt_) {
+ // No-op
+ return ADBC_STATUS_OK;
+ } else if (!bulk_table_.empty()) {
+ SetError(error, "Cannot prepare with bulk insert");
+ return ADBC_STATUS_INVALID_STATE;
+ }
+ SetError(error, "Cannot prepare a statement without a query");
+ return ADBC_STATUS_INVALID_STATE;
+ }
+
AdbcStatusCode GetObjects(const std::shared_ptr<SqliteStatementImpl>& self,
int depth,
const char* catalog, const char* db_schema,
const char* table_name, const char** table_type,
@@ -1353,8 +1367,9 @@ AdbcStatusCode SqliteStatementNew(struct AdbcConnection*
connection,
AdbcStatusCode SqliteStatementPrepare(struct AdbcStatement* statement,
struct AdbcError* error) {
if (!statement->private_data) return ADBC_STATUS_INVALID_STATE;
- // No-op
- return ADBC_STATUS_OK;
+ auto* ptr =
+
reinterpret_cast<std::shared_ptr<SqliteStatementImpl>*>(statement->private_data);
+ return (*ptr)->Prepare(*ptr, error);
}
AdbcStatusCode SqliteStatementRelease(struct AdbcStatement* statement,
diff --git a/drivers/sqlite/sqlite_test.cc b/drivers/sqlite/sqlite_test.cc
index 3f40587..be232f5 100644
--- a/drivers/sqlite/sqlite_test.cc
+++ b/drivers/sqlite/sqlite_test.cc
@@ -27,6 +27,7 @@
#include <arrow/testing/matchers.h>
#include "adbc.h"
+#include "adbc_validation.h"
#include "drivers/test_util.h"
// Tests of the SQLite example driver
@@ -738,4 +739,17 @@ TEST_F(Sqlite, Transactions) {
ADBC_ASSERT_OK_WITH_ERROR(error, AdbcConnectionRelease(&connection2,
&error));
}
+TEST_F(Sqlite, ValidationSuite) {
+ struct AdbcValidateTestContext ctx;
+ std::memset(&ctx, 0, sizeof(ctx));
+ AdbcValidateDatabaseNewRelease(&ctx);
+ AdbcValidateConnectionNewRelease(&ctx);
+ AdbcValidateConnectionAutocommit(&ctx);
+ AdbcValidateStatementNewRelease(&ctx);
+ AdbcValidateStatementSqlExecute(&ctx);
+ AdbcValidateStatementSqlPrepare(&ctx);
+ ASSERT_EQ(ctx.failed, 0);
+ ASSERT_EQ(ctx.total, ctx.passed);
+}
+
} // namespace adbc
diff --git a/validation/adbc_validation.c b/validation/adbc_validation.c
new file mode 100644
index 0000000..76ee737
--- /dev/null
+++ b/validation/adbc_validation.c
@@ -0,0 +1,378 @@
+// 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.
+
+#include "adbc_validation.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <adbc.h>
+
+#define ADBCV_STRINGIFY(s) #s
+const char* AdbcValidateStatusCodeMessage(AdbcStatusCode code) {
+#define STRINGIFY_VALUE(s) ADBCV_STRINGIFY(s)
+#define CASE(CONSTANT) \
+ case ADBC_STATUS_##CONSTANT: \
+ return #CONSTANT " (" STRINGIFY_VALUE(ADBC_STATUS_##CONSTANT) ")";
+
+ switch (code) {
+ CASE(OK);
+ CASE(UNKNOWN);
+ CASE(NOT_IMPLEMENTED);
+ CASE(NOT_FOUND);
+ CASE(ALREADY_EXISTS);
+ CASE(INVALID_ARGUMENT);
+ CASE(INVALID_STATE);
+ CASE(INVALID_DATA);
+ CASE(INTEGRITY);
+ CASE(INTERNAL);
+ CASE(IO);
+ CASE(CANCELLED);
+ CASE(TIMEOUT);
+ CASE(UNAUTHENTICATED);
+ CASE(UNAUTHORIZED);
+ default:
+ return "(invalid code)";
+ }
+#undef CASE
+#undef STRINGIFY_VALUE
+}
+
+void AdbcValidateBeginCase(struct AdbcValidateTestContext* ctx, const char*
suite,
+ const char* test_case) {
+ printf("-- %s: %s\n", suite, test_case);
+}
+
+void AdbcValidateBeginAssert(struct AdbcValidateTestContext* ctx, const char*
fmt, ...) {
+ ctx->total++;
+ printf(" ");
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ printf(": ");
+ fflush(stdout);
+}
+
+void AdbcValidatePass(struct AdbcValidateTestContext* ctx) {
+ ctx->passed++;
+ printf("pass\n");
+}
+
+void AdbcValidateFail(struct AdbcValidateTestContext* ctx, const char* file,
int lineno,
+ struct AdbcError* error) {
+ ctx->failed++;
+ printf("FAIL\n");
+ printf("%s:%d\n", file, lineno);
+ if (error && error->release) {
+ printf("%s\n", error->message);
+ error->release(error);
+ }
+}
+
+#define ADBCV_ASSERT_FAILS_WITH(STATUS, ERROR, EXPR)
\
+ AdbcValidateBeginAssert(adbc_context, "%s == %s", #EXPR,
\
+
AdbcValidateStatusCodeMessage(ADBC_STATUS_##STATUS)); \
+ if (ADBC_STATUS_##STATUS != (EXPR)) {
\
+ AdbcValidateFail(adbc_context, __FILE__, __LINE__, ERROR);
\
+ return;
\
+ }
\
+ AdbcValidatePass(adbc_context);
+#define ADBCV_ASSERT_OK(ERROR, EXPR) \
+ AdbcValidateBeginAssert(adbc_context, "%s == %s", #EXPR, \
+ AdbcValidateStatusCodeMessage(ADBC_STATUS_OK)); \
+ if (ADBC_STATUS_OK != (EXPR)) { \
+ AdbcValidateFail(adbc_context, __FILE__, __LINE__, ERROR); \
+ return; \
+ } \
+ AdbcValidatePass(adbc_context);
+#define ADBCV_ASSERT_EQ(EXPECTED, ACTUAL) \
+ AdbcValidateBeginAssert(adbc_context, "%s == %s: ", #ACTUAL, #EXPECTED); \
+ if ((EXPECTED) != (ACTUAL)) { \
+ AdbcValidateFail(adbc_context, __FILE__, __LINE__, NULL); \
+ return; \
+ } \
+ AdbcValidatePass(adbc_context);
+#define ADBCV_ASSERT_NE(EXPECTED, ACTUAL) \
+ AdbcValidateBeginAssert(adbc_context, "%s == %s: ", #ACTUAL, #EXPECTED); \
+ if ((EXPECTED) == (ACTUAL)) { \
+ AdbcValidateFail(adbc_context, __FILE__, __LINE__, NULL); \
+ return; \
+ } \
+ AdbcValidatePass(adbc_context);
+
+void AdbcValidateDatabaseNewRelease(struct AdbcValidateTestContext*
adbc_context) {
+ struct AdbcError error;
+ struct AdbcDatabase database;
+ memset(&error, 0, sizeof(error));
+ memset(&database, 0, sizeof(database));
+
+ AdbcValidateBeginCase(adbc_context, "Database", "new then release");
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
AdbcDatabaseRelease(&database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseNew(&database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseRelease(&database, &error));
+ ADBCV_ASSERT_EQ(NULL, database.private_data);
+
+ AdbcValidateBeginCase(adbc_context, "Database", "new, init, release");
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseNew(&database, &error));
+ if (adbc_context->setup_database) {
+ ADBCV_ASSERT_OK(&error, adbc_context->setup_database(&database, &error));
+ }
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseInit(&database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseRelease(&database, &error));
+ ADBCV_ASSERT_EQ(NULL, database.private_data);
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
AdbcDatabaseRelease(&database, &error));
+}
+
+void AdbcValidateConnectionNewRelease(struct AdbcValidateTestContext*
adbc_context) {
+ struct AdbcError error;
+ struct AdbcDatabase database;
+ struct AdbcConnection connection;
+ memset(&error, 0, sizeof(error));
+ memset(&database, 0, sizeof(database));
+ memset(&connection, 0, sizeof(connection));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "setup");
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseNew(&database, &error));
+ if (adbc_context->setup_database) {
+ ADBCV_ASSERT_OK(&error, adbc_context->setup_database(&database, &error));
+ }
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseInit(&database, &error));
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcConnectionRelease(&connection, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "new then release");
+ ADBCV_ASSERT_OK(&error, AdbcConnectionNew(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRelease(&connection, &error));
+ ADBCV_ASSERT_EQ(NULL, connection.private_data);
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "new, init, release");
+ ADBCV_ASSERT_OK(&error, AdbcConnectionNew(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionInit(&connection, &database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRelease(&connection, &error));
+ ADBCV_ASSERT_EQ(NULL, connection.private_data);
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcConnectionRelease(&connection, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "two concurrent
connections");
+ struct AdbcConnection connection2;
+ memset(&connection2, 0, sizeof(connection2));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionNew(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionInit(&connection, &database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionNew(&connection2, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionInit(&connection2, &database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRelease(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRelease(&connection2, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "Teardown");
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseRelease(&database, &error));
+ if (error.release) error.release(&error);
+}
+
+void AdbcValidateConnectionAutocommit(struct AdbcValidateTestContext*
adbc_context) {
+ struct AdbcError error;
+ struct AdbcDatabase database;
+ struct AdbcConnection connection;
+ memset(&error, 0, sizeof(error));
+ memset(&database, 0, sizeof(database));
+ memset(&connection, 0, sizeof(connection));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "setup");
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseNew(&database, &error));
+ if (adbc_context->setup_database) {
+ ADBCV_ASSERT_OK(&error, adbc_context->setup_database(&database, &error));
+ }
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseInit(&database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionNew(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionInit(&connection, &database, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection",
+ "commit fails with autocommit (on by default)");
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcConnectionCommit(&connection, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection",
+ "rollback fails with autocommit (on by default)");
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcConnectionRollback(&connection, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "enable autocommit");
+ ADBCV_ASSERT_OK(&error,
+ AdbcConnectionSetOption(&connection,
ADBC_CONNECTION_OPTION_AUTOCOMMIT,
+ ADBC_OPTION_VALUE_ENABLED, &error));
+ AdbcValidateBeginCase(adbc_context, "Connection", "disable autocommit");
+ ADBCV_ASSERT_OK(&error,
+ AdbcConnectionSetOption(&connection,
ADBC_CONNECTION_OPTION_AUTOCOMMIT,
+ ADBC_OPTION_VALUE_DISABLED, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "commit/rollback succeed");
+ ADBCV_ASSERT_OK(&error, AdbcConnectionCommit(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRollback(&connection, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "commit/rollback are
idempotent");
+ ADBCV_ASSERT_OK(&error, AdbcConnectionCommit(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionCommit(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRollback(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRollback(&connection, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "enable autocommit");
+ ADBCV_ASSERT_OK(&error,
+ AdbcConnectionSetOption(&connection,
ADBC_CONNECTION_OPTION_AUTOCOMMIT,
+ ADBC_OPTION_VALUE_ENABLED, &error));
+ AdbcValidateBeginCase(adbc_context, "Connection",
+ "commit/rollback fail with autocommit");
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcConnectionCommit(&connection, &error));
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcConnectionRollback(&connection, &error));
+
+ AdbcValidateBeginCase(adbc_context, "Connection", "Teardown");
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRelease(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseRelease(&database, &error));
+ if (error.release) error.release(&error);
+}
+
+void AdbcValidateStatementNewRelease(struct AdbcValidateTestContext*
adbc_context) {
+ struct AdbcError error;
+ struct AdbcDatabase database;
+ struct AdbcConnection connection;
+ struct AdbcStatement statement;
+ memset(&error, 0, sizeof(error));
+ memset(&database, 0, sizeof(database));
+ memset(&connection, 0, sizeof(connection));
+ memset(&statement, 0, sizeof(statement));
+
+ AdbcValidateBeginCase(adbc_context, "StatementNewRelease", "setup");
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseNew(&database, &error));
+ if (adbc_context->setup_database) {
+ ADBCV_ASSERT_OK(&error, adbc_context->setup_database(&database, &error));
+ }
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseInit(&database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionNew(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionInit(&connection, &database, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementNewRelease", "new then
release");
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcStatementRelease(&statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementNew(&connection, &statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementRelease(&statement, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementNewRelease", "new, execute,
release");
+ ADBCV_ASSERT_OK(&error, AdbcStatementNew(&connection, &statement, &error));
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcStatementExecute(&statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementRelease(&statement, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementNewRelease", "new, get stream,
release");
+ ADBCV_ASSERT_OK(&error, AdbcStatementNew(&connection, &statement, &error));
+ struct ArrowArrayStream out;
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcStatementGetStream(&statement, &out, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementRelease(&statement, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementNewRelease", "new, prepare,
release");
+ ADBCV_ASSERT_OK(&error, AdbcStatementNew(&connection, &statement, &error));
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcStatementPrepare(&statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementRelease(&statement, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementNewRelease", "Teardown");
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRelease(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseRelease(&database, &error));
+ if (error.release) error.release(&error);
+}
+
+void AdbcValidateStatementSqlExecute(struct AdbcValidateTestContext*
adbc_context) {
+ struct AdbcError error;
+ struct AdbcDatabase database;
+ struct AdbcConnection connection;
+ struct AdbcStatement statement;
+ struct ArrowArrayStream out;
+ memset(&error, 0, sizeof(error));
+ memset(&database, 0, sizeof(database));
+ memset(&connection, 0, sizeof(connection));
+ memset(&statement, 0, sizeof(statement));
+
+ AdbcValidateBeginCase(adbc_context, "StatementSql", "setup");
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseNew(&database, &error));
+ if (adbc_context->setup_database) {
+ ADBCV_ASSERT_OK(&error, adbc_context->setup_database(&database, &error));
+ }
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseInit(&database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionNew(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionInit(&connection, &database, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementSql", "execute");
+ ADBCV_ASSERT_OK(&error, AdbcStatementNew(&connection, &statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementSetSqlQuery(&statement, "SELECT 1",
&error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementExecute(&statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementGetStream(&statement, &out, &error));
+ ADBCV_ASSERT_NE(NULL, out.release);
+ out.release(&out);
+ ADBCV_ASSERT_OK(&error, AdbcStatementRelease(&statement, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementSql", "Teardown");
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRelease(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseRelease(&database, &error));
+ if (error.release) error.release(&error);
+}
+
+void AdbcValidateStatementSqlPrepare(struct AdbcValidateTestContext*
adbc_context) {
+ struct AdbcError error;
+ struct AdbcDatabase database;
+ struct AdbcConnection connection;
+ struct AdbcStatement statement;
+ struct ArrowArrayStream out;
+ memset(&error, 0, sizeof(error));
+ memset(&database, 0, sizeof(database));
+ memset(&connection, 0, sizeof(connection));
+ memset(&statement, 0, sizeof(statement));
+
+ AdbcValidateBeginCase(adbc_context, "StatementSql", "setup");
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseNew(&database, &error));
+ if (adbc_context->setup_database) {
+ ADBCV_ASSERT_OK(&error, adbc_context->setup_database(&database, &error));
+ }
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseInit(&database, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionNew(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcConnectionInit(&connection, &database, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementSql", "prepare");
+ ADBCV_ASSERT_OK(&error, AdbcStatementNew(&connection, &statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementSetSqlQuery(&statement, "SELECT 1",
&error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementPrepare(&statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementExecute(&statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementGetStream(&statement, &out, &error));
+ ADBCV_ASSERT_NE(NULL, out.release);
+ out.release(&out);
+ ADBCV_ASSERT_OK(&error, AdbcStatementRelease(&statement, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementSql", "prepare without
execute");
+ ADBCV_ASSERT_OK(&error, AdbcStatementNew(&connection, &statement, &error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementSetSqlQuery(&statement, "SELECT 1",
&error));
+ ADBCV_ASSERT_OK(&error, AdbcStatementPrepare(&statement, &error));
+ ADBCV_ASSERT_FAILS_WITH(INVALID_STATE, &error,
+ AdbcStatementGetStream(&statement, &out, &error));
+ ADBCV_ASSERT_EQ(NULL, out.release);
+ ADBCV_ASSERT_OK(&error, AdbcStatementRelease(&statement, &error));
+
+ AdbcValidateBeginCase(adbc_context, "StatementSql", "Teardown");
+ ADBCV_ASSERT_OK(&error, AdbcConnectionRelease(&connection, &error));
+ ADBCV_ASSERT_OK(&error, AdbcDatabaseRelease(&database, &error));
+ if (error.release) error.release(&error);
+}
diff --git a/validation/adbc_validation.h b/validation/adbc_validation.h
new file mode 100644
index 0000000..2d702ae
--- /dev/null
+++ b/validation/adbc_validation.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef ADBC_VALIDATION_H
+#define ADBC_VALIDATION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <adbc.h>
+
+struct AdbcValidateTestContext {
+ int total;
+ int passed;
+ int failed;
+ AdbcStatusCode (*setup_database)(struct AdbcDatabase* database,
+ struct AdbcError* error);
+};
+
+void AdbcValidateDatabaseNewRelease(struct AdbcValidateTestContext*
adbc_context);
+void AdbcValidateConnectionNewRelease(struct AdbcValidateTestContext*
adbc_context);
+void AdbcValidateConnectionAutocommit(struct AdbcValidateTestContext*
adbc_context);
+void AdbcValidateStatementNewRelease(struct AdbcValidateTestContext*
adbc_context);
+void AdbcValidateStatementSqlExecute(struct AdbcValidateTestContext*
adbc_context);
+void AdbcValidateStatementSqlPrepare(struct AdbcValidateTestContext*
adbc_context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ADBC_VALIDATION_H