-
Notifications
You must be signed in to change notification settings - Fork 562
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pyodbc with iodbc #444
Comments
Perhaps @TallTed may be able to help. |
Hi, Pleasantly easy to fix: you haven't linked against This patch is sufficient, albeit inelegant:
For the record this was on a brand new ubuntu 18.04 VM for the purpose; theoretically you shouldn't need more than A more elegant fix would attempt to use HTH ~Tim |
Thanks Tim. There are a couple of issues to work out:
As you know (and your example above shows), it isn't possible to provide a build that works for both. We could make the code work using an I used to have pyodbc detect whether iODBC was installed and use it where possible. This led to non-stop problems and questions, so I removed it when Apple (seemed to) back off of iODBC. (Apparently they still ship libraries, just not header files. That could just be because their software uses it.) My proposal for (1) is to default to unixODBC everywhere and have a flag for those that want a custom build. Is that useful to anyone? It would mean you couldn't just use pip install, though. That seems like a real show stopper for a ton of people. Is there a way to pass flags in pip that I missed? I'm hoping the flag above would also work for macOS and binary wheels. It's not possible to build a single binary that works with both unixODBC and iODBC, so I have to pick one if I'm going to provide binaries. And on macOS, I don't think everyone has Xcode configured. The binaries seem pretty popular. Would the same flag work here also? If you want a macOS iODBC build, you have to download the code and build it yourself, adding a flag to setup.cfg or the command line. It seems like a can of worms, but I get that iODBC users want a solution. Is there a better approach? |
Hi, High Sierra here says:
So it sounds to me like iODBC is the default system-wide reliable option on macOS, while linux distros tend to default to unixODBC. ç'est la vie. I'm not an expert on what's possible in I think this addresses both linux and macOS, both vanilla default installations and cluttered dev environments. Are people who want custom local builds really going to worry about using pip? HTH |
@timhaynesopenlink re: "build your binaries with unixODBC for linux and iODBC for macOS" That makes sense to me if my understanding is correct that macOS ships with the iODBC binaries (much like how the Windows OS ships with its own ODBC driver manager) and therefore the macOS wheels built for iODBC will allow mere mortals to have |
@gordthompson - Yes, macOS has shipped with iODBC dylibs since 10.3.0, which you can verify on Apple's OpenSource listings. |
I actually knew the libraries were still there, but the real problem is that the ODBC drivers are not interchangeable between unixODBC and iODBC. Even if libraries are available, if everyone wants to use unixODBC drivers installed with brew, I'd be fielding a lot of questions. Maybe I should register pyodbc-iodbc as a different pypi project or something. |
@mkleehammer re: "Maybe I should register pyodbc-iodbc as a different pypi project or something." I had the same idea myself, but then I thought "Why would someone want to override (replace?) iODBC with unixODBC if iODBC is already there on macOS?". I suppose one possibility might be that pyodbc has gained a reputation of being tied to unixODBC (which it [sort of] is, at least currently), causing Mac users to assume that they need to jump through some hoops for unixODBC. Perhaps if it "just works" with an iODBC build for macOS then those brew/unixODBC questions will go away (eventually). In other words, is it really that "everyone wants to use unixODBC", or is it that Mac users believe (reinforced by the Internet Infinite Memory Effect) that they have to? |
One of the biggest differences between iODBC and unixODBC is that the former is by default UTF-32 while the latter is UTF-16 for its Unicode APIs, and likewise any ODBC drivers used with them also need to have a compatible ABI. For example, ODBC Driver for SQL Server is UTF-16 only. |
Today, iODBC supports most Unicode encodings -- UCS-2, UCS-4 (a/k/a UTF-32), UTF-8, and UTF-32 (a/k/a UCS-4). UTF-16 support is expected in Q3 2018. On macOS, native GUI ODBC interaction is only available with iODBC. Native GUI apps and ODBC drivers that want that native Mac interface -- such as Microsoft Excel, and ODBC drivers from many vendors -- are therefore linked to iODBC (and typically, but not always, to the iODBC Frameworks rather than the dylibs). It is somewhat odd that Microsoft chose to tightly couple their ODBC Driver for SQL Server for macOS to UnixODBC, given that Microsoft Excel and Microsoft Query are bound to iODBC, and that Microsoft is aware that macOS ships with iODBC, but different teams there do not always communicate well with each other. At the same time, it is worth noting that multiple ODBC driver vendors (including my own employer, OpenLink Software) offer ODBC Drivers for SQL Server that are bound to iODBC. For a more detailed Driver Manager comparison, you can check out this Gsheet. |
@v-chojas Can "ODBC Driver x for SQL Server" work with pyodbc/iODBC, perhaps by using |
@gordthompson No. The driver is UTF-16 only, and iODBC is UTF-32 by default. pyODBC settings can't change that since they only control how it interacts with the DM; the problem here is an incompatible DM-driver interface. unixODBC is chosen because it is extremely close in compatibility to Windows' DM. ODBC Driver for SQL Server itself calls back into DM for some functionality (e.g. BCP.) |
Okay, so it sounds like building macOS wheels with iODBC won't provide a "just works" solution for msodbcsql. At least not until iODBC adds UTF-16 support and macOS starts shipping those binaries as part of the base install (or perhaps pushes them out in an update to existing macOS users). For users who just want basic connectivity to SQL Server, is FreeTDS a viable option? In other words, is installing FreeTDS_ODBC with iODBC and SSL support (the latter for Azure SQL) on macOS less of a hassle than installing unixODBC to make msodbcsql happy? |
@timhaynesopenlink iodbc-config --cflags -> -I/usr/include/iodbc |
It is not really possible to build a single pyodbc that works with both:
I think the best solution might be to use different namespaces to make this decision more visible to users rather than hiding it underneath a single namespace like "pyodbc". What about this design? @gordthompson @v-chojas @TallTed The
Each subpackage works by attempting to import a different binary. For example, the
To keep things simple, on Windows we'll bundle the
On other operating systems, we simply require that you pip install "pyodbc-unixodbc" and "pyodbc-iodbc". On macOS, we'd provide binary wheels for both in addition to the source.
Note that these are global packages and don't try to install under the pyodbc package. The last time I worked with packages that did tricky things, they always caused headaches for exe builders, etc. |
Sounds reasonable to me. I hope that it won't cause too many headaches for existing users. For example, if the current "recipe" is import pyodbc
cnxn = pyodbc.connect("DSN=foo") would the new approach require import pyodbc
from pyodbc.unixodbc import connect
cnxn = connect("DSN=foo") and if so, might it be possible to do something like from pyodbc.unixodbc import connect as pyodbc.connect so that cnxn = pyodbc.connect("DSN=foo") would still work? Also, a minor suggestion: Perhaps |
For the sake of backward-compatibility, I would certainly appreciate being able to continue using: import pyodbc
cnxn = pyodbc.connect("DSN=foo") from both Windows and Linux. If I have to change the pyodbc installation process for this, fair enough, but I've got a LOT of code that calls |
@mkleehammer - The comments from @keitherskine and @gordthompson make sense; especially about using @timhaynesopenlink, @pkleef, @openlink, @OpenLinkSoftware - Please chime in. |
@mkleehammer I think we need to consider this from the perspective of the common platforms: Windows: there is only one DM (odbc32.dll), it comes with the OS, and basically all ODBC applications and drivers use it. Thus it makes no sense to distinguish between different DMs and the additional subpackaging/importing is only creating unnecessary complexity and confusion. Linux and macOS: both iODBC and unixODBC can be encountered. A quick web search suggests unixODBC is somewhat more common (~240k results for unixODBC, ~60k for iODBC. ) It thus makes sense to distinguish between the two, but at what level? Is it expected that an application (i.e. python) use drivers from both DMs at once? The fact that unixODBC has been the default DM for pyODBC on non-Windows platforms, and the desire to keep the following unchanged across them...
...suggests to me the best approach be
This benefits
It is similar to a situation with the msodbcsql driver --- version 13.x package name was just |
I suspected moving the Obviously you can do this yourself now, which I do by writing a However, I did think it could be a good place to provide some "shortcut" functions for common configurations like SQL Server on Windows, PostgreSQL using UTF-8, etc. It could also be useful to have some test functions so you can setup the initial connection string, and then have one or more functions that attempt to figure out the correct encodings for you and test things like whether numeric structures work, is SQLDescribeParam supported, etc. Today I do a lot of this under the covers and store it in the Obviously it is something we can do in addition to the Thoughts from everyone? One other thing, I'd seriously consider changing the function interface in one other way - I'd really prefer if the connection string keywords that pyodbc should not be looking at were separated from the pyodbc keywords like |
One of pyodbc's great strengths is its ability to connect to most RDBMS's out there. However, I'm guessing that most applications use just one RDBMS at any one time. Hence, it would be convenient to be able to set a "default" RDBMS when pyodbc is installed so that no extra Python code is required when creating a connection. For example, in an ideal world, it would be good to be able to install pyodbc like this:
and thus make a connection in the usual way:
If a different RDBMS is needed, they could be specified in the code, e.g.
On the question of separating pyodbc-specific parameters from odbc-specific parameters on
https://turbodbc.readthedocs.io/en/latest/pages/advanced_usage.html#advanced-usage On the one hand, I'm kind of ok with this, but then again, they're all just parameters so does it really matter if one parameter is for pyodbc and one parameter is for odbc? Those turbodbc options are essentially just another dictionary object. |
Please, no. ODBC has DSNs already for a reason. |
@timhaynesopenlink Well, if pyodbc can set the encoding based on the provided DSN, all the better, but I'm guessing that wouldn't be easy. If not, then how does pyodbc know what the target RDBMS is, in order to set the encoding correctly? If that can be figured out under the hood by pyodbc, great! Maybe an "rdbms" parameter is too clunky, but I'm guessing something is needed. |
Bonjour
and I got the same error: Erreur de segmentation
|
That looks like a bug in iODBC: https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqldrivers-function
Also, regarding the "ODBC Driver Manager Comparison" linked above --- unixODBC does support UTF-8 encoding for the ANSI API --- it is how msodbcsql can be used through it. |
Hmmm... Even if it is a bug, it would be easy to work around with a comment indicating why we did it even though the specification doesn't require it. (Otherwise I might remove it later ;) ) |
iODBC is on GitHub so I suggest it be reported there first. |
Bonjour,
if i modify by :
the code work |
Now i have this new error... phil@ubuntu-desktop:~/test-python$ python
|
Appears to be more iODBC bugs... the SQLGetData one is similar to the SQLDrivers one above: https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetdata-function
The cur.tables() one might be similar, and I wouldn't be surprised if the same is true of the other catalog functions --- and workarounds might be basically impossible, since a null means a very specific thing to those functions. https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/arguments-in-catalog-functions |
I made a 444-iodbc branch to test building separate pyodbc and pyiodbc projects but I didn't get very far.
First, does anyone now how to properly get the iODBC header files? Their macOS docs are old and I couldn't find the installer they mentioned. (Are we sure this is worth the trouble?). It builds against the unixODBC headers, but won't work since there are some different data sizes. Second, for testing (I don't want to have to pay to license something for this), is this the right driver? Thanks. Let me know what you all think of this approach. Basically it is as you all suggested: pyodbc stays the same and is either Windows or unixODBC, pyiodbc is a new project that is always iODBC and is not supported on Windows. |
@mkleehammer -- You can download the latest iODBC 3.52.12 SDK, which includes header files, Mac-native administrators (32-bit and 64-bit), test apps, Frameworks, and dylibs, here or here. We can provide a temporary license to whichever of our drivers you want to test with at no cost; just write to OpenLink Technical Support and reference this thread. For most flexible testing, we'd recommend a Lite Edition Release 7 ODBC Driver for Virtuoso, MySQL, PostgreSQL, Oracle, Sybase, or Microsoft SQL Server. These drivers are all fat binaries (currently including both 32-bit and 64-bit for Intel) with no external dependencies. (Express Edition drivers such as the one you linked to are built fat, but depend on the local Java, and have limitations due to the way Java is built for macOS. Express Edition Release 7 requires Java 8 or later, and can only be used by 64-bit ODBC apps. Express Edition Release 6 requires Java 6 or earlier, and can only be used by 32-bit ODBC apps.) |
I don't understand the code well enough to accurately relay your reported issues (1) (2). We would appreciate it if you can report those directly, optimally via github issues, but you can raise them to a public iODBC mailing list (for bugs or macOS) or confidential OpenLink Support Case(s) if you prefer. |
Build with unixODBC instead of libiodbc, see discussion in mkleehammer/pyodbc#444
Build with unixODBC instead of libiodbc, see discussion in mkleehammer/pyodbc#444 (cherry picked from commit 13c500a)
Build with unixODBC instead of libiodbc, see discussion in mkleehammer/pyodbc#444
Any further progress/info? cheers |
Anything on this? |
@afreepenguin Is there a specific reason you need to use iODBC instead of unixODBC? |
Figured out my using unixODBC I just had to link dylib file in a weird way.... |
hi,
Configuration : Ubuntu 18.04 - Python 2.7
i'm trying to compile pyodbc with iodbc.
I added to the Setup.py script:
settings['extra_compile_args'].append('-I/usr/include/iodbc')
after
settings['extra_compile_args'].append('-Wno-write-strings')
and
settings['extra_link_args'].append('-L/usr/lib/x86_64-linux-gnu/')
after
if ldflags:
settings['extra_link_args'].extend(ldflags.split())
Result of : python setup.py build
src/pyodbcmodule.cpp:1096:15: error: ‘SQL_CONVERT_GUID’ was not declared in this scope
MAKECONST(SQL_CONVERT_GUID),
^
src/pyodbcmodule.cpp:859:28: note: in definition of macro ‘MAKECONST’
#define MAKECONST(v) { #v, v }
^
src/pyodbcmodule.cpp:1096:15: note: suggested alternative: ‘SQL_CONVERT_BIT’
MAKECONST(SQL_CONVERT_GUID),
^
src/pyodbcmodule.cpp:859:28: note: in definition of macro ‘MAKECONST’
#define MAKECONST(v) { #v, v }
^
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
I put in comment the line
MAKECONST(SQL_CONVERT_GUID), into src file : pyodbcmodule.cpp
and the line
{ SQL_CONVERT_GUID, GI_UINTEGER }, into src file : connection.cpp
Compilation ok (but some warning)
Python test file : t01.py :
The two connexion string "cs" work's with iodbctest
Execution : python t01.py
Traceback (most recent call last):
File "t01.py", line 1, in
import pyodbc
ImportError: /home/phil/.local/lib/python2.7/site-packages/pyodbc.so: undefined symbol: SQLFetchScroll
symbol: SQLFetchScroll
Result of : grep -r 'SQLFetchScroll'
cursor.cpp: "Skips the next
count
records by calling SQLFetchScroll with SQL_FETCH_NEXT.\n"cursor.cpp: // SQLFetchScroll(SQL_FETCH_RELATIVE, count), but it requires scrollable cursors which are often slower. I would
cursor.cpp: ret = SQLFetchScroll(cursor->hstmt, SQL_FETCH_NEXT, 0);
cursor.cpp: return RaiseErrorFromHandle(cursor->cnxn, "SQLFetchScroll", cursor->cnxn->hdbc, cursor->hstmt);
Is it possible for you to help me ?
The text was updated successfully, but these errors were encountered: