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

Reply via email to