Skip to Content.
Sympa Menu

freetds - Re: [freetds] ODBC handling of raiserror

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: "James K. Lowden" <jklowden AT freetds.org>
  • To: FreeTDS Development Group <freetds AT lists.ibiblio.org>
  • Subject: Re: [freetds] ODBC handling of raiserror
  • Date: Mon, 12 Feb 2007 08:40:12 -0500

ZIGLIO, Frediano, VF-IT wrote:
> > (Normally, any errors about a query are returned before the data, but
> > sometimes the error occurs within a row e.g. "select type,
> > type/(type-108)
> > from systypes where type > 100". After encountering such an
> > error, the
> > server stops sending rows for that query.)
> >
>
> mm... error.c test check this case. I reminds that sybase stops while
> mssql return the error and then continue with next row.

Ah, right. I remember that now.

> The
> > "what's next" states would be simplified to 1) row pending, 2) results
> > pending, or 3) nothing pending. To get "post results" data
> > (e.g. return
> > status), the client library wouldn't even examine the stream; it would
> > examine its own data structure to see if it was populated by
> > tds_nextrow.
> >
>
> So, stop at the "minimun token" (that is process how many tokens as the
> library which would process less tokens) encountered and let the library
> continue (if necessary). It sounds resonable. Mmmm... sometime I think
> that message shouldn't call a handler but returns the error.

Maximum, actually. After reading a ROW packet, see if the next token is a
ROW. If so, return control to the client library. If not, read all
remaining packets for that result, and then return control to the client
library.

We should do it this way because TDS is very messy in this area and the
client libraries have a hard time knowing where they are in the stream.
And libtds sometimes has to "skip ahead" when db-lib doesn't ask for e.g.
return status. It's easier to read everything from the stream, organize
it in memory, and let the client library examine what it cares to.

The libraries all have different API functions for reading "post result"
data (output parameters, return status, compute rows). In db-lib, they're
all handled within one call to dbresults(). In ODBC, each one needs
SQLMoreResults.

db-lib
------

dbresults -> tds_results
dbnextrow[REG] -> tds_nextrow
dbnextrow[COMP] -> (examine dbproc->tds)
dbnumrets -> (examine dbproc->tds)
dbhasretstatus -> (examine dbproc->tds)
etc.

ODBC
----
SQLExecute -> tds_results and tds_nextrow
SQLMoreResults -> examine *tds for compute rows (set flag)
examine *tds for parameters (set flag)
examine *tds for return status (set flag)
tds_results
SQLFetch -> flag set, return row
no flag, tds_nextrow

The more I think about it, the clearer it is that libtds has to stay "one
step ahead" of the client libraries. It has to read deep into the stream
-- without blocking, of course -- so that it can always answer the client
library with knowledge about what the server "is going to say".

For example, this stored proc:

create proc P @a int output
as
select @a = @a + 1
return 23

When that procedure is executed, it obviously returns a parameter and a
return status. In db-lib,

dbresults succeeds
dbnumcols returns 0
dbnextrow is never called
dbnumrets returns 1
dbhasretstatus returns true

libtds cannot assume tds_nextrow will be called. If tds_results
determines there are no regular results, it has to call tds_nextrow
itself, to collect the "post results" results. (Maybe we should call them
"regular results" [REG_ROW] and "irregular results").

--jkl




Archive powered by MHonArc 2.6.24.

Top of Page