Re: Fix for Declare/Fetch issue - Mailing list pgsql-odbc
From | Marko Ristola |
---|---|
Subject | Re: Fix for Declare/Fetch issue |
Date | |
Msg-id | 4364D392.8040503@kolumbus.fi Whole thread Raw |
In response to | Re: Fix for Declare/Fetch issue (Dave Page <dpage@vale-housing.co.uk>) |
List | pgsql-odbc |
My test case failed. I tested only column wise query. It returned the correct number of rows, but only the first cursor fetch got correct data. The self contained test case is attached: it creates a test table, inserts there six rows and fetches those rows as column wise. Please use Fetch=2 with it. Finally it drops the test table. You need to change DATABASE, USERID and PASSWORD. It worked without Declare/fetch as it should: OK(UseDeclareFetch=0): After colwise query: data[1] = { 4, 0001 }, data[2] = { 4, 1001 } After colwise query: data[1] = { 4, 2001 }, data[2] = { 4, 3001 } After colwise query: data[1] = { 4, 4001 }, data[2] = { 4, 5001 } ok. (4= number of characters. "0001" is a character string value.) FAILED (UseDeclareFetch=1,Fetch=2): After colwise query: data[1] = { 4, 0001 }, data[2] = { 4, 1001 } After colwise query: data[1] = { -1, UNSET }, data[2] = { -1, UNSET } After colwise query: data[1] = { -1, UNSET }, data[2] = { -1, UNSET } ok. -1 means possibly a NULL value(?). UNSET means that the string buffer is uninitialized after SQLFetchScroll. Unfreed memory was a problem with this failed test case. You can confirm that by setting the number of rows into 600 000 and using Fetch=2 with Declare/Fetch. The program prints "INITIALIZATION OF 600000 ROWS DONE". Then the process's used memory grows very fast. Regards, Marko Ristola. Dave Page wrote: >Great, thanks Anoop. > >Can anyone test this fairly quickly? I don't have the appropriate hardware >to hand for the next few days, and it would be helpful for a number of >reasons if we could get this committed before November. > >Thanks, Dave. > > > #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sql.h> #include <sqlext.h> #define NUMBEROF_TEST_ROWS (6) int CHECK(SQLSMALLINT handle_type,SQLHANDLE handle,SQLRETURN ret) { if (ret != SQL_SUCCESS && ret != SQL_NO_DATA) { SQLRETURN ret; SQLINTEGER i = 0; SQLCHAR state[32]; SQLINTEGER native; SQLCHAR text[512]; SQLSMALLINT text_len; int has_err = 0; do { i++; ret = SQLGetDiagRec(handle_type,handle,i,state,&native,text,sizeof(text), &text_len); fprintf(stderr,"message=%s\nstate=%s native error %d.\n",text,state,native); has_err=1; } while(ret == SQL_SUCCESS); if (!has_err) fprintf(stderr,"An unknonw error occurred\n"); } if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO || ret == SQL_NO_DATA) return 1; return 0; } // PREPARATIONS int CreateInitialData(SQLHANDLE m_env,SQLHANDLE m_conn) { int row; int nextVacuum=1024; SQLHANDLE stmt; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLSetConnectOption(m_conn,SQL_AUTOCOMMIT,0))) return 1; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLAllocHandle(SQL_HANDLE_STMT,m_conn,&stmt))) return 1; if (!CHECK(SQL_HANDLE_STMT,stmt,SQLExecDirect(stmt,(SQLCHAR*)"CREATE TABLE test_testcolwisequery (" " key1 VARCHAR(250)," " key2 VARCHAR(250)," " value1 VARCHAR(250)," " value2 VARCHAR(250)," " primary key(key1,key2))",SQL_NTS))) goto fail; for (row=0; row < NUMBEROF_TEST_ROWS; row++) { char key1[200],key2[200],value1[200]; char sqlcmd[512]; sprintf(key1,"%d000",row); sprintf(key2,"%d001",row); sprintf(value1,"%d002",row); sprintf(sqlcmd,"INSERT INTO test_testcolwisequery(key1,key2,value1) values( '%s' , '%s' , '%s' )", key1,key2,value1); if (!CHECK(SQL_HANDLE_STMT,stmt,SQLExecDirect(stmt,(SQLCHAR*)sqlcmd,SQL_NTS))) goto fail; if (row % 10000 == 0) { if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLTransact(m_env,m_conn,SQL_COMMIT))) goto fail; } if (row == nextVacuum) { if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLTransact(m_env,m_conn,SQL_COMMIT))) goto fail; if (!CHECK(SQL_HANDLE_STMT,stmt,SQLExecDirect(stmt,(SQLCHAR*)"VACUUM ANALYZE test_testcolwisequery",SQL_NTS))) goto fail; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLTransact(m_env,m_conn,SQL_COMMIT))) goto fail; nextVacuum *=2; } } if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLTransact(m_env,m_conn,SQL_COMMIT))) goto fail; SQLFreeHandle(SQL_HANDLE_STMT,stmt); if (NUMBEROF_TEST_ROWS > 100) printf("INITIALIZATION OF %d ROWS DONE.\n",NUMBEROF_TEST_ROWS); return 1; fail: SQLFreeHandle(SQL_HANDLE_STMT,stmt); return 0; } int DropTestEnv(SQLHANDLE m_env,SQLHANDLE m_conn) { SQLHANDLE stmt; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLAllocHandle(SQL_HANDLE_STMT,m_conn,&stmt))) return 1; if (!CHECK(SQL_HANDLE_STMT,stmt,SQLExecDirect(stmt,(SQLCHAR*)"DROP TABLE test_testcolwisequery",SQL_NTS))) goto fail; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLTransact(m_env,m_conn,SQL_COMMIT))) goto fail; SQLFreeHandle(SQL_HANDLE_STMT,stmt); return 1; fail: SQLFreeHandle(SQL_HANDLE_STMT,stmt); return 0; } // PREPARATIONS END #define TEXT_SIZE 300 SQLINTEGER data_len[2]; char data[2][TEXT_SIZE]; void initBufs() { data_len[0]=-123; data_len[1]=-123; strcpy(data[0],"UNSET"); strcpy(data[1],"UNSET"); } void PrintData(char *msg,SQLUINTEGER nrows) { unsigned int i; printf("%s: ",msg); for (i=0; i<nrows; i++) { if (i) printf(", "); printf("data[%d] = { %d, %s }",i+1,(int)data_len[i],data[i]); } printf("\n"); fflush(stdout); } /* You need the following definition: * CREATE TABLE test_testcolwisequery(value1 VARCHAR(100)); * * */ #define USERID "marko" #define DATABASE "marko" #define PASSWORD "marko" int main(int argc, char **argv) { SQLHANDLE m_env; SQLHANDLE m_conn; SQLHANDLE m_stmt; SQLUINTEGER fetchedRows; SQLINTEGER statuses[2]; SQLRETURN rc; if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&m_env)) { fprintf(stderr,"Allocating ENV handle failed.\n"); return 1; } if (!CHECK(SQL_HANDLE_ENV,m_env,SQLSetEnvAttr(m_env, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3,0))) return 1; if (!CHECK(SQL_HANDLE_ENV,m_env,SQLAllocHandle(SQL_HANDLE_DBC,m_env,&m_conn))) return 1; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLConnect(m_conn,(SQLCHAR*) DATABASE, SQL_NTS,(SQLCHAR*) USERID,SQL_NTS,(SQLCHAR*) PASSWORD,SQL_NTS))) return 1; if (!CreateInitialData(m_env,m_conn)) return 1; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLAllocHandle(SQL_HANDLE_STMT,m_conn,&m_stmt))) return 1; if (!CHECK(SQL_HANDLE_STMT,m_stmt,SQLSetStmtAttr(m_stmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN,0))) return 1; if (!CHECK(SQL_HANDLE_STMT,m_stmt,SQLSetStmtAttr(m_stmt, SQL_ATTR_ROW_ARRAY_SIZE, (void*)2,0))) return 1; if (!CHECK(SQL_HANDLE_STMT,m_stmt,SQLSetStmtAttr(m_stmt, SQL_ATTR_ROW_STATUS_PTR, statuses,0))) return 1; if (!CHECK(SQL_HANDLE_STMT,m_stmt,SQLSetStmtAttr(m_stmt, SQL_ATTR_ROWS_FETCHED_PTR, &fetchedRows,0))) return 1; if (!CHECK(SQL_HANDLE_STMT,m_stmt,SQLBindCol(m_stmt,1, // Column number SQL_C_CHAR, // C data type &data[0], // parameter value ptr TEXT_SIZE, // buffer length (SQLINTEGER*)&data_len[0]))) // string length ptr return 1; if (!CHECK(SQL_HANDLE_STMT,m_stmt,SQLExecDirect(m_stmt,(SQLCHAR*) "SELECT key2 FROM test_testcolwisequery", SQL_NTS))) return 1; initBufs(); while ( (rc = SQLFetchScroll(m_stmt,SQL_FETCH_NEXT, 0)) != SQL_NO_DATA) { PrintData("After colwise query",fetchedRows); initBufs(); } if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLFreeStmt(m_stmt,SQL_CLOSE))) return 1; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLTransact(m_env,m_conn,SQL_COMMIT))) return 1; // if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLTransact(m_env,m_conn,SQL_ROLLBACK))) // return 1; if (!DropTestEnv(m_env,m_conn)) return 1; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLTransact(m_env,m_conn,SQL_COMMIT))) return 1; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLFreeStmt(m_stmt,SQL_DROP))) return 1; if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLDisconnect(m_conn))) return 1; if (!CHECK(SQL_HANDLE_ENV,m_env,SQLFreeConnect(m_conn))) return 1; if (SQL_SUCCESS != SQLFreeEnv(m_env)) { fprintf(stderr,"Connect env freeing failed\n"); return 1; } fprintf(stderr,"ok.\n"); return 0; }
pgsql-odbc by date: