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;
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;