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:

Previous
From: Alex Jiang
Date:
Subject: TQuery not showing new columns
Next
From: lothar.behrens@lollisoft.de
Date:
Subject: Buffer overrun in copy_statement_with_parameters ?