Skip to content

Conversation

staticlibs
Copy link
Collaborator

@staticlibs staticlibs commented Sep 28, 2025

This PR fixes the SQLNumResultCols function making it to return the actual number of columns for CALL, EXECUTE and EXPLAIN queries. Without that some ODBC clients were unable to fetch the result set for
such queries.

EXPLAIN output contains 1 row with 2 columns. First column is a constant physical_plan (or logical_plan) and the second column contains actual plan details as a VARCHAR.

Testing: new test added.

Fixes: #200

edit: description and name updated with additional query types.

@bucweat
Copy link
Contributor

bucweat commented Oct 2, 2025

After seeing and testing this fix, I wondered if output from other statement types was not getting output via ODBC. I believe I found at least one:

PRAGMA table_info('table_name');
CALL pragma_table_info('table_name');

PRAGMA table_info() works just fine even though StatementType::PRAGMA_STATEMENT is not in the switch statement...not sure why. CALL pragma_table_info() does not output anything via ODBC.

Another example is EXECUTE. Using the example from here, the EXECUTE statement does not output anything via ODBC.

I added case duckdb::StatementType::CALL_STATEMENT: and StatementType::EXECUTE_STATEMENT: to the switch statement in this pull request and rebuilt the ODBC driver:

	switch (hstmt->stmt->data->statement_type) {
        case duckdb::StatementType::SELECT_STATEMENT:
        case duckdb::StatementType::EXPLAIN_STATEMENT:
        case duckdb::StatementType::CALL_STATEMENT:
        case duckdb::StatementType::EXECUTE_STATEMENT:

            break;
        default:
            *column_count_ptr = 0;
	}

And now the CALL statement output via ODBC works. From my test C# program:

True query --> CALL pragma_table_info('test');
RESULT:cid,name,type,notnull,dflt_value,pk
RESULT:0,a,INTEGER,false,null,false
RESULT:1,b,INTEGER,false,null,false

which is the same as PRAGMA table_info():

True query --> PRAGMA table_info('test');
RESULT:cid,name,type,notnull,dflt_value,pk
RESULT:0,a,INTEGER,false,null,false
RESULT:1,b,INTEGER,false,null,false

EXECUTE query_person(40, 'B'); also outputs the correct result via ODBC:

True query --> EXECUTE query_person('B', 40);
RESULT:name,age
RESULT:Bob,41

BTW I found the available StatementTypes in this list. I have not gone through the complete list, so there may be more...

@staticlibs
Copy link
Collaborator Author

@bucweat

I think these examples are kind of corner cases:

  1. PRAGMA use is discouraged
  2. CALL <table_fun> can be written as SELECT * FROM <table_fun>
  3. SQLPrepare and SQLExecute is likely to be used with ODBC instead of SQL-level PREPARE + EXECUTE

Though it won't harm to support at least some of them too, going to extend the PR a bit.

@staticlibs staticlibs changed the title Fix SQLNumResultCols for EXPLAIN queries Fix SQLNumResultCols for CALL, EXECUTE and EXPLAIN Oct 3, 2025
This PR fixes the `SQLNumResultCols` function making it to return the
actual number of columns for `CALL`, `EXECUTE` and `EXPLAIN` queries.
Without that some ODBC clients were unable to fetch the result set for
such queries.

`EXPLAIN` output contains 1 row with 2 columns. First column is a
constant `physical_plan` (or `logical_plan`) and the second column
contains actual plan details as a `VARCHAR`.

Testing: new test added.

Fixes: duckdb#200
staticlibs added a commit to staticlibs/duckdb-odbc that referenced this pull request Oct 3, 2025
This is a backport of the PR duckdb#241 to `v1.4-andium` stable branch.

This PR fixes the `SQLNumResultCols` function making it to return the
actual number of columns for `CALL`, `EXECUTE` and `EXPLAIN` queries.
Without that some ODBC clients were unable to fetch the result set for
such queries.

`EXPLAIN` output contains 1 row with 2 columns. First column is a
constant `physical_plan` (or `logical_plan`) and the second column
contains actual plan details as a `VARCHAR`.

Testing: new test added.

Fixes: duckdb#200
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 this pull request may close these issues.

No output when using EXPLAIN via ODBC
2 participants