Description:
SQLGetInfo does report an incomplete set of cursor properties.
I tested the static cursor, but while browsing the sourcecode I saw that this is a general problem. SQLGetInfo does not return any of the concurrency flags (read-only / updatable) for the cursors attributes.
//this is just an example, using a static cursor for the test:
SQLGetInfo(hdbc, SQL_STATIC_CURSOR_ATTRIBUTES2, &res, sizeof(res), &t)
does never return the following flags in "res":
SQL_CA2_READ_ONLY_CONCURRENCY
SQL_CA2_LOCK_CONCURRENCY
SQL_CA2_OPT_ROWVER_CONCURRENCY
SQL_CA2_OPT_VALUES_CONCURRENCY
Even if I try to use a dynamic cursor, the concurrency flags are still not set (even though they are "supported" !?). It's perfectly possible that other flags are missed too. I can only use a forward only cursor with read-only concurrency.
I am attaching a c++ sourcecode to test the behavior and a SAMPLE patch for the driver/info.c sourcefile to fix the read-only concurrency flag for a static cursor (note that other flags might also be missing!!)
Thanks, Chris
How to repeat:
//
//myodbctest.cpp
//
//compile with: g++ -lmyodbc3 myodbctest.cpp -o myodbctest
//
//tested on myodbc version 3.51.12
#include "sql.h"
#include "sqlext.h"
#include "sqltypes.h"
#include "sqlucode.h"
#include <iostream>
#define CHECK_RES(res) \
if (res != SQL_SUCCESS) \
{ \
std::cout << "Error at " << __LINE__ << __FILE__ << std::endl; \
exit(1); \
}
/*
* simple tests for a db connection using myodbc driver (odbc over mysql)
*
* we're interested in a scrollable cursor (no matter what concurrency it supports)....but does it support some??
*/
int main()
{
SQLHENV henv;
SQLHDBC hdbc;
//open the test connection
SQLRETURN r = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);
CHECK_RES(r);
r = SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3,0);
CHECK_RES(r);
r = SQLAllocHandle(SQL_HANDLE_DBC,henv, &hdbc);
CHECK_RES(r);
SQLCHAR * dsn = (SQLCHAR*) "someDSN";
SQLCHAR * uid = (SQLCHAR*) "someUSER";
SQLCHAR * pwd = (SQLCHAR*) "somePASSWORD";
r = SQLConnect(hdbc, dsn, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
CHECK_RES(r);
//check some connection attributes
SQLCHAR dbms[30];
r = SQLGetInfo(hdbc, SQL_DBMS_NAME, &dbms, 40, NULL);
std::cout << "DBMS: " << dbms << std::endl;
//check if static cursor supports read-only concurrency
SQLRETURN res1 = 0;
SQLSMALLINT t;
r = SQLGetInfo(hdbc, SQL_STATIC_CURSOR_ATTRIBUTES2, &res1, sizeof(res1), &t); //static cursor options
CHECK_RES(r);
std::cout << "Supports static2 - read only: " << (res1 & SQL_CA2_READ_ONLY_CONCURRENCY) << std::endl;
//check if static cursor supports updatable concurrency
SQLRETURN res2 = 0;
bool updatable = false;
r = SQLGetInfo(hdbc, SQL_STATIC_CURSOR_ATTRIBUTES2, &res2, sizeof(res2), &t); //static cursor options
CHECK_RES(r);
std::cout << "Supports static2 - lock: " << (res2 & SQL_CA2_LOCK_CONCURRENCY) << std::endl;
updatable |= (res2 & SQL_CA2_LOCK_CONCURRENCY);
r = SQLGetInfo(hdbc, SQL_STATIC_CURSOR_ATTRIBUTES2, &res2, sizeof(res2), &t); //static cursor options
CHECK_RES(r);
std::cout << "Supports static2 - rowver: " << (res2 & SQL_CA2_OPT_ROWVER_CONCURRENCY) << std::endl;
updatable |= (res2 & SQL_CA2_OPT_ROWVER_CONCURRENCY);
r = SQLGetInfo(hdbc, SQL_STATIC_CURSOR_ATTRIBUTES2, &res2, sizeof(res2), &t); //static cursor options
CHECK_RES(r);
std::cout << "Supports static2 - values: " << (res2 & SQL_CA2_OPT_VALUES_CONCURRENCY) << std::endl;
updatable |= (res2 & SQL_CA2_OPT_VALUES_CONCURRENCY);
std::cout << "Supports static2 - updatable: " << updatable << std::endl;
//close connection
r = SQLDisconnect(hdbc);
CHECK_RES(r);
r = SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
CHECK_RES(r);
r = SQLFreeHandle(SQL_HANDLE_ENV, henv);
CHECK_RES(r);
return 0;
}
Suggested fix:
--- info.c 2005-10-09 22:33:40.000000000 +0300
+++ info.c 2008-01-02 22:21:47.000000000 +0200
@@ -447,6 +447,7 @@
SQL_CA2_MAX_ROWS_INSERT |
SQL_CA2_MAX_ROWS_DELETE |
SQL_CA2_MAX_ROWS_UPDATE |
+ SQL_CA2_READ_ONLY_CONCURRENCY | /* fill concurrency info too !? */
SQL_CA2_CRC_EXACT);
*pcbInfoValue= sizeof(SQLUINTEGER);
break;