Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected token COLMETADATA #138

Closed
billgraziano opened this issue Dec 16, 2015 · 4 comments
Closed

Unexpected token COLMETADATA #138

billgraziano opened this issue Dec 16, 2015 · 4 comments

Comments

@billgraziano
Copy link

I'm running the simple.go example. I made a change to the SQL:

set nocount on; select 1, 'abc'

I get an error back

Invalid TDS stream: Unexpected token COLMETADATA

It appears to be the SET NOCOUNT ON that's causing the problem. I've tested with

DECLARE @T INT; SELECT 1, 'abc' 

and that works fine. But

DECLARE @T INT = 37; SELECT 1, 'abc' 

returns the same error.

I've tried poking around in the source code but I'm brand new to GO and I can't track it down., Also, if I wrap the bad statement in an EXEC it works fine.

@melignus
Copy link
Contributor

I've been trying to wrap my head around this problem for a little while now.

I have a noisy query that's been doing the same thing to me, temp tables, intermediate selects, a select coalesce, etc. I threw some log statements into the tokenizer because it seems to be there that I'm blowing up. If I wrap all the preliminary 'noisy' part of the query into a tx.MustExec("query setup, variable assignment etc") and then use tx.Query("select * from #ResultTable") only on the resulting temp table it works fine.

It seems there's a token pattern with some noisy queries that closes the token channel before all of the select like data is done being parsed so when the real result at the end of the stream sends it's column data, the parser gets unexpected data.

I believe this is the offending section of the code, but I haven't looked at it long enough to figure out how to ignore initial 0xFD tokens:

go-mssqldb/token.go

Lines 386 to 403 in f6e253f

case tokenDone, tokenDoneProc:
done := parseDone(sess.buf)
if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 {
sess.log.Printf("(%d row(s) affected)\n", done.RowCount)
}
if done.Status&doneError != 0 || failed {
ch <- lastError
return
}
if done.Status&doneSrvError != 0 {
lastError.Message = "Server Error"
ch <- lastError
return
}
ch <- done
if done.Status&doneMore == 0 {
return
}

I dumped the tokens during execution and found patterns that work and patterns that break. But I don't know enough about TDS (yet anyway) to know exactly how this is breaking the parser.

Works

declare @t int; select 1, 'abc'

Parser Dump:tokenColMetadata tokenRow tokenDone

Breaks

declare @t int = 37; select 1, 'abc'

Parser Dump:tokenDone tokenColMetadata tokenRow tokenDone

It appears that some operations, in this case assignment instead of just declaration are throwing a tokenDone byte probably attached to a return value of some sort ie variable assignment ok that's throwing off the parser when it gets to the real data.

So patterns that don't work are anything that throws a a bunch of 0xFD (tokenDone) in the setup of the query:

0xFD (tokenDone, maybe sql server acknowledging a variable assignment?)
... n tokenDones
0xFD
0x81 (tokenColMetadata start of the results we want)
0xD1 (tokenRow) 
... n tokenRows
0xD1 
0xFD (tokenDone)

This pattern below seems to work in all cases, you can work around the error by cramming all the variable assignments into a single statement in a transaction and then then querying your result in a separate call.

tx := db.MustBegin()

_ := tx.MustExec("declare @t int = 37") 0xFD
rows, err := tx.Query("select 1, 'abc'") 0x81 0xD1 0xFD

As opposed to:

db.Query("declare @t int = 37; select 1, 'abc'") 0xFD 0x81 0xD1 0xFD

@dimdin
Copy link
Collaborator

dimdin commented Dec 16, 2015

Please try to remove these two lines:

go-mssqldb/mssql.go

Lines 265 to 266 in f6e253f

case doneStruct:
break loop

Sorry I cannot test this change right now.

@melignus
Copy link
Contributor

That worked for my 'noisy' query. It doesn't appear to have broken any of my other endpoints either.
Thank you!

denisenkom added a commit that referenced this issue Apr 3, 2016
@denisenkom
Copy link
Owner

Merged pull-request with a fix and added unit-test.

odeke-em pushed a commit to orijtech/go-mssqldb that referenced this issue Jul 26, 2020
gabrielcorado pushed a commit to gravitational/go-mssqldb that referenced this issue Oct 4, 2024
* Fix: Handle extended chars in SQL instance names
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants