Re: dbbind failure on unknown bindtype
Paul Thurston <[email protected]>
| Newsgroups | gmane.comp.db.tds.freetds |
|---|---|
| Message-ID | <8CE89D28262A9144A043F26236D8317C0201864516@EXVMBX020-21.exch020.serverdata.net> |
James:
I did try your suggestion, (and had that set-up earlier) with no joy.
See below for the code for dbbind(...) from dblib.c. This is from the v0.83 build of 12/25/2010.
Can you point out where the population of the (BYTE*) varaddr parameter occurs in this code?
I'm not able to locate a single spot in the code where varaddr appears (either logically or formally) in the left-hand side of an assignment.
Thanks,
Paul
________________________________
<dblib source code>
RETCODE
dbbind(DBPROCESS * dbproc, int column, int vartype, DBINT varlen, BYTE * varaddr)
{
TDSCOLUMN *colinfo = NULL;
TDSRESULTINFO* results;
int srctype = -1;
int desttype = -1;
tdsdump_log(TDS_DBG_FUNC, "dbbind(%p, %d, %d, %d, %p)\n", dbproc, column, vartype, varlen, varaddr);
CHECK_DBPROC();
DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);
CHECK_PARAMETER(varaddr, SYBEABNV, FAIL);
results = dbproc->tds_socket->res_info;
if (results == NULL || results->num_cols < column || column < 1) {
dbperror(dbproc, SYBEABNC, 0);
return FAIL;
}
if (varlen < 0) {
switch (vartype) {
case CHARBIND:
case STRINGBIND:
case NTBSTRINGBIND:
case VARYCHARBIND:
case VARYBINBIND:
/*
* No message for this error. Documentation doesn't define varlen < 0, but
* experimentation with Sybase db-lib shows it's accepted as if zero.
*/
tdsdump_log(TDS_DBG_FUNC, "dbbind: setting varlen (%d) to 0\n", varlen);
varlen = 0;
break;
}
}
if (0 == varlen) { /* "Note that if varlen is 0, no padding takes place." */
switch (vartype) {
case CHARBIND:
case STRINGBIND:
case NTBSTRINGBIND:
varlen = -1;
break;
default:
break; /* dbconvert: "The destlen is ignored for all fixed-length, non-NULL data types." */
}
}
dbproc->avail_flag = FALSE;
colinfo = dbproc->tds_socket->res_info->columns[column - 1];
srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
if (-1 == (desttype = _db_get_server_type(vartype))) {
dbperror(dbproc, SYBEBTYP, 0);
return FAIL;
}
if (! dbwillconvert(srctype, desttype)) {
dbperror(dbproc, SYBEABMT, 0);
return FAIL;
}
colinfo->column_varaddr = (char *) varaddr;
colinfo->column_bindtype = vartype;
colinfo->column_bindlen = varlen;
return SUCCEED;
} /* dbbind() */
From: [email protected] [mailto:[email protected]] On Behalf Of [email protected]
Sent: Wednesday, December 29, 2010 1:24 PM
To: FreeTDS Development Group
Subject: Re: [freetds] dbbind failure on unknown bindtype
On Tue, Dec 28, 2010 at 10:47:07PM -0800, Paul Thurston wrote:
> Here's the call sequence (on SQL Server 2008)
>
> int iColType = dbcoltype(dproc, iColumn + 1); // The value is returned
> as iColType = 56
>
> RETCODE errCode = dbbind(dbproc, iColumn + 1, iColType, iColType,
> iColSize, (BYTE*) csBuffer); //error message: Unknown bind type passed
> to DB-Library
Hi Paul,
The above code is wrong and the message correct!
The third parameter of dbbind() is
INT vartype "a description of the binding's data type"
It's one of the defined constants I referred you to in sybdb.h.
In your case, if csBuffer is a DBINT* (and thus iColSize == sizeof(DBINT)) then your vartype should be INTBIND, not SYBINT4.
I know, it's not very consistent.
dbbind() tells the library about the program's variables. db-lib learns about the server's datatypes from the server before the dbbind() call, when the metadata are sent in response to dbresults(). dbbind() tells the library the type, size, and address of the program variable into which the each columns's data are to be copied. The library then undertakes to place the server's data into the client's variables in the format prescribed by the value of the vartype parameter.
I think many people confuse client and server datatypes. We're used to living in an Intel IEEE world, with its way of representing numbers. But database servers (should) define their types in machine-independent ways.
http://msdn.microsoft.com/en-us/library/ms187745.aspx
SYBINT4 defines no bit pattern or size. It refers to a T-SQL datatype that is defined by its *characteristics*, by what values it can hold. The server is free to invent ways to store & transmit that integer as long as the type continues to behave as advertised.
INTBIND denotes a C datatype. It serves the same purpose in dbbind() as a format string of "%d" does in scanf(3). It's needed because C has no typeof() operator and no function overloading, no built-in way to pass to a function the type of a variable.
The vendors sometimes foment confusion by conflating the two. Examples:
1. The above link includes "storage" in its description of each type, inviting the reader to think of the type in phyisical terms. (It also uses the "-2^31 ... to 2^31-1" notation, which is neither mathematical, nor C, nor SQL. But who really reads that page anyway?)
2. Both vendors provide a terrible table in the dbbind() documentation implying that e.g. INTBIND "refers to" SYBINT4. It could also be used with SYBCHAR, to name just one.
3. The type parameters of dbconvert() are taken from the datatype domain, not the vartype domain, despite the fact that the destination at least must refer to a C program variable, not an abstract SQL datatype.
Power being what it is, the weeds they sow sprout faster than I can root them out!
(To its credit, btw, Microsoft's ODBC documentation does get it right: SQL_C_SLONG denotes an integer and SQLINTEGER defines one. No mention of server datatypes when discussing C datatypes. Cf. http://msdn.microsoft.com/en-us/library/ms714556(v=vs.85).aspx.)
All said, I think you'll find bsqldb and the db-lib unit tests all work as expected with your server. dbbind() is fine. I hope my little sojourn in pedantry helps clarify the issue.
--jkl
_______________________________________________
FreeTDS mailing list
[email protected]<mailto:[email protected]>
http://lists.ibiblio.org/mailman/listinfo/freetds