Is iodbc supported?
Closed this issue · 30 comments
The driver I'm trying to use only works with libiodbc.
I was able to use iodbc with odbc-rs
so I don't know if anything special is needed.
Hello @bbigras ,
"support" is a strong word, but it is possible to link odbc-api
against iodbc. Actually the abstraction does happen on the level of odbc-sys
which provides the raw interface declarations to the driver manager.
You could give the following a spin in your Cargo.toml
:
[dependencies]
odbc-api = "0.33.0"
odbc-sys = { version = "0.20.0", features = ["iodbc"] }
I don't have a way to test this, so take it with a grain of salt. You would (to my knowledge) be the first person to use odbc-api
with iodbc
so I am interessted to hear how it goes. While in theory odbc-api
should be able to work fine with any driver manager so far it is only tested with windows and UnixODBC, so I can not promise you what it works.
Switching to unixODBC on Mac is also an option, if your data source does provide drivers which works fine with it. In this stack overflow question, sadly the person did not have that option: https://stackoverflow.com/questions/66474954/using-iodbc-in-rust
Cheers, Markus
Thanks for the quick reply!
I tried odbc-sys = { version = "0.20.0", features = ["iodbc"] }
but I got the same message, which is:
Jan 20 13:40:01.330 DEBUG odbc_api::environment: ODBC Environment created.
Jan 20 13:40:01.330 WARN odbc_api::handles::logging: State: HY0, Native error: 50, Message:
Error: ODBC emitted an error calling 'SQLSetEnvAttr':
State: HY0, Native error: 50, Message:
One weird thing is that even without the iodbc
feature, my binary was linked to libiodbc.so.2
.
I'm using:
let environment = odbc_api::Environment::new()?;
let mut conn = environment.connect_with_connection_string(&conn_str)?;
conn_str
looks like:
DRIVER=wd230hfo64.so;Server Name=some_ip;Server Port=4900;Database=some_database;UID=user;PWD=password
It's a binary driver, and it only works with iodbc. The so file requires libiodbcinst.so.2
.
One weird thing is that even without the iodbc feature, my binary was linked to libiodbc.so.2.
I've been pondering about that, too. Maybe a symbolic link from libodbc.so
to libiodbc.so.2
had been created?
As mentioned in the other thread: Seems to me iodbc
doesn't support connection pooling (in the driver manager, your application code can of course still cache connections). At very least not with the attributes you are using.
Would you mind trying to just create a connection without using the r2d2-odbc-api
crate? This way we could find out if we hit any issues once the pooling is out of the way.
Yes, my latest code snippet didn't use r2d2-odbc-api.
let environment = odbc_api::Environment::new()?;
let mut conn = environment.connect_with_connection_string(&conn_str)?;
Jan 20 14:03:49.948 DEBUG odbc_api::environment: ODBC Environment created.
Jan 20 14:03:49.948 WARN odbc_api::handles::logging: State: HY0, Native error: 50, Message:
Error: ODBC emitted an error calling 'SQLSetEnvAttr':
State: HY0, Native error: 50, Message:
Does it already fail then calling Environment::new
?
the only call to SQLSetEnvAttr
here is setting the ODBC version. Which is the very first thing to do after creating an environment. odbc-api
uses a fixed ODBC version of 3.80
. What version did you use with odbc-rs
?
My guess is by the way that you used the much older ODBC 3.0
standard.
I could imagine introducing a complier flag to allow using an older version.
yeah it fails when calling odbc_api::Environment::new()?
.
[pid 738442] access("/home/bbigras/.odbcinst.ini", R_OK) = -1 ENOENT (No such file or directory)
[pid 738442] newfstatat(AT_FDCWD, "/etc/odbcinst.ini", 0x7ffd2194f250, 0) = -1 ENOENT (No such file or directory)
[pid 738442] access("/home/bbigras/.odbc.ini", R_OK) = -1 ENOENT (No such file or directory)
[pid 738442] newfstatat(AT_FDCWD, "/etc/odbc.ini", 0x7ffd2194f250, 0) = -1 ENOENT (No such file or directory)
[pid 738442] access("/home/bbigras/.odbc.ini", R_OK) = -1 ENOENT (No such file or directory)
[pid 738442] newfstatat(AT_FDCWD, "/etc/odbc.ini", 0x7ffd2194f250, 0) = -1 ENOENT (No such file or directory)
Jan 20 14:46:19.378 DEBUG odbc_api::environment: ODBC Environment created.
Jan 20 14:46:19.378 WARN odbc_api::handles::logging: State: HY0, Native error: 50, Message:
strace: Process 738450 attached
Error: ODBC emitted an error calling 'SQLSetEnvAttr':
State: HY0, Native error: strace: Process 738452 attached
50, Message:
[pid 738450] openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC <unfinished ...>
[pid 738451] +++ exited with 1 +++
[pid 738452] +++ exited with 1 +++
[pid 738448] +++ exited with 1 +++
[pid 738444] +++ exited with 1 +++
[pid 738445] +++ exited with 1 +++
[pid 738450] <... openat resumed>) = -1 (errno 18446744073709551385)
[pid 738447] +++ exited with 1 +++
[pid 738450] +++ exited with 1 +++
[pid 738449] +++ exited with 1 +++
[pid 738446] +++ exited with 1 +++
[pid 738443] +++ exited with 1 +++
+++ exited with 1 +++
with my working code:
❯ cargo tree | rg odbc
├── odbc v0.16.1
│ ├── odbc-safe v0.5.0
│ │ └── odbc-sys v0.8.2
│ └── odbc-sys v0.8.2
├── r2d2_odbc v0.2.0 (https://github.com/bbigras/r2d2-odbc.git?branch=latin1#eb9b6b37)
│ ├── odbc v0.16.1 (*)
Another difference between the odbc
and odbc-api
crate is that the odbc
crate allowed to specify the used ODBC API version. This is what the version type parameter was all about. The idea was to only implement the features for the ODBC versions which allow for them.
With odbc-api
I figured that it is probably complicated enough to write an application against one version of ODBC and decide the odbc version
used for the user. I chose version 3.8 which had been around for a several years already. Making my life and that of my users a bit easier.
This link (http://www.iodbc.org/dataspace/doc/iodbc/wiki/iodbcWiki/ODBCOnUnix#Known%20working%20ODBC%20applications) would indicate that iodbc is at least aware of ODBC version 3.5. It also seems that iodbc
is somewhat better supported than I initially thought. Might giving updating your driver manager a try?
If that doesn't work, the next thing to test would be build an odbc-api using ODBC 3.5
instead of ODBC 3.8
.
Oh, what may have not become clear from the above explaination. To see which ODBC API version you used in the past you have to look into your source code. Around the place there your environment is created and the version is declared to the application.
Do you mind me asking what your datasource is? If you are using iodbc
on linux I may be able to test this after all.
It's HFSQL. The database for windev applications. Probably a pita for anyone to download and test, if it's even possible to download without paying.
so far I found:
pub struct ODBCEnv(Environment<Version3>);
pub type Version3 = safe::Odbc3;
https://docs.rs/odbc-sys/latest/odbc_sys/enum.AttrOdbcVersion.html#variant.Odbc3
Might giving updating your driver manager a try?
You mean my wd230hfo64.so file? If so, I think I got the latest version for the (outdated) server we have.
pub type Version3 = safe::Odbc3
;
What's the information I've been looking for. Would you mind testig if it works with pub type Version = Odbc3m8
? Probably need to exchange a declare_version
with declare_version_3_8
somethere. https://docs.rs/odbc-safe/latest/odbc_safe/struct.Environment.html#method.declare_version_3_8
You mean my wd230hfo64.so file? If so, I think I got the latest version for the (outdated) server we have.
No, that would be your driver. Your driver manager is iodbc
. So "mind updating iodbc?", would have been a better way to phrase my request.
What's the information I've been looking for. Would you mind testig if it works with
pub type Version = Odbc3m8
? Probably need to exchange adeclare_version
withdeclare_version_3_8
somethere. https://docs.rs/odbc-safe/latest/odbc_safe/struct.Environment.html#method.declare_version_3_8
I'll try.
btw, with:
diff --git a/odbc-api/src/environment.rs b/odbc-api/src/environment.rs
index 455740f..9b70c37 100644
--- a/odbc-api/src/environment.rs
+++ b/odbc-api/src/environment.rs
@@ -141,7 +141,7 @@ impl Environment {
debug!("ODBC Environment created.");
let result = environment
- .declare_version(AttrOdbcVersion::Odbc3_80)
+ .declare_version(AttrOdbcVersion::Odbc3)
.into_result(&environment);
// Translate invalid attribute into a more meaningful error, provided the additional
I get:
Jan 20 15:31:06.267 DEBUG odbc_api::environment: ODBC Environment created. [37/11020]
Jan 20 15:31:06.267 WARN odbc_api::handles::logging: State: IM0, Native error: 48, Message:
thread 'main' panicked at 'rec_number argument of diagnostics must be > 0.', /home/bbigras/src/odbc-api/odbc-api/src/handles/diagnostics.rs:139:29
stack backtrace:
0: rust_begin_unwind
at /rustc/9ad5d82f822b3cb67637f11be2e65c5662b66ec0/library/std/src/panicking.rs:577:5
1: core::panicking::panic_fmt
at /rustc/9ad5d82f822b3cb67637f11be2e65c5662b66ec0/library/core/src/panicking.rs:110:14
2: odbc_api::handles::diagnostics::diagnostics
at /home/bbigras/src/odbc-api/odbc-api/src/handles/diagnostics.rs:139:29
3: odbc_api::handles::diagnostics::Record::fill_from
at /home/bbigras/src/odbc-api/odbc-api/src/handles/diagnostics.rs:166:15
4: odbc_api::handles::logging::log_diagnostics
at /home/bbigras/src/odbc-api/odbc-api/src/handles/logging.rs:11:11
5: odbc_api::error::<impl odbc_api::handles::sql_result::SqlResult<T>>::into_result
at /home/bbigras/src/odbc-api/odbc-api/src/error.rs:83:21
6: odbc_api::environment::Environment::connect_with_connection_string_utf16
at /home/bbigras/src/odbc-api/odbc-api/src/environment.rs:276:9
7: odbc_api::environment::Environment::connect_with_connection_string
at /home/bbigras/src/odbc-api/odbc-api/src/environment.rs:261:9
8: graphql_cienapps::main::main::{{closure}}
at ./src/main.rs:54:20
9: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
at /rustc/9ad5d82f822b3cb67637f11be2e65c5662b66ec0/library/core/src/future/mod.rs:84:19
10: graphql_cienapps::main::{{closure}}
at ./src/main.rs:23:1
11: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
at /rustc/9ad5d82f822b3cb67637f11be2e65c5662b66ec0/library/core/src/future/mod.rs:84:19
12: <async_std::task::builder::SupportTaskLocals<F> as core::future::future::Future>::poll::{{closure}}
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-1.10.0/src/task/builder.rs:199:17
13: async_std::task::task_locals_wrapper::TaskLocalsWrapper::set_current::{{closure}}
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-1.10.0/src/task/task_locals_wrapper.rs:60:13
14: std::thread::local::LocalKey<T>::try_with
at /rustc/9ad5d82f822b3cb67637f11be2e65c5662b66ec0/library/std/src/thread/local.rs:413:16
15: std::thread::local::LocalKey<T>::with
at /rustc/9ad5d82f822b3cb67637f11be2e65c5662b66ec0/library/std/src/thread/local.rs:389:9
16: async_std::task::task_locals_wrapper::TaskLocalsWrapper::set_current
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-1.10.0/src/task/task_locals_wrapper.rs:55:9
17: <async_std::task::builder::SupportTaskLocals<F> as core::future::future::Future>::poll
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-1.10.0/src/task/builder.rs:197:13
18: <futures_lite::future::Or<F1,F2> as core::future::future::Future>::poll
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-lite-1.12.0/src/future.rs:526:33
19: async_executor::Executor::run::{{closure}}
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-executor-1.4.1/src/lib.rs:242:31
20: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
at /rustc/9ad5d82f822b3cb67637f11be2e65c5662b66ec0/library/core/src/future/mod.rs:84:19
21: async_executor::LocalExecutor::run::{{closure}}
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-executor-1.4.1/src/lib.rs:447:33
22: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
at /rustc/9ad5d82f822b3cb67637f11be2e65c5662b66ec0/library/core/src/future/mod.rs:84:19
23: async_io::driver::block_on
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-io-1.6.0/src/driver.rs:142:33
24: async_global_executor::reactor::block_on::{{closure}}
at /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-global-executor-2.0.2/src/reactor.rs:3:18
Ok, so at least your version of iodbc
doesn't seem to be able to handle ODBC 3.8. If you could try updating iodbc
to a newer version and see if they added support that would be great. If they didn't I'll try releasing a version of odbc-api
which works with ODBC 3.5 or ODBC 3. I could probably start with that earliest thursday next week, due to other obligations. Some effort will probably go into setting up a test environment with iodbc
and some iodbc
datasource on CI.
sadly, I'm already using libiodbc-3.52.15 (the latest).
Okay, if you are impatient you can checkout odbc-api
include it with a path
statement in the cargo toml and change the odbcversion locally. See how it goes.
with this patch to odbc-rs, I get:
diff --git a/src/environment/list_data_sources.rs b/src/environment/list_data_sources.rs
index d600444..9a022ff 100644
--- a/src/environment/list_data_sources.rs
+++ b/src/environment/list_data_sources.rs
@@ -25,7 +25,7 @@ pub struct DriverInfo {
pub attributes: HashMap<String, String>,
}
-type SqlInfoMethod = fn(&mut safe::Environment<safe::Odbc3>,
+type SqlInfoMethod = fn(&mut safe::Environment<safe::Odbc3m8>,
ffi::FetchOrientation,
&mut [u8],
&mut [u8])
diff --git a/src/environment/mod.rs b/src/environment/mod.rs
index 03a2ee3..1fae324 100644
--- a/src/environment/mod.rs
+++ b/src/environment/mod.rs
@@ -5,7 +5,7 @@ use super::{ffi, into_result, safe, try_into_option, DiagnosticRecord, GetDiagRe
use std;
/// Environment state used to represent that environment has been set to odbc version 3
-pub type Version3 = safe::Odbc3;
+pub type Version3 = safe::Odbc3m8;
pub static mut OS_ENCODING: &encoding_rs::Encoding = encoding_rs::UTF_8;
pub static mut DB_ENCODING: &encoding_rs::Encoding = encoding_rs::UTF_8;
Jan 20 15:53:20.559 ERROR odbc::result: State: HY010, Native error: 0, Message: [iODBC][Driver Manager]Function sequence error
OLOLO State: HY010, Native error: 0, Message: [iODBC][Driver Manager]Function sequence error
if you are impatient you can checkout
odbc-api
include it with apath
statement in the cargo toml and change the odbcversion locally
Isn't it what I did in #148 (comment) ?
Isn't it what I did in #148 (comment) ?
It is my bad. The call stack panics, because the connection fails, but neither iodbc
nor the driver does provide a diagnostic record with an error message. I suspect what narrow connection methods would work better.
So, roadmap with regards to this issue is likely to be:
- Switch to narrow methods on non-windows platform by default
- introduce feature flag to allow going against older odbc versions
I'd be helpful to know some free and open source iodbc data sources which could be used for testing against iodbc
.
Cheers, Markus
Hello @bbigras,
odbc-api 0.34.0
has just been released. iodbc
is not officially supported yet, but the first, and possible biggest step has been taken. If compiled with the narrow
feature activated, narrow function calls are used. So if referenced in the Cargo.toml
as
odbc-api = { version="0.34.0", features=["narrow"] }
You should be able to create a connection. The compiler flag for declaring the ODBC version has not been included yet. So you would still need to edit that locally. Would you kindly repeat your experiment with the narrow
feature activated and tell me how it goes?
Cheers, Markus
Hello @bbigras ,
odbc-api 0.34.1
has just been released. It might be the first version which might work for you, without tinkering beyond setting some feature flags.
[dependencies]
odbc-api = { version = "0.34.1", features = ["odbc_version_3_5", "narrow"] }
I could at least create an iODBC environment with these settings. However I have little idea how I would set up a datasource, for testing with iodbc. Currently the ODBC version 3.5 feature flag is tested, with UnixODBC. So please tell me how it goe for you. I am fairly confident you should at least be able to create a connection, if that has worked before for you with the odbc
crate.
Cheers, Markus
Oh, sorry I forgot to test the last version.
with 0.34.0
I got:
Feb 13 13:52:30.248 DEBUG odbc_api::environment: ODBC Environment created.
Feb 13 13:52:30.248 WARN odbc_api::handles::logging: State: HY024, Native error: 0, Message:
Error: ODBC emitted an error calling 'SQLSetEnvAttr':
State: HY024, Native error: 0, Message:
But with 0.34.1
, I'm able to fetch data from a table!! 🎉
with 0.34.1, I'm able to fetch data from a table!! 🎉
Happy to hear that!
The one thing keeping me from implementing a simplified iodbc
feature flag, is my inability to set up a working iodbc
datasource in CI. If you have any idea of a freely available compatible data source tell me. Otherwise, I'll close this issue.
Cheers, Markus
Won't have time to investigate and find a freely available, easy to set up ODBC compatible with iodbc. Closing this issue. iodbc
works, but tests remain exclusively against windows and unixODBC. Not adding "official" iodbc suport for now, but happy to help out users which encounter trouble.