Skip to content

Commit

Permalink
use db2 dsn in tests and readme default configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
rupurt committed Jul 16, 2023
1 parent b6d1d13 commit 9ad0f91
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 74 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ testext
test/python/__pycache__/
.Rhistory
.clangd
.data
.odbc.ini
.odbcinst.ini
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ A DuckDB extension to read data directly from databases supporting the ODBC inte

### odbc_scan

```shell
ODBCSYSINI=${PWD} ODBCINSTINI=.odbcinst.ini ODBCINI=.odbc.ini ./build/release/duckdb
```
```duckdb
D select * from odbc_scan(
'Driver=/nix/store/py6m0q4ij50pwjk6a5f18qhhahrvf2sk-db2-driver-11.5.8/lib/libdb2.so;Hostname=localhost;Database=odbctest;Uid=db2inst1;Pwd=password;Port=50000',
'Driver={db2 odbctest};Hostname=localhost;Database=odbctest;Uid=db2inst1;Pwd=password;Port=50000',
'DB2INST1',
'PEOPLE'
);
Expand Down Expand Up @@ -42,12 +45,9 @@ This extension is tested and known to work with the ODBC drivers of the followin
If you have tested the extension against other databases let us know by opening an [issue](https://github.com/rupurt/odbc-scanner-duckdb-extension/issues/new)
or creating a pull request with a set of tests.

## Supported DSN Formats
## Connection String and DSN Formats

### Connection Strings

- IBM Db2 - `Driver=/nix/store/py6m0q4ij50pwjk6a5f18qhhahrvf2sk-db2-driver-11.5.8/lib/libdb2.so;Hostname=localhost;Database=odbctest;Uid=db2inst1;Pwd=password;Port=50000`
- Postgres - `Driver=/opt/homebrew/Cellar/psqlodbc/15.00.0000/lib/psqlodbca.so;Server=localhost;Database=odbc_test;Uid=postgres;Pwd=password;Port=5432`
For a full list of supported values read the [connection string](./docs/ODBC_CONNECTION_STRING_AND_DSN_FORMATS.md) documentation.

## Development

Expand Down Expand Up @@ -75,6 +75,13 @@ nix run .#build
./build/release/duckdb
```

To use ODBC DSN's with driver paths managed by the `odbc-drivers-nix` flake run the generate nix apps.

```shell
nix run .#generate-odbc-ini
nix run .#generate-odbcinst-ini
```

## Test

Run the official DuckDB `cmake` builder with `nix` to ensure `unixodbc` is linked correctly
Expand Down
33 changes: 33 additions & 0 deletions docs/ODBC_CONNECTION_STRING_AND_DSN_FORMATS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ODBC Connection String and DSN Formats

`odbc-scanner-duckdb` supports standard ODBC connection string and DSN formats. A detailed list can be obtained
from [connectionstrings.com](https://www.connectionstrings.com).

## Find the Path to your Nix managed ODBC Driver

```shell
nix run .#odbc-driver-paths
db2 /nix/store/6flbacf9h5bk09iw37b7sncgjn9mdkwj-db2-odbc-driver-11.5.8/lib/libdb2.so
```

## DSN's

### Db2

```odbc.ini
[db2 odbctest]
Driver = db2
```

```odbcinst.ini
[db2]
Driver = ${DB2_DRIVER_PATH}
```

## Connection Strings

### Db2

```
Driver=/nix/store/py6m0q4ij50pwjk6a5f18qhhahrvf2sk-db2-driver-11.5.8/lib/libdb2.so;Hostname=localhost;Database=odbctest;Uid=db2inst1;Pwd=password;Port=50000
```
83 changes: 76 additions & 7 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 52 additions & 22 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,35 @@
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
odbc-drivers.url = "github:rupurt/odbc-drivers-nix";
};

outputs = {
flake-utils,
nixpkgs,
odbc-drivers,
...
}: let
systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"];
outputs = flake-utils.lib.eachSystem systems (system: let
pkgs = import nixpkgs {
inherit system;
# config = { allowUnfree = true; };
};
# use old version of nix packages that builds against glibc 2.35
pkgs =
import (builtins.fetchGit {
name = "nixpkgs-with-glibc-2.35-224";
url = "https://github.com/nixos/nixpkgs";
ref = "refs/heads/nixpkgs-unstable";
rev = "8ad5e8132c5dcf977e308e7bf5517cc6cc0bf7d8";
}) {
inherit system;
overlays = [
odbc-drivers.overlay
];
};
stdenv = pkgs.llvmPackages_15.stdenv;
in rec {
# packages exported by the flake
packages = {};
packages = {
db2-odbc-driver = pkgs.db2-odbc-driver {};
};

# nix run
apps = {
Expand All @@ -30,6 +43,23 @@
envsubst < ./templates/.clangd.template > .clangd
'');
};
generate-odbc-ini = {
type = "app";
program = toString (pkgs.writeScript "generate-odbc-ini" ''
cp ./templates/.odbc.ini.template .odbc.ini
'');
};
generate-odbcinst-ini = {
type = "app";
program = toString (pkgs.writeScript "generate-odbcinst-ini" ''
DB2_DRIVER_PATH=${packages.db2-odbc-driver}/lib/${if stdenv.isDarwin then "libdb2.dylib" else "libdb2.so"} \
envsubst < ./templates/.odbcinst.ini.template > .odbcinst.ini
'');
};
ls-odbc-driver-paths = {
type = "app";
program = toString (pkgs.writeScript "ls-odbc-driver-paths" ''
echo "db2 ${packages.db2-odbc-driver}/lib/${if stdenv.isDarwin then "libdb2.dylib" else "libdb2.so"}"
'');
};
load-db2-schema = {
Expand All @@ -47,18 +77,18 @@
gnumake
cmake
ninja
llvmPackages_16.clang
openssl
# unixODBCDrivers.msodbcsql17
unixODBCDrivers.psql
# unixODBCDrivers.mariadb
packages.db2-odbc-driver
]
)}:$PATH"
export CC=${pkgs.llvmPackages_16.clang}/bin/clang
export CXX=${pkgs.llvmPackages_16.clang}/bin/clang++
export CC=${stdenv.cc}/bin/clang
export CXX=${stdenv.cc}/bin/clang++
make \
GEN=ninja \
ODBCSYSINI=$PWD \
ODBCINSTINI=.odbcinst.ini \
ODBCINI=$PWD/.odbc.ini \
test CLIENT_FLAGS="-DODBC_CONFIG=${pkgs.unixODBC}/bin/odbc_config"
'');
};
Expand All @@ -71,15 +101,12 @@
gnumake
cmake
ninja
llvmPackages_16.clang
openssl
# unixODBCDrivers.msodbcsql17
unixODBCDrivers.psql
# unixODBCDrivers.mariadb
packages.db2-odbc-driver
]
)}:$PATH"
export CC=${pkgs.llvmPackages_16.clang}/bin/clang
export CXX=${pkgs.llvmPackages_16.clang}/bin/clang++
export CC=${stdenv.cc}/bin/clang
export CXX=${stdenv.cc}/bin/clang++
make \
GEN=ninja \
Expand All @@ -98,14 +125,17 @@
pkgs.git
pkgs.gnumake
pkgs.cmake
# faster cmake builds
pkgs.ninja
pkgs.llvmPackages_16.clang
# clangd lsp
pkgs.llvmPackages_15.bintools
pkgs.llvmPackages_15.clang
pkgs.envsubst
pkgs.openssl
pkgs.unixODBC
# pkgs.unixODBCDrivers.msodbcsql17
pkgs.unixODBCDrivers.psql
# pkgs.unixODBCDrivers.mariadb
# psql cli
pkgs.postgresql_15
packages.db2-odbc-driver
];
};
});
Expand Down
10 changes: 5 additions & 5 deletions src/include/odbc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,15 +294,15 @@ struct OdbcConnection {
" native=" + std::to_string(diagnostics->native));
}
}
void Dial(string dsn) {
auto conn_str_in_len = (SQLSMALLINT)dsn.length();
void Dial(string connection_string) {
auto conn_str_in_len = (SQLSMALLINT)connection_string.length();
SQLSMALLINT conn_str_out_len = 0;
SQLCHAR conn_str_out[MAX_CONN_STR_OUT + 1] = {0};

auto sql_return = SQLDriverConnect(
handle_conn, NULL, (SQLCHAR *)dsn.c_str(), conn_str_in_len,
conn_str_out, (SQLSMALLINT)MAX_CONN_STR_OUT, &conn_str_out_len,
SQL_DRIVER_NOPROMPT);
handle_conn, NULL, (SQLCHAR *)connection_string.c_str(),
conn_str_in_len, conn_str_out, (SQLSMALLINT)MAX_CONN_STR_OUT,
&conn_str_out_len, SQL_DRIVER_NOPROMPT);
if (sql_return == SQL_SUCCESS || sql_return == SQL_SUCCESS_WITH_INFO) {
dialed = true;
} else if (sql_return == SQL_NO_DATA_FOUND) {
Expand Down
9 changes: 4 additions & 5 deletions src/include/odbc_scan.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

namespace duckdb {
struct OdbcScanBindData : public FunctionData {
string dsn;
string connection_string;
string schema_name;
string table_name;
shared_ptr<OdbcEnvironment> environment;
Expand Down Expand Up @@ -289,7 +289,7 @@ class OdbcScanFunction : public TableFunction {
OdbcScanBind(ClientContext &context, TableFunctionBindInput &input,
vector<LogicalType> &return_types, vector<string> &names) {
auto bind_data = make_uniq<OdbcScanBindData>();
bind_data->dsn = input.inputs[0].GetValue<string>();
bind_data->connection_string = input.inputs[0].GetValue<string>();
bind_data->schema_name = input.inputs[1].GetValue<string>();
bind_data->table_name = input.inputs[2].GetValue<string>();

Expand All @@ -298,7 +298,7 @@ class OdbcScanFunction : public TableFunction {

bind_data->connection = make_shared<OdbcConnection>();
bind_data->connection->Init(bind_data->environment);
bind_data->connection->Dial(bind_data->dsn);
bind_data->connection->Dial(bind_data->connection_string);

bind_data->statement = make_uniq<OdbcStatement>(bind_data->connection);
bind_data->statement->Init();
Expand Down Expand Up @@ -335,8 +335,7 @@ class OdbcScanFunction : public TableFunction {
static unique_ptr<GlobalTableFunctionState>
OdbcScanInitGlobalState(ClientContext &context,
TableFunctionInitInput &input) {
auto global_state = make_uniq<OdbcScanGlobalState>();
return global_state;
return make_uniq<OdbcScanGlobalState>();
}

static unique_ptr<LocalTableFunctionState>
Expand Down
2 changes: 2 additions & 0 deletions templates/.odbc.ini.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[db2 odbctest]
Driver = db2
2 changes: 2 additions & 0 deletions templates/.odbcinst.ini.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[db2]
Driver = ${DB2_DRIVER_PATH}
Loading

0 comments on commit 9ad0f91

Please sign in to comment.