Closed aborsu closed 4 years ago
Hi, I work for Anaconda, and we'd like to understand what's going wrong here. Unfortunately, I don't know enough about Teradata to know what the problem is yet. It looks to me like /opt/teradata/client/16.10/bin/tdxodbc64
is a binary in a totally separate world - one that presumably finds its own libodbc. Whatever libodbc we're providing via conda presumably isn't the correct one. We'd be happy to point the python teradata at the correct one if we knew what it should be - or better yet, how to build a package with the correct one.
I was able to reproduce this problem. The issue is pretty straight forward. If we take a look at the debug output:
2018-06-21 11:08:30,604 - teradata.tdodbc - INFO - Loading ODBC Library: `libodbc.so`
2018-06-21 11:08:30,605 - teradata.tdodbc - INFO - Available drivers:
This debug information provides us two clues:
libodbc.so
https://github.com/Teradata/PyTd/blob/269b9161f77b9fd8caf17c2d8965013a4766633b/teradata/tdodbc.py#L318-L319What it doesn't tell you:
Let's take a look at:
# ls -l /usr/lib64/lib{odbc,odbcinst,ddicu28}.so
lrwxrwxrwx. 1 root root 45 Aug 3 06:36 /usr/lib64/libddicu28.so -> /opt/teradata/client/16.20/lib64/libddicu28.so
lrwxrwxrwx. 1 root root 42 Aug 3 06:36 /usr/lib64/libodbc.so -> /opt/teradata/client/16.20/lib64/libodbc.so
lrwxrwxrwx. 1 root root 46 Aug 3 06:36 /usr/lib64/libodbcinst.so -> /opt/teradata/client/16.20/lib64/libodbcinst.so
These are all symlinks created by the installation of the tdodbc driver (in my case, tdodbc1620-16.20.00.36-1.noarch.rpm)
Now, with a vanilla installation of Miniconda and then conda install teradata
or pip install teradata
, I don't see this problem. That's because it ends up loading the correct libodbc.so
via ctypes.cdll.LoadLibrary()
.
However, when I had installed unixodbc
in the same environment, the problem reported by @aborsu popped up, with the exact error message. To make it go away, I had to uninstall unixodbc
, because it provides it's own odbc shared library which goes by the same name: libodbc.so
and is sits at $CONDA_PREFIX/lib/libodbc.so
, which is preferred by ctypes.cdll.LoadLibrary()
.
However, it is not necessary that libodbc.so
is provided only by the unixodbc
conda package. It could have been provided by an installation by the system package manager too. And when that happens, it could also break the symlinks shown above.
So, to summarize, the problem really is that ctypes.cdll.LoadLibrary('libodbc.so')
is loading the wrong shared library. To verify that, one can use the following snippet:
import ctypes.util
from pathlib import Path
libdl = ctypes.CDLL(ctypes.util.find_library('dl'))
libodbc = ctypes.cdll.LoadLibrary('libodbc.so')
class linkmap(ctypes.Structure):
_fields_ = (('l_addr', ctypes.c_void_p),
('l_name', ctypes.c_char_p))
libdl.dlinfo.argtypes = (ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p)
if __name__ == '__main__':
import sys
lmptr = ctypes.c_void_p()
result = libdl.dlinfo(libodbc._handle, 2, ctypes.byref(lmptr))
abspath = ctypes.cast(lmptr, ctypes.POINTER(linkmap)).contents.l_name
if result == 0 and abspath:
abspath = Path(abspath.decode(sys.getfilesystemencoding())).resolve()
else:
abspath = u'Not Found'
print(u'libdbc.so path: %s' % abspath)
With unixodbc in the environment:
(tdata) [root@somemachine ~] # python /path/to/snippet.py
libdbc.so path: /tdata/lib/libodbc.so.2.0.0
Without unixodbc in the conda environment and no installation by system package manager:
(tdata) [root@somemachine ~] # python /path/to/snippet.py
libdbc.so path: /opt/teradata/client/16.20/lib64/libodbc.so
In case of unixodbc being installed in the same conda environment, /opt/teradata/client/16.10/bin/tdxodbc64
is unaffected because it has libodbc.so
in it's DT_NEEDED
section and picks it up from /usr/lib64/libodbc.so
, which is a symlink to the correct driver as shown above.
Another way to mitigate this issue is to pass the argument odbcLibPath:
from teradata import tdodbc
session = tdodbc.connect(method="odbc", ... odbcLibPath="/path/to/teradata/libodbc.so" );
In OP's case, it would be: /opt/teradata/client/16.10/lib64/libodbc.so
@nehaljwani I've tried this but it doesn't work either. I also have No driver found for Teradata. Unfortunately I cannot uninstall unixodbc from the environment as I need to communicate with oracle databases from the same environment so i'm stuck using pyodbc for the moment. This means no sqlAlchemy and all errors (syntax authentication, ...) are presented as a generic error.
@aborsu I patched the taradata package and changed the line:
odbc = ctypes.cdll.LoadLibrary(odbcLibPath)
to:
odbc = ctypes.cdll.LoadLibrary("/absolute/path/to/teradata/driver/provided/libodbc.so")
And now along with ODBCINST and ODBCINI pointing to the correct ini files provided by the teradata odbc driver package, everything works. I don't even have to remove unixodbc.
Hi team,
I am trying the suggested workarounds for the exact same scenario (unixodbc installed and has been removed, trying to pytd module via Anaconda returns "DRIVER_NOT_FOUND") by explicitly defining the libodbc.so actual path inside the tdodbc.py file:
def initOdbcLibrary(odbcLibPath=None):
...
odbcLibPath = "/opt/teradata/client/ODBC_64/lib/libodbc.so"
odbc = ctypes.cdll.LoadLibrary(odbcLibPath)
...
Even with this I am still getting the error. I wanted to check if there's a way to debug from the code where it returns the "DRIVER_NOT_FOUND" -- would you have any ideas?
def initDriverList():
...
rc = SQL_SUCCESS
...
rc = odbc.SQLDrivers(hEnv, direction, description,
len(description), ADDR(descriptionLength),
None, 0, attributesLength)
#rc returns a value of "100" which is SQL_NO_DATA => DRIVER_NOT_FOUND
...
Thanks.
Hello,
Same thing for me, specifying the odbcLibPath does not resolve the issue.
Hey all,
I'm having the exact same issue. Even if I set ODBCINI
and/or ODBCINST
environment variables, I still get no available drivers. Desperate for any solution. This is using a conda Python 3 instance.
We switched to the new teradatasql package. No issue anymore
Had the same issue. Tried many of the above but nothing worked. I removed anaconda and installed python36 and it is working now on oracle linux.
This is all I have in my .bash_profile: export ODBCINI=/opt/teradata/client/ODBC_64/odbc.ini
And then the contents of /opt/teradata/client/ODBC_64/odbc.ini are: [ODBC Drivers] Teradata Database ODBC Driver 16.20=Installed
[Teradata Database ODBC Driver 16.20] Description=Teradata Database ODBC Driver 16.20 Driver=/opt/teradata/client/ODBC_64/lib/tdataodbc_sb64.so CPTimeout=60
[ODBC] InstallDir=/opt/teradata/client/ODBC_64 Trace=no Pooling=yes
[ODBC Data Sources] Teradata ODBC DSN=Teradata Database ODBC Driver 16.20
[TDP6] Description=Teradata Database ODBC Driver 16.20
Driver=/opt/teradata/client/ODBC_64/lib/tdataodbc_sb64.so
DBCName1=<put your teradata ip here>
UID=
PWD=
Hope this helps!
I've taken the liberty to create a new issue as the no drivers recognized has a couple of issues open already, but I think the problem comes from the use of a conda install of python rather than a system install (I'm not sure).
When using tdxodbc everything works even from python, but from conda the drivers are not recognized. I believe that when using conda, it by defaults uses the libodbc.so library that is packaged with conda rather than the system one.