Skip to content
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

SQLGetDiagRec is unable to return the error message on Windows #56

Open
staticlibs opened this issue Feb 3, 2025 · 1 comment · May be fixed by #62
Open

SQLGetDiagRec is unable to return the error message on Windows #56

staticlibs opened this issue Feb 3, 2025 · 1 comment · May be fixed by #62

Comments

@staticlibs
Copy link
Contributor

This problem was discovered while testing the fix to #29 (see details there in comments).

With the latest nightly the following works correctly:

print(pyodbc.connect("DSN=DuckDB;access_mode=read_only").cursor().execute("select current_setting('access_mode')").fetchone())
('read_only',)

But the following fails:

print(pyodbc.connect("DRIVER=DuckDB Driver;access_mode=read_only").cursor().execute("select current_setting('access_mode')").fetchone())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pyodbc.InterfaceError: ('IM003', '[IM003] O\x00Ɗ\x00䒀䒀핼핼Ɗ\x00ࠠ픾픾Ɗ\x00ࠐ픾픾Ɗ\x00\x02\x00Ɗ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\uffff\uffff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00㾀㾀\x00\x00蕠蕠 틨틨Ɗ\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00 (0) (SQLDriverConnect); [IM003] O\x00Ɗ\x00䒀䒀핼핼Ɗ\x00ࠠ픾픾Ɗ\x00ࠐ픾픾Ɗ\x00\x02\x00Ɗ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\uffff\uffff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00㾀㾀\x00\x00蕠蕠틨틨Ɗ\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00 (0)')
@staticlibs
Copy link
Contributor Author

The IM003 error is correct in this case, DuckDB cannot open the connection to :memory: with access_mode=read_only. It tries to report the following error message:

ODBC_DuckDB->SQLDriverConnect\nCatalog Error: Cannot launch in-memory database in read-only mode!

The problem lies in the SQLGetDiagRec function, its current impl does not follow the spec, this bit is not implemented:

If MessageText is NULL, TextLengthPtr will still return the total number of characters (excluding the null-termination character for character data) available to return in the buffer pointed to by MessageText.

Because of this the number of characters is not returned and Windows ODBC Driver manager keeps calling SQLGetDiagRec in a loop and ends up with the random memory written to the error message.

I am working on a fix.

@staticlibs staticlibs changed the title Cannot set configuration options in connection string when DRIVER name is specified SQLGetDiagRec is unable to return the error message on Windows Feb 13, 2025
staticlibs added a commit to staticlibs/duckdb-odbc that referenced this issue Feb 16, 2025
According to ODBC spec:

> If `MessageText` is `NULL`, `TextLengthPtr` will still return the
> total number of characters (excluding the null-termination character
> for character data) available to return in the buffer pointed to by
> `MessageText`.

Such length-only calls are actually used by the Windows ODBC Driver
Manager. Currently messages are returned in garbled form on Windows.

This change adds the logic to set the `TextLengthPtr` to the actual
message length when the `MessageText` is specified as `NULL`.

Note: the impl still can be improved to handle partial message reads
better (cover existing TODO there).

Testing: existing test is extended to cover this scenario.

Fixes: duckdb#56
@staticlibs staticlibs linked a pull request Feb 16, 2025 that will close this issue
staticlibs added a commit to staticlibs/duckdb-odbc that referenced this issue Feb 19, 2025
According to ODBC spec:

> If `MessageText` is `NULL`, `TextLengthPtr` will still return the
> total number of characters (excluding the null-termination character
> for character data) available to return in the buffer pointed to by
> `MessageText`.

Such length-only calls are actually used by the Windows ODBC Driver
Manager. Currently messages are returned in garbled form on Windows.

This change adds the logic to set the `TextLengthPtr` to the actual
message length when the `MessageText` is specified as `NULL`.

Note: the impl still can be improved to handle partial message reads
better (cover existing TODO there).

Testing: existing test is extended to cover this scenario.

Fixes: duckdb#56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant