microsoft / ODBC-Specification

Microsoft ODBC Specification
Other
121 stars 40 forks source link

SQLBindCol description & SQL_DATA_AT_FETCH #98

Open matthew-wozniczka opened 7 years ago

matthew-wozniczka commented 7 years ago

The current description of SQLBindCol on MSDN talks about the valid values for StrLen_or_IndPtr, and says that SQLFetch/SQLFetchScroll return values into that buffer, but for the SQL_DATA_AT_FETCH case it will be using it for input, so that description will need to be changed.

matthew-wozniczka commented 7 years ago

On that note, would it be possible to increase the scope of this repo to include the 'rest' of the spec?

matthew-wozniczka commented 7 years ago

If TargetValuePtr is a null pointer, the driver unbinds the data buffer for the column

How does this interact with SQL_DATA_AT_FETCH? Should a non-null (dummy) pointer be provided here? Does a column 'bound' as SQL_DATA_AT_FETCH count as bound for the purposes of SQL_DESC_COUNT? Seems like no, does that cause problems?

mikepizzo commented 7 years ago

Proposal: 1) If DynamicColumns is true, client must ensure that str_len_or_indicator_ptr is initialized to SQL_DATA_AT_FETCH or SQL_DATA_UNAVAILABLE. 2) If DynamicColumns is false, the driver must ensure that str_len_or_indicator_ptr is set for every bound column described by the IRD (same rules as today in 3.x) 3) Driver/DM should never write SQL_DATA_UNAVAILABLE (they just leave the buffer unchanged).

mikepizzo commented 7 years ago

Alternatively, we could say that client sets the value referenced by str_len_or_indicator_ptr to any value other than SQL_DATA_AT_FETCH (typically SQL_DATA_UNAVAILABLE for the first fetch) and that the driver sets the value of unused bound columns (not those marked as SQL_DATA_AT_FETCH) to SQL_DATA_UNAVAILABLE. That would allow the client not to have to reset the status between each call to SQLFetch/SQLFetchScroll.

matthew-wozniczka commented 7 years ago

"If DynamicColumns is true" == SQL_ATTR_DYNAMIC_COLUMNS is true?

IIRC SQL_DATA_AT_FETCH is still supported even when dynamic columns are turned off, right? Will it only be supported when the ODBC version is set to 4+? Otherwise it could still break applications.

mikepizzo commented 7 years ago

No; you're right. SQL_DATA_AT_FETCH is supported even when dynamic columns is turned off; the driver just doesn't need to set DATA_UNAVAILABLE in those cases.

SO I think what we're left with is that the 4.0 application must initialize the buffer to some value other than SQL_DATA_AT_FETCH. Typically this will be the value from the previous fetch, and applications can initialize it to SQL_DATA_UNAVAILABLE.

matthew-wozniczka commented 7 years ago

Sorry, just want to be clear on this, is SQL_DATA_AT_FETCH only supported when SQL_ATTR_ODBC_VERSION is set to 4 (or 'greater', 380 notwithstanding)?

mikepizzo commented 7 years ago

Correct.

mikepizzo commented 7 years ago

We could add a (statement?) option that the application set to enable data_at_fetch (SQL_STMT_ATTR_ENABLE_FETCH_I_PROMISE_TO_INITIALIZE_MY_STR_LEN_OR_IND_PTRS), but that would basically have the same effect as setting the version to 4.0 so might not be worth it...

matthew-wozniczka commented 7 years ago

Not sure if it belongs in this issue, but another issue I have with the current definition of SQL_DATA_AT_FETCH is that it modifies the behavior of bindings on a per-row basis (we had that for streamed input/output parameters already, but not for column bindings AFAIK).

What I mean is that the driver actually has to look at the value for each cell, and check it against SQL_DATA_AT_FETCH, whereas before it could do a little bit of setup per-binding, and then 'blit' that column across the rowset with very tight code that didn't have to do many checks. (you could check as a pre-processing step, but then you slow down all fetches, even if they would have only fetched a couple (or no) rows)

IMO it would be better if you had to specify it per-column, as opposed to per-cell. (Just off the top of my head, a new descriptor field, something like SQL_DESC_BIND_TYPE which defaults to the current behaviour, and you could set it to SQL_DATA_AT_FETCH, which makes it ignore the data ptr and interrupt fetches instead). Would avoid some of the issues raised as well, since we're no longer re-purposing the length indicator.

mikepizzo commented 7 years ago

Agree that having a descriptor field for data-at-fetch addresses a lot of issues with overloading str_len_or_ind_ptr as an input/output field. This means that the application will have to set this outside of calling SQLBindCol, but that's probably fine.

There is already a SQL_DESC_BIND_TYPE used for row-wise/column-wise binding.

Proposal: 1) Add a new SQL_DESC_DATA_AT_FETCH descriptor field, used for ARDs, whose SQLSMALLINT value is SQL_FALSE (the default) or SQL_TRUE (for retrieving the data at fetch).

2) Setting SQL_DESC_DATA_PTR to a non-null value (directly, or through SQLBindCol) sets SQL_DESC_DATA_AT_FETCH to false for the column.

3) Setting SQL_DESC_DATA_AT_FETCH to SQL_TRUE clears any binding for the column by setting SQL_DESC_DATA_PTR to null.

4) SQL_DESC_DATA_AT_FETCH can be changed during an interrupted fetch if rowsetsize =1, and applies to the next SQLFetch/SQLFetchScroll.

mikepizzo commented 7 years ago

Applied.

mikepizzo commented 7 years ago

Need to add to headers: SQL_DESC_DATA_AT_FETCH.