[freetds] Announcing (sort of) tdsparse

James K. Lowden jklowden at schemamania.org
Fri Apr 23 00:00:12 EDT 2004

I've been toying with an idea for a while that's now far enough along that
I'd like some feedback.  I'm curious if anyone else finds the idea useful,
and, if so, how.  

"tdsparse" is a little under 3000 lines of C++ that converts a TDS image
into XML.  

In English, I wrote a simple shell script and C program that converts a
typical TDSDUMP log into a bytestream: all the commentary is gone, and all
that remains are the bytes exchanged with the server, the "TDS
conversation" in binary form.  That's what I call a "stream image":

$ hexdump -C stream |head
00000000  02 00 02 00 00 00 00 00  6f 61 6b 2e 73 63 68 65 
00000010  6d 61 6d 61 6e 69 61 2e  6f 72 67 00 00 00 00 00 
00000020  00 00 00 00 00 00 13 67  75 65 73 74 00 00 00 00 
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 

tdsparse reads that file from stdin (OK, it's C++, so we'll say cin).  It
interprets each packet and writes verbose XML on cout:

$ ./tdsparse <stream |sed 's/<\     /</g; s/\       >/>/g'| head -20
<TDS Header Packet offset = 0 size = 8>
        <TDS 4.2 or 5.0 login packet offset=0 size=1>0x2</TDS 4.2 or 5.0
login packet>
        <is_final offset=1 size=1>0x0</is_final>
        <size offset=2 size=2>0x200</size>
        <unknown offset=4 size=4>0x00000000</unknown>
</TDS Header Packet>
<TDS Header Packet offset = 512 size = 8>
        <TDS 4.2 or 5.0 login packet offset=0 size=1>0x2</TDS 4.2 or 5.0
login packet>
        <is_final offset=1 size=1>0x1</is_final>
        <size offset=2 size=2>0x61</size>
        <unknown offset=4 size=4>0x00000000</unknown>
</TDS Header Packet>
<TDS 4.2 or 5.0 Login Packet offset = 0 size = 589>
        <host_name offset=0 size=30>oak.schemamania.org</host_name>
        <host_name_length offset=30 size=1>0x13</host_name_length>
        <user_name offset=31 size=30>guest</user_name>
        <user_name_length offset=61 size=1>0x5</user_name_length>

So far, it understands 12 tokens of only TDS 5.0, mostly because I didn't
want to deal with Unicode while I was trying out the idea.  It decodes a
basic 5.0 session, including the capabilities array and data rows.   

C++ makes this pretty easy, by the way.  Every TDS datatype is a
templatized class ("element") that knows how to read itself from the
stream and write itself as XML.  As the main loop identifies each token in
the stream, it instantiates a packet object based on the token whose
members are all elements or sub-packets.  The packet object i/o methods
merely invoke the methods of its members.  The bulk of the work is
identifying each packet type, constructing a class with the right members,
and writing the i/o methods.  It's repetitive, but it's not very hard at
this point.  

I started this project for a few reasons.  

1.  It would make a good debugging tool.  An independent interpretation of
the bytestream would be useful, and it would be possible to quickly
interpret logs posted on the list.   

2.  I'm interested in how XML might represent TDS.  It seems to me that in
theory one could use XML to communicate with databases.  That would be
less efficient with respect to bandwidth, but it might be quite efficient
with respect to programmers' time.  

3.  The XML output could be converted with standard tools to other forms,
and might serve as the basis for better TDS documentation.  

I wonder how this tickles your imagination, if at all, and whether or not
it should be part of the FreeTDS project.  


More information about the FreeTDS mailing list