More on using FreeTDS on a server (was Re: [freetds] Server dumpscore...)

ZIGLIO, Frediano, VF-IT Frediano.Ziglio at vodafone.com
Mon Apr 19 08:06:39 EDT 2004


> 
> Here's the latest on my efforts to use FreeTDS for 
> server-side networking.
> 
> First the bad news: Microsoft's ODBC driver for SQL Server 
> still refuses
> to talk to my little server.  All I get is a generic 
> "Protocol error in
> TDS stream".  I suspect I'm failing to send some critical token in the
> login response, but it's hard to be sure with an error 
> message that vague.
> 

I don't know too... never tried.

> Now a little the good news: I can now use the tsql program to submit
> queries, and get tables back.  The tables don't look quite right --
> strings come across okay, but numbers are mangled.  But I'm definitely
> making progress.
> 
> And the real purpose of this message: Questions!
> 
> * Can anybody recommend an alternative ODBC/TDS driver for 
> Windows?  One
>   that, maybe, would give better error messages?  Or it would 
> also be okay
>   if it simply worked, I suppose.
> 

As James said ODBC compile under windows. Also you can enable logging.

> * I have a log, produced by FreeTDS, of the network traffic 
> in my failed
>   attempts to access my little SQL server via Microsoft's ODBC driver.
>   Does anybody out there have a similar dump of a *successful* login?
>   Nothing fancy, just a TDS4.2 login such as the "test connection"
>   button in the ODBC Microsoft SQL Server Setup dialog.
> 

It would be useful if you zip&mail the log..

> * What should I do about queries that don't result in tables? 
>  For example,
>   tsql sends a "set textsize 64512" request.  My server currently just
>   sends token #253 (Result Set Done).  Is that proper?
> 

Yes and not. Any query end with a DONE token however if you issue a
batch of 3 select you get 3 done, if you issue a batch with 3 "set
textsize" you get only one DONE.

> * Are there any common "gotchas" when sending numbers?  It 
> kind of looks
>   like tsql is printing the addresses of the numbers, instead of the
>   numbers themselves -- the values are all similar, but never 
> identical.
>   I don't think it's an endian thing.
> 

If similar they can't be a endian problem...

> * Can anybody spot any obvious problems with my table-sending 
> function,
>   below?  The XXXX_t names are all types; their purpose 
> should be pretty
>   obvious, except that rows are represented as an array of 
> value_t values.
>   value_t is a union of all supported data types.  For 
> strings, it is a
>   (char *) and the actual text of the string is appended to 
> each row's 
>   value_t array; that way, when the row is freed so are all 
> of its strings.
>   Column types, names, etc. are stored in the table->col 
> array.  By looking
>   at the log file, I have verified that my little SQL server is indeed
>   sending garbage for integers; this isn't a bug in tsql.
> 
> /* send a table to the client */
> void tdsprinttable(table)
> 	table_t table;	/* the table to send */
> {
> 	TDSRESULTINFO	*resinfo;/* FreeTDS library version of table */
> 	int		r, c;	/* row & column counters */
> 	int		rowsize;/* maximum row memory needed */
> 	int		offset;	/* offset of field within row */
> 
> 	/* allocate a FreeTDS table */
> 	resinfo = tds_alloc_results(table->ncols);
> 
> 	/* fill in the column info for all columns */
> 	rowsize = 0;
> 	for (c = 0; c < table->ncols; c++)
> 	{
> 		/* fill in this column's info */
> 		switch (table->col[c].type)
> 		{
> 		  case OP_STRING:
> 			resinfo->columns[c]->column_type = SYBCHAR;
> 			resinfo->columns[c]->column_size = 
> table->col[c].width;
> 			break;
> 			

you should use tds_set_column_type

> 		  case OP_INTEGER:
> 			resinfo->columns[c]->column_type = SYBINT4;
> 			resinfo->columns[c]->column_size = sizeof(long);
> 			break;
> 
> 		  case OP_NUMERIC:
> 			resinfo->columns[c]->column_type = SYBFLT8;
> 			resinfo->columns[c]->column_size = 
> sizeof(double);
> 			break;
> 
> 		  case OP_BOOLEAN:
> 			resinfo->columns[c]->column_type = SYBBIT;
> 			resinfo->columns[c]->column_size = 1;
> 			break;
> 		}
> 		strcpy(resinfo->columns[c]->column_name,
> 				textnametext(table->col[c].name));
> 		resinfo->columns[c]->column_namelen =
> 				
> strlen(resinfo->columns[c]->column_name);
> 
> 		/* for non-string data, the data offsets don't change so
> 		 * we might as well set them here.
> 		 */
> 		resinfo->columns[c]->column_offset = c * 
> sizeof(value_t);
> 
> 		/* add this column's row data size to rowmax */
> 		rowsize += resinfo->columns[c]->column_size;

see tds_add_row_column_size and tds_process_col_fmt in token.c

> 	}
> 
> 	/* start the result, and send column info */
> 	tds_send_result(tds, resinfo);
> 	tds_send_174_token(tds, table->ncols);
> 
> 	/* for each row... */
> 	for (r = 0; r < table->nrows; r++)
> 	{
> 		/* tell FreeTDS where the data is */
> 		resinfo->current_row = (unsigned char *)&table->row[r];
> 
> 		/* convert the row */
> 		for (c = 0; c < table->ncols; c++)
> 		{
> 			/* most fields' offsets don't change, but we do
> 			 * need to worry about strings.
> 			 */
> 			if (table->col[c].type == OP_STRING)
> 			{
> 				resinfo->columns[c]->column_offset =
> 					(unsigned char 
> *)table->row[r][c].string
> 						- resinfo->current_row;
> 			}
> 		}
> 
> 		/* send the row */
> 		tds_send_row(tds, resinfo);

quite strange code... if I understand you don't use our row buffer but
rewrite column_offset and current_row...

> 	}
> 	resinfo->current_row = NULL;
> 
> 	/* end the table */
> 	tds_send_253_token(tds, 16, table->nrows);
> 	tds_flush_packet(tds);
> 
> 	/* clean up */
> 	tds_free_results(resinfo);
> 	didresult = 1;
> }
> 

Why don't you join to FreeTDS group to improve our (rudimental and not
working) server ??

freddy77



More information about the FreeTDS mailing list