Skip to Content.
Sympa Menu

freetds - [freetds] SQLNumResultCols before SQLExecute

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: Dylan Kucera <djkucera AT sympatico.ca>
  • To: freetds AT lists.ibiblio.org
  • Subject: [freetds] SQLNumResultCols before SQLExecute
  • Date: Sat, 12 Mar 2011 12:50:46 -0500

The following post is unrelated to the issue I just posted with respect to
the "handle 0" problem with TDS 8.0 that I just posted.

I was hoping to get some feedback on a work-around that I created for the
limitation where FreeTDS cannot determine the answer for SQLNumResultCols
after only calling SQLPrepare. As designed, from what I understand,
SQLExecute must be called first.

I'm working with the Oracle Heterogenous Services database link capability
so I have no ability to change the approach it takes, and in some
scenarios it asks for SQLNumResultCols after only doing a SQLPrepare.

From what I've observed, I believe I can count on the structure of the
statement where this occurs to be

SELECT "c1", "c2", ..., "cn" FROM "t1" WHERE ...

So, assuming there is no reason to believe the database link has chosen
invalid columns (which it won't because it's already confirmed the column
list with sp_columns! It just seems to have obsessive compulsive
disorder!) then counting the commas before the FROM and adding one does
the trick.

I know it's not the most elegant thing in the world but after doing this I
can use my Oracle Heterogeneous Services database links just fine. For
those who generally work on the FreeTDS code, would you consider putting
something like this into the main code line for those of us wishing to use
FreeTDS in this use case? Would it really be worse than returning 0?

Perhaps at the least this helps someone else out, though I'd be open to
any cautionary tales if someone has already been down this path.

in odbc.c, 2 changes:

1) Near line 1320: redefine IRD_UPDATE as per another post I found where
someone had a similar problem:

#define IRD_UPDATE(desc, errs, exit) do { } while(0)

#if 0
#define IRD_UPDATE(desc, errs, exit) \
do { \
if (desc->type == DESC_IRD &&
((TDS_STMT*)desc->parent)->need_reprepare && \
odbc_update_ird((TDS_STMT*)desc->parent, errs) !=
SQL_SUCCESS) \
exit; \
} while(0)
#endif

2) Near line 4425: redefine SQLNumResultCols as follows:

SQLRETURN ODBC_API
SQLNumResultCols(SQLHSTMT hstmt, SQLSMALLINT FAR * pccol)
{
char *s;
char *p;
long c;

INIT_HSTMT;


tdsdump_log(TDS_DBG_FUNC, "SQLNumResultCols(%p, %p)\n",
hstmt, pccol);

/*
* 3/15/2001 bsb - DBD::ODBC calls SQLNumResultCols on non-result
* generating queries such as 'drop table'
*/
#if 0
if (stmt->row_status == NOT_IN_ROW) {
odbc_errs_add(&stmt->errs, "24000", NULL);
ODBC_RETURN(stmt, SQL_ERROR);
}
#endif
IRD_UPDATE(stmt->ird, &stmt->errs, ODBC_RETURN(stmt, SQL_ERROR));
*pccol = stmt->ird->header.sql_desc_count;


if (stmt->ird->header.sql_desc_count == 0) {
tdsdump_log(TDS_DBG_FUNC, "SQLNumResultCols(%p, %p) - Desparate measures -
parse from %s\n",
hstmt, pccol, stmt->prepared_query);
s = malloc (strlen(stmt->prepared_query) + 64);
strcpy(s, stmt->prepared_query);
strupr(s);
p = strstr(s, " FROM ");
if (p != 0) {
*p = '\0';
c = 1;
p = s;
while ((p = strchr(p+1, ',')) != 0) {
++c;
}
*pccol = c;
}
free(s);
}


tdsdump_log(TDS_DBG_FUNC, "SQLNumResultCols(%p, %p) = %d\n",
hstmt, pccol, *pccol);


ODBC_RETURN_(stmt);
}






Archive powered by MHonArc 2.6.24.

Top of Page