Skip to content

Commit 3115969

Browse files
authored
fix(c/driver_manager): test and fix bugs in profiles (#4080)
- Fix substitution of undefined env var erasing the entire value instead of substituting in a blank string. - Improve error messages. - Add end-to-end tests with Python. - Add end-to-end tests in Conda/virtualenv. - Add end-to-end tests with the user path (`~/.config`, etc.) This is not complete; see #4082, #4085, #4086, #4087 for things that also need to be fixed, but this establishes a baseline of tests. Closes #4024.
1 parent adea2d7 commit 3115969

15 files changed

Lines changed: 837 additions & 194 deletions

.github/workflows/native-unix.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ jobs:
589589
ADBC_USE_UBSAN: "0"
590590
run: |
591591
export PATH=$RUNNER_TOOL_CACHE/go/${GO_VERSION}/x64/bin:$PATH
592+
export _ADBC_IS_CONDA=1
592593
./ci/scripts/python_build.sh "$(pwd)" "$(pwd)/build" "$HOME/local"
593594
- name: Build Panic Dummy
594595
run: |
@@ -603,6 +604,8 @@ jobs:
603604
run: |
604605
cargo build -padbc_dummy
605606
- name: Test Python Driver Manager
607+
env:
608+
PYTEST_ADDOPTS: "--run-system"
606609
run: |
607610
if [[ $(uname) = "Darwin" ]]; then
608611
export PANICDUMMY_LIBRARY_PATH=$(pwd)/go/adbc/pkg/libadbc_driver_panicdummy.dylib

.github/workflows/native-windows.yml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -337,21 +337,15 @@ jobs:
337337
env:
338338
BUILD_ALL: "0"
339339
BUILD_DRIVER_MANAGER: "1"
340-
run: .\ci\scripts\python_build.ps1 $pwd $pwd\build
341-
- name: Build Python Driver PostgreSQL
342-
env:
343-
BUILD_ALL: "0"
344340
BUILD_DRIVER_POSTGRESQL: "1"
345-
run: .\ci\scripts\python_build.ps1 $pwd $pwd\build
346-
- name: Build Python Driver SQLite
347-
env:
348-
BUILD_ALL: "0"
349341
BUILD_DRIVER_SQLITE: "1"
342+
_ADBC_IS_CONDA: "1"
350343
run: .\ci\scripts\python_build.ps1 $pwd $pwd\build
351344
- name: Test Python Driver Manager
352345
env:
353346
BUILD_ALL: "0"
354347
BUILD_DRIVER_MANAGER: "1"
348+
PYTEST_ADDOPTS: "--run-system"
355349
run: .\ci\scripts\python_test.ps1 $pwd $pwd\build
356350
- name: Test Python Driver PostgreSQL
357351
env:

c/driver/framework/connection.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ class Connection : public ObjectBase {
165165
}
166166
return driver::Option();
167167
}
168-
return Base::GetOption(key);
168+
return status::NotImplemented(Derived::kErrorPrefix, " Unknown connection option ",
169+
key);
169170
}
170171

171172
/// \internal

c/driver/sqlite/sqlite.cc

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ constexpr std::string_view kConnectionOptionLoadExtensionEntrypoint =
5252
/// The batch size for query results (and for initial type inference)
5353
constexpr std::string_view kStatementOptionBatchRows = "adbc.sqlite.query.batch_rows";
5454
constexpr std::string_view kStatementOptionBindByName = "adbc.statement.bind_by_name";
55+
constexpr int kDefaultBatchSize = 1024;
5556

5657
std::string_view GetColumnText(sqlite3_stmt* stmt, int index) {
5758
return {
@@ -547,6 +548,15 @@ class SqliteDatabase : public driver::Database<SqliteDatabase> {
547548
return Base::ReleaseImpl();
548549
}
549550

551+
Result<driver::Option> GetOption(std::string_view key) override {
552+
if (key == "uri") {
553+
return driver::Option(uri_);
554+
} else if (key == kStatementOptionBatchRows) {
555+
return driver::Option(static_cast<int64_t>(batch_size_));
556+
}
557+
return Base::GetOption(key);
558+
}
559+
550560
Status SetOptionImpl(std::string_view key, driver::Option value) override {
551561
if (key == "uri") {
552562
if (lifecycle_state_ != driver::LifecycleState::kUninitialized) {
@@ -556,13 +566,32 @@ class SqliteDatabase : public driver::Database<SqliteDatabase> {
556566
UNWRAP_RESULT(uri, value.AsString());
557567
uri_ = std::move(uri);
558568
return status::Ok();
569+
} else if (key == kStatementOptionBatchRows) {
570+
if (lifecycle_state_ != driver::LifecycleState::kUninitialized) {
571+
return status::fmt::InvalidState(
572+
"{} cannot set {} after AdbcDatabaseInit, set it directly on the statement "
573+
"instead",
574+
kErrorPrefix, key);
575+
}
576+
int64_t batch_size;
577+
UNWRAP_RESULT(batch_size, value.AsInt());
578+
if (batch_size <= 0 || batch_size > std::numeric_limits<int>::max()) {
579+
return status::fmt::InvalidArgument(
580+
"{} Invalid statement option value {}={} (value is non-positive or out of "
581+
"range of int)",
582+
kErrorPrefix, key, value.Format());
583+
}
584+
batch_size_ = static_cast<int>(batch_size);
585+
return status::Ok();
559586
}
560587
return Base::SetOptionImpl(key, value);
561588
}
562589

563590
private:
591+
friend class SqliteConnection;
564592
std::string uri_{kDefaultUri};
565593
sqlite3* conn_ = nullptr;
594+
int batch_size_ = kDefaultBatchSize;
566595
};
567596

568597
class SqliteConnection : public driver::Connection<SqliteConnection> {
@@ -672,6 +701,7 @@ class SqliteConnection : public driver::Connection<SqliteConnection> {
672701
Status InitImpl(void* parent) {
673702
auto& db = *reinterpret_cast<SqliteDatabase*>(parent);
674703
UNWRAP_RESULT(conn_, db.OpenConnection());
704+
batch_size_ = db.batch_size_;
675705
return status::Ok();
676706
}
677707

@@ -693,6 +723,13 @@ class SqliteConnection : public driver::Connection<SqliteConnection> {
693723
return SqliteQuery::Execute(conn_, "BEGIN");
694724
}
695725

726+
Result<driver::Option> GetOption(std::string_view key) override {
727+
if (key == kStatementOptionBatchRows) {
728+
return driver::Option(static_cast<int64_t>(batch_size_));
729+
}
730+
return Base::GetOption(key);
731+
}
732+
696733
Status SetOptionImpl(std::string_view key, driver::Option value) {
697734
if (key == kConnectionOptionEnableLoadExtension) {
698735
if (!conn_ || lifecycle_state_ != driver::LifecycleState::kInitialized) {
@@ -761,6 +798,8 @@ class SqliteConnection : public driver::Connection<SqliteConnection> {
761798
}
762799

763800
private:
801+
friend class SqliteStatement;
802+
764803
Status CheckOpen() const {
765804
if (!conn_) {
766805
return status::InvalidState("connection is not open");
@@ -772,6 +811,7 @@ class SqliteConnection : public driver::Connection<SqliteConnection> {
772811
// Temporarily hold the extension path (since the path and entrypoint need
773812
// to be set separately)
774813
std::string extension_path_;
814+
int batch_size_ = kDefaultBatchSize;
775815
};
776816

777817
class SqliteStatement : public driver::Statement<SqliteStatement> {
@@ -1111,7 +1151,9 @@ class SqliteStatement : public driver::Statement<SqliteStatement> {
11111151
}
11121152

11131153
Status InitImpl(void* parent) {
1114-
conn_ = reinterpret_cast<SqliteConnection*>(parent)->conn();
1154+
auto& conn = *reinterpret_cast<SqliteConnection*>(parent);
1155+
conn_ = conn.conn();
1156+
batch_size_ = conn.batch_size_;
11151157
return Statement::InitImpl(parent);
11161158
}
11171159

@@ -1151,7 +1193,16 @@ class SqliteStatement : public driver::Statement<SqliteStatement> {
11511193
return Statement::ReleaseImpl();
11521194
}
11531195

1154-
Status SetOptionImpl(std::string_view key, driver::Option value) {
1196+
Result<driver::Option> GetOption(std::string_view key) override {
1197+
if (key == kStatementOptionBatchRows) {
1198+
return driver::Option(static_cast<int64_t>(batch_size_));
1199+
} else if (key == kStatementOptionBindByName) {
1200+
return driver::Option(bind_by_name_ ? "true" : "false");
1201+
}
1202+
return Base::GetOption(key);
1203+
}
1204+
1205+
Status SetOptionImpl(std::string_view key, driver::Option value) override {
11551206
if (key == kStatementOptionBatchRows) {
11561207
int64_t batch_size;
11571208
UNWRAP_RESULT(batch_size, value.AsInt());
@@ -1170,7 +1221,7 @@ class SqliteStatement : public driver::Statement<SqliteStatement> {
11701221
return Base::SetOptionImpl(key, std::move(value));
11711222
}
11721223

1173-
int batch_size_ = 1024;
1224+
int batch_size_ = kDefaultBatchSize;
11741225
bool bind_by_name_ = false;
11751226
AdbcSqliteBinder binder_;
11761227
sqlite3* conn_ = nullptr;

c/driver_manager/adbc_driver_manager.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ AdbcStatusCode InternalInitializeProfile(TempDatabase* args,
471471
// use try_emplace so we only add the option if there isn't
472472
// already an option with the same name
473473
std::string processed;
474-
CHECK_STATUS(ProcessProfileValue(values[i], processed, error));
474+
CHECK_STATUS(ProcessProfileValue(keys[i], values[i], processed, error));
475475
args->options.try_emplace(keys[i], processed);
476476
}
477477

c/driver_manager/adbc_driver_manager_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ AdbcStatusCode LoadDriverFromRegistry(HKEY root, const std::wstring& driver_name
189189
#endif
190190

191191
// Profile loading
192-
AdbcStatusCode ProcessProfileValue(std::string_view value, std::string& out,
193-
struct AdbcError* error);
192+
AdbcStatusCode ProcessProfileValue(std::string_view key, std::string_view value,
193+
std::string& out, struct AdbcError* error);
194194

195195
// Initialization
196196
/// Temporary state while the database is being configured.

0 commit comments

Comments
 (0)