Conversation
DATENTYPE carries neither length nor scale in TYPE_INFO — it is a fixed 3-byte value — but the encoder grouped it with TIMENTYPE, DATETIME2NTYPE and DATETIMEOFFSETNTYPE, which do carry a 1-byte scale. The decoder in the same file already implements the correct rule (`VarLenType::Daten => 3`, with no `read_u8`). Every DATE column therefore added one spurious byte to the bulk COLMETADATA. The server read the remaining column metadata shifted by one byte and rejected the load with "Invalid column type from bcp client for colid N+1", blaming the column after the date (tiberius-rs#410, tiberius-rs#373). The new test encodes a sequence, which is what COLMETADATA is: a single round trip cannot catch this, because the stray byte still decodes back to the same value and only the next column goes wrong.
|
Thanks @nandoxlsm — your diagnosis lines up with ours. The same fix looks to already be in #443 (in review): Closing as a duplicate of #443 — but thank you for the independent, clear write-up. Following up on #373/#410 there. |
|
Thanks @MattJackson — checked #443 and you're right, it's the same fix with the same reasoning (and your comment documents the spec sections better than mine did). Happy to defer to it. One practical note, in case it's useful: #443 targets Either way: we hit this against a live Azure SQL with a 47-column table ( |
|
I agree, we have a large backlog and its is moving just slowly due the amount of fixes it all contains. Ill speak with @aqrln and others to see if we should just steam ahead on the stack or if we should be picking a few off into small commits. Im hoping that the stack will proceed, but its about 1 a week right now so not the pace we want or need it to be. |
|
@MattJackson yeah this is not sustainable, I don't have as much capacity as I hoped for to properly review this. If you already reviewed this code before, I think we should just go ahead and merge it. We need to ship the new release to resolve the security issues. Let me know if there's anything in particular I should pay closer attention to or that you haven't reviewed yourself before, but otherwise feel free to merge. |
|
Agreed. I have merged the stack and closed out the issues. Ill review remaining issues and PRs to see whats really open but we should be at a much cleaner state now. Please push a new crate when available, didn't see that as part of any CI @aqrln |
|
@MattJackson ah here's where this thread was, I was struggling to find it, it wasn't showing up in the search results somehow. Only just now seeing your response here. I published the crates and opened this issue today: #454 We should connect on Discord or something so it's easier to coordinate. Maybe even create a Discord server for the community. |
|
Agreed. for now email me (on my profile) and lets connect. Discord sounds good long term, ill add it to list :) |
Fixes the root cause behind #410 and #373: a
DATEcolumn makes a bulk load fail withInvalid column type from bcp client for colid <N+1>(error 4816), always blaming the column after the date.The bug
Encode for VarLenContextwrites a length byte forVarLenType::Daten:The decoder in the same file already implements the correct rule:
Per MS-TDS,
TIMENTYPE,DATETIME2NTYPEandDATETIMEOFFSETNTYPEcarry a 1-byte SCALE in TYPE_INFO;DATENTYPEcarries nothing — it is a fixed 3-byte value. So everyDATEcolumn adds one spurious byte to the bulk COLMETADATA, the server reads everything after it shifted by one byte, and the load is rejected naming the next column.The test
The existing
round_triptest cannot catch this: with a single type info, the stray byte is simply left in the buffer and the value still decodes back equal. COLMETADATA is a sequence, so the new test encodes aDATEfollowed by another column and decodes both — which fails onmainand passes with the fix:cargo test --features "tds73 tokio" --lib→ 213 passed, 0 failed.cargo fmtclean.How it was found
Bulk-loading a 47-column table into Azure SQL where column 4 was
DATE: the server reportedcolid 5. The same table with every column asNVARCHAR(MAX)loaded 313,465 rows without a problem, and changing only that one column toDATETIME2made the typed load succeed — which is what pointed at the metadata rather than the values.