1717#include " duckdb/common/adbc/options.h"
1818#include " duckdb/common/adbc/single_batch_array_stream.hpp"
1919#include " duckdb/function/table/arrow.hpp"
20-
20+ # include " duckdb/common/adbc/wrappers.hpp "
2121#include < stdlib.h>
2222#include < string.h>
2323
@@ -249,7 +249,9 @@ AdbcStatusCode ConnectionNew(struct AdbcConnection *connection, struct AdbcError
249249 return ADBC_STATUS_INVALID_ARGUMENT;
250250 }
251251
252- connection->private_data = nullptr ;
252+ auto connection_wrapper = new duckdb::DuckDBAdbcConnectionWrapper ();
253+ connection_wrapper->connection = nullptr ;
254+ connection->private_data = connection_wrapper;
253255 return ADBC_STATUS_OK;
254256}
255257
@@ -263,45 +265,65 @@ AdbcStatusCode ExecuteQuery(duckdb::Connection *conn, const char *query, struct
263265 return ADBC_STATUS_OK;
264266}
265267
268+ AdbcStatusCode InternalSetOption (duckdb::Connection &conn, std::unordered_map<std::string, std::string> &options,
269+ struct AdbcError *error) {
270+ // If we got here, the options have already been validated and are acceptable
271+ for (auto &option : options) {
272+ if (strcmp (option.first .c_str (), ADBC_CONNECTION_OPTION_AUTOCOMMIT) == 0 ) {
273+ if (strcmp (option.second .c_str (), ADBC_OPTION_VALUE_ENABLED) == 0 ) {
274+ if (conn.HasActiveTransaction ()) {
275+ AdbcStatusCode status = ExecuteQuery (&conn, " COMMIT" , error);
276+ if (status != ADBC_STATUS_OK) {
277+ options.clear ();
278+ return status;
279+ }
280+ }
281+ } else if (strcmp (option.second .c_str (), ADBC_OPTION_VALUE_DISABLED) == 0 ) {
282+ if (!conn.HasActiveTransaction ()) {
283+ AdbcStatusCode status = ExecuteQuery (&conn, " START TRANSACTION" , error);
284+ if (status != ADBC_STATUS_OK) {
285+ options.clear ();
286+ return status;
287+ }
288+ }
289+ }
290+ }
291+ }
292+ options.clear ();
293+ return ADBC_STATUS_OK;
294+ }
266295AdbcStatusCode ConnectionSetOption (struct AdbcConnection *connection, const char *key, const char *value,
267296 struct AdbcError *error) {
268297 if (!connection) {
269298 SetError (error, " Connection is not set" );
270299 return ADBC_STATUS_INVALID_ARGUMENT;
271300 }
272-
273- auto conn = static_cast <duckdb::Connection *>(connection->private_data );
301+ std::string key_string = std::string (key);
302+ std::string key_value = std::string (value);
303+ auto conn_wrapper = static_cast <duckdb::DuckDBAdbcConnectionWrapper *>(connection->private_data );
274304 if (strcmp (key, ADBC_CONNECTION_OPTION_AUTOCOMMIT) == 0 ) {
275305 if (strcmp (value, ADBC_OPTION_VALUE_ENABLED) == 0 ) {
276- if (conn->HasActiveTransaction ()) {
277- AdbcStatusCode status = ExecuteQuery (conn, " COMMIT" , error);
278- if (status != ADBC_STATUS_OK) {
279- return status;
280- }
281- } else {
282- // no-op
283- }
306+ conn_wrapper->options [key_string] = key_value;
284307 } else if (strcmp (value, ADBC_OPTION_VALUE_DISABLED) == 0 ) {
285- if (conn->HasActiveTransaction ()) {
286- // no-op
287- } else {
288- // begin
289- AdbcStatusCode status = ExecuteQuery (conn, " START TRANSACTION" , error);
290- if (status != ADBC_STATUS_OK) {
291- return status;
292- }
293- }
308+ conn_wrapper->options [key_string] = key_value;
294309 } else {
295310 auto error_message = " Invalid connection option value " + std::string (key) + " =" + std::string (value);
296311 SetError (error, error_message);
297312 return ADBC_STATUS_INVALID_ARGUMENT;
298313 }
314+ } else {
315+ // This is an unknown option to the DuckDB driver
316+ auto error_message =
317+ " Unknown connection option " + std::string (key) + " =" + (value ? std::string (value) : " (NULL)" );
318+ SetError (error, error_message);
319+ return ADBC_STATUS_NOT_IMPLEMENTED;
320+ }
321+ if (!conn_wrapper->connection ) {
322+ // If the connection has not yet been initialized, we just return here.
299323 return ADBC_STATUS_OK;
300324 }
301- auto error_message =
302- " Unknown connection option " + std::string (key) + " =" + (value ? std::string (value) : " (NULL)" );
303- SetError (error, error_message);
304- return ADBC_STATUS_NOT_IMPLEMENTED;
325+ auto conn = reinterpret_cast <duckdb::Connection *>(conn_wrapper->connection );
326+ return InternalSetOption (*conn, conn_wrapper->options , error);
305327}
306328
307329AdbcStatusCode ConnectionReadPartition (struct AdbcConnection *connection, const uint8_t *serialized_partition,
@@ -323,7 +345,8 @@ AdbcStatusCode ConnectionCommit(struct AdbcConnection *connection, struct AdbcEr
323345 SetError (error, " Connection is not set" );
324346 return ADBC_STATUS_INVALID_ARGUMENT;
325347 }
326- auto conn = static_cast <duckdb::Connection *>(connection->private_data );
348+ auto conn_wrapper = static_cast <duckdb::DuckDBAdbcConnectionWrapper *>(connection->private_data );
349+ auto conn = reinterpret_cast <duckdb::Connection *>(conn_wrapper->connection );
327350 if (!conn->HasActiveTransaction ()) {
328351 SetError (error, " No active transaction, cannot commit" );
329352 return ADBC_STATUS_INVALID_STATE;
@@ -341,7 +364,8 @@ AdbcStatusCode ConnectionRollback(struct AdbcConnection *connection, struct Adbc
341364 SetError (error, " Connection is not set" );
342365 return ADBC_STATUS_INVALID_ARGUMENT;
343366 }
344- auto conn = static_cast <duckdb::Connection *>(connection->private_data );
367+ auto conn_wrapper = static_cast <duckdb::DuckDBAdbcConnectionWrapper *>(connection->private_data );
368+ auto conn = reinterpret_cast <duckdb::Connection *>(conn_wrapper->connection );
345369 if (!conn->HasActiveTransaction ()) {
346370 SetError (error, " No active transaction, cannot rollback" );
347371 return ADBC_STATUS_INVALID_STATE;
@@ -479,16 +503,25 @@ AdbcStatusCode ConnectionInit(struct AdbcConnection *connection, struct AdbcData
479503 return ADBC_STATUS_INVALID_ARGUMENT;
480504 }
481505 auto database_wrapper = static_cast <DuckDBAdbcDatabaseWrapper *>(database->private_data );
506+ auto conn_wrapper = static_cast <duckdb::DuckDBAdbcConnectionWrapper *>(connection->private_data );
507+ conn_wrapper->connection = nullptr ;
482508
483- connection->private_data = nullptr ;
484- auto res =
485- duckdb_connect (database_wrapper->database , reinterpret_cast <duckdb_connection *>(&connection->private_data ));
486- return CheckResult (res, error, " Failed to connect to Database" );
509+ auto res = duckdb_connect (database_wrapper->database , &conn_wrapper->connection );
510+ auto adbc_status = CheckResult (res, error, " Failed to connect to Database" );
511+ if (adbc_status != ADBC_STATUS_OK) {
512+ return adbc_status;
513+ }
514+ // We might have options to set
515+ auto conn = reinterpret_cast <duckdb::Connection *>(conn_wrapper->connection );
516+ return InternalSetOption (*conn, conn_wrapper->options , error);
487517}
488518
489519AdbcStatusCode ConnectionRelease (struct AdbcConnection *connection, struct AdbcError *error) {
490520 if (connection && connection->private_data ) {
491- duckdb_disconnect (reinterpret_cast <duckdb_connection *>(&connection->private_data ));
521+ auto conn_wrapper = static_cast <duckdb::DuckDBAdbcConnectionWrapper *>(connection->private_data );
522+ auto conn = reinterpret_cast <duckdb::Connection *>(conn_wrapper->connection );
523+ duckdb_disconnect (reinterpret_cast <duckdb_connection *>(&conn));
524+ delete conn_wrapper;
492525 connection->private_data = nullptr ;
493526 }
494527 return ADBC_STATUS_OK;
@@ -638,7 +671,9 @@ AdbcStatusCode StatementNew(struct AdbcConnection *connection, struct AdbcStatem
638671 }
639672
640673 statement->private_data = statement_wrapper;
641- statement_wrapper->connection = static_cast <duckdb_connection>(connection->private_data );
674+ auto conn_wrapper = static_cast <duckdb::DuckDBAdbcConnectionWrapper *>(connection->private_data );
675+
676+ statement_wrapper->connection = conn_wrapper->connection ;
642677 statement_wrapper->statement = nullptr ;
643678 statement_wrapper->result = nullptr ;
644679 statement_wrapper->ingestion_stream .release = nullptr ;
0 commit comments