[freetds] errors from dblib

Frediano Ziglio freddy77 at gmail.com
Sun Apr 19 06:58:31 EDT 2009


2009/4/19 James K. Lowden <jklowden at freetds.org>:
> Frediano Ziglio wrote:
>> I got some time to compile and run our dblib tests with MS and Sybase
>> libraries.
>
> Very nice!  I assume the log contains only bad results, and the others
> work OK?
>

Yes, only errors

> It looks like we're more compatible with Sybase than Microsoft....
>
>> You can see from attached files. I got dbsqlok fixed for timeout test
>> removing these lines
>>
>>   marker = tds_peek(tds);
>
> I spent some time looking at this.  I'm not sure we can remove those rows.
>
>
> The code is deeply confused by the cancel packet.  After the CANCEL is
> sent, the server acknowledges it.  But first it sends the pending data.
> dbsqlok() sees the ROWFORMAT2 token and returns success.
>
> With Microsoft/Sybase, does dbsqlok() fail?  (I assume yes.)
>

Yes, both fails

> The error isn't tds_peek().  The error is in tds_goodread().  It should
> wait for the cancel acknowledgement, wasting any pending data.  Here's the
> stack:
>
>      tds_peek()
> calls tds_get_byte()
> calls tds_read_packet()
> calls goodread()
> calls tds_goodread()
> calls tds_send_cancel() on timeout
>        and continues to wait
>

I always though tds_get/peak/read as low level. The layer is Client
libraries <-> Token Processing <-> Reading processing. Client
libraries should IMHO never call tds_peek/tds_read and similar. Token
processing handle correctly cancellation. It's also difficult to
handle cancellation in low level cause you don't know exactly the
state of the connection. This cause usually low level reading
functions are called by token processing which perhaps readed already
a partial packet or token so you don't know if you are in a middle of
some data.

> My log ends with:
>
> [snip]
> query.c:1951:tds_send_cancel: sending cancel packet
> net.c:781:Sending packet
> 0000 06 01 00 08 00 00 00 00-                        |........|
>
> net.c:654:Received packet
> 0000 04 01 00 4f 00 00 00 00-61 23 00 00 00 01 00 09 |...O.... a#......|
> 0010 62 65 67 69 6e 74 69 6d-65 00 00 00 09 62 65 67 |begintim e....beg|
> 0020 69 6e 74 69 6d 65 10 00-00 00 0c 00 00 00 3d 00 |intime.. ......=.|
> 0030 ae 01 00 00 d1 ef 9b 00-00 20 e0 1b 01 fd 11 00 |........ . ......|
> 0040 02 00 01 00 00 00 fd 20-00 02 00 00 00 00 00    |.......  .......|
>
> dblib.c:4579:dbsqlok() exits on result token 0x61
> [pins]
>
> tds_goodread() then gets a packet: Token 0x61, TDS_ROWFMT2_TOKEN!
> Evidently, the server had it in its buffer, and when the CANCEL packet

In this case the client, we received all the packet already. But
tds_process_tokens know that client sent a cancel and correctly handle
the cancel discarding all packets :)

> arrived, it flushed the buffer and acknowledged the cancel.  The token
> sequence:
>
> 61: ROWFMT2
> 23 00 00 00: length 35 bytes
> 01 00: 1 column
> 09: label is 9 bytes
> 62 65 67 69 6e 74 69 6d 65: "begintime"
> 00: no catalog
> 00: no schema
> 00: no table
> 09: colname is 9 bytes
> 62 65 67 69 6e 74 69 6d 65: "begintime"
> 10 00 00 00: status updatable?
> 0c 00 00 00: usertype 12
> 3d: datatype 61
> 00: no locale
>
> ae: CONTROL
> 01 00: length 1 byte
> 00: no fmt data
>
> d1: ROW
> ef 9b 00 00 20 e0 1b 01: 8-byte datetime
>
> fd: DONE
> 11 00: valid count, more coming
> 02 00: TDS_TRAN_PROGRESS
> 01 00 00 00: @@rowcount = 1
>
> fd: DONE
> 20 00: acknowledgement of attention (i.e. of cancel)
> 02 00: TDS_TRAN_PROGRESS
> 00 00 00 00: no rowcount
>
> Fooey.  I've run out of time today.  I think the answer is that
> tds_goodread() should call tds_process_cancel().
>

IMHO not as explained above.

freddy77



More information about the FreeTDS mailing list