tds_protocol/
token.rs

1//! TDS token stream definitions.
2//!
3//! Tokens are the fundamental units of TDS response data. The server sends
4//! a stream of tokens that describe metadata, rows, errors, and other information.
5//!
6//! ## Token Structure
7//!
8//! Each token begins with a 1-byte token type identifier, followed by
9//! token-specific data. Some tokens have fixed lengths, while others
10//! have length prefixes.
11//!
12//! ## Usage
13//!
14//! ```rust,ignore
15//! use tds_protocol::token::{Token, TokenParser};
16//! use bytes::Bytes;
17//!
18//! let data: Bytes = /* received from server */;
19//! let mut parser = TokenParser::new(data);
20//!
21//! while let Some(token) = parser.next_token()? {
22//!     match token {
23//!         Token::Done(done) => println!("Rows affected: {}", done.row_count),
24//!         Token::Error(err) => eprintln!("Error {}: {}", err.number, err.message),
25//!         _ => {}
26//!     }
27//! }
28//! ```
29
30use bytes::{Buf, BufMut, Bytes};
31
32use crate::codec::{read_b_varchar, read_us_varchar};
33use crate::error::ProtocolError;
34use crate::types::TypeId;
35
36/// Token type identifier.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38#[repr(u8)]
39pub enum TokenType {
40    /// Column metadata (COLMETADATA).
41    ColMetaData = 0x81,
42    /// Error message (ERROR).
43    Error = 0xAA,
44    /// Informational message (INFO).
45    Info = 0xAB,
46    /// Login acknowledgment (LOGINACK).
47    LoginAck = 0xAD,
48    /// Row data (ROW).
49    Row = 0xD1,
50    /// Null bitmap compressed row (NBCROW).
51    NbcRow = 0xD2,
52    /// Environment change (ENVCHANGE).
53    EnvChange = 0xE3,
54    /// SSPI authentication (SSPI).
55    Sspi = 0xED,
56    /// Done (DONE).
57    Done = 0xFD,
58    /// Done in procedure (DONEINPROC).
59    DoneInProc = 0xFF,
60    /// Done procedure (DONEPROC).
61    DoneProc = 0xFE,
62    /// Return status (RETURNSTATUS).
63    ReturnStatus = 0x79,
64    /// Return value (RETURNVALUE).
65    ReturnValue = 0xAC,
66    /// Order (ORDER).
67    Order = 0xA9,
68    /// Feature extension acknowledgment (FEATUREEXTACK).
69    FeatureExtAck = 0xAE,
70    /// Session state (SESSIONSTATE).
71    SessionState = 0xE4,
72    /// Federated authentication info (FEDAUTHINFO).
73    FedAuthInfo = 0xEE,
74    /// Column info (COLINFO).
75    ColInfo = 0xA5,
76    /// Table name (TABNAME).
77    TabName = 0xA4,
78    /// Offset (OFFSET).
79    Offset = 0x78,
80}
81
82impl TokenType {
83    /// Create a token type from a raw byte.
84    pub fn from_u8(value: u8) -> Option<Self> {
85        match value {
86            0x81 => Some(Self::ColMetaData),
87            0xAA => Some(Self::Error),
88            0xAB => Some(Self::Info),
89            0xAD => Some(Self::LoginAck),
90            0xD1 => Some(Self::Row),
91            0xD2 => Some(Self::NbcRow),
92            0xE3 => Some(Self::EnvChange),
93            0xED => Some(Self::Sspi),
94            0xFD => Some(Self::Done),
95            0xFF => Some(Self::DoneInProc),
96            0xFE => Some(Self::DoneProc),
97            0x79 => Some(Self::ReturnStatus),
98            0xAC => Some(Self::ReturnValue),
99            0xA9 => Some(Self::Order),
100            0xAE => Some(Self::FeatureExtAck),
101            0xE4 => Some(Self::SessionState),
102            0xEE => Some(Self::FedAuthInfo),
103            0xA5 => Some(Self::ColInfo),
104            0xA4 => Some(Self::TabName),
105            0x78 => Some(Self::Offset),
106            _ => None,
107        }
108    }
109}
110
111/// Parsed TDS token.
112///
113/// This enum represents all possible tokens that can be received from SQL Server.
114/// Each variant contains the parsed token data.
115#[derive(Debug, Clone)]
116pub enum Token {
117    /// Column metadata describing result set structure.
118    ColMetaData(ColMetaData),
119    /// Row data.
120    Row(RawRow),
121    /// Null bitmap compressed row.
122    NbcRow(NbcRow),
123    /// Completion of a SQL statement.
124    Done(Done),
125    /// Completion of a stored procedure.
126    DoneProc(DoneProc),
127    /// Completion within a stored procedure.
128    DoneInProc(DoneInProc),
129    /// Return status from stored procedure.
130    ReturnStatus(i32),
131    /// Return value from stored procedure.
132    ReturnValue(ReturnValue),
133    /// Error message from server.
134    Error(ServerError),
135    /// Informational message from server.
136    Info(ServerInfo),
137    /// Login acknowledgment.
138    LoginAck(LoginAck),
139    /// Environment change notification.
140    EnvChange(EnvChange),
141    /// Column ordering information.
142    Order(Order),
143    /// Feature extension acknowledgment.
144    FeatureExtAck(FeatureExtAck),
145    /// SSPI authentication data.
146    Sspi(SspiToken),
147    /// Session state information.
148    SessionState(SessionState),
149    /// Federated authentication info.
150    FedAuthInfo(FedAuthInfo),
151}
152
153/// Column metadata token.
154#[derive(Debug, Clone, Default)]
155pub struct ColMetaData {
156    /// Column definitions.
157    pub columns: Vec<ColumnData>,
158}
159
160/// Column definition within metadata.
161#[derive(Debug, Clone)]
162pub struct ColumnData {
163    /// Column name.
164    pub name: String,
165    /// Column data type ID.
166    pub type_id: TypeId,
167    /// Column data type raw byte (for unknown types).
168    pub col_type: u8,
169    /// Column flags.
170    pub flags: u16,
171    /// User type ID.
172    pub user_type: u32,
173    /// Type-specific metadata.
174    pub type_info: TypeInfo,
175}
176
177/// Type-specific metadata.
178#[derive(Debug, Clone, Default)]
179pub struct TypeInfo {
180    /// Maximum length for variable-length types.
181    pub max_length: Option<u32>,
182    /// Precision for numeric types.
183    pub precision: Option<u8>,
184    /// Scale for numeric types.
185    pub scale: Option<u8>,
186    /// Collation for string types.
187    pub collation: Option<Collation>,
188}
189
190/// SQL Server collation.
191#[derive(Debug, Clone, Copy, Default)]
192pub struct Collation {
193    /// Locale ID.
194    pub lcid: u32,
195    /// Sort ID.
196    pub sort_id: u8,
197}
198
199/// Raw row data (not yet decoded).
200#[derive(Debug, Clone)]
201pub struct RawRow {
202    /// Raw column values.
203    pub data: bytes::Bytes,
204}
205
206/// Null bitmap compressed row.
207#[derive(Debug, Clone)]
208pub struct NbcRow {
209    /// Null bitmap.
210    pub null_bitmap: Vec<u8>,
211    /// Raw non-null column values.
212    pub data: bytes::Bytes,
213}
214
215/// Done token indicating statement completion.
216#[derive(Debug, Clone, Copy)]
217pub struct Done {
218    /// Status flags.
219    pub status: DoneStatus,
220    /// Current command.
221    pub cur_cmd: u16,
222    /// Row count (if applicable).
223    pub row_count: u64,
224}
225
226/// Done status flags.
227#[derive(Debug, Clone, Copy, Default)]
228pub struct DoneStatus {
229    /// More results follow.
230    pub more: bool,
231    /// Error occurred.
232    pub error: bool,
233    /// Transaction in progress.
234    pub in_xact: bool,
235    /// Row count is valid.
236    pub count: bool,
237    /// Attention acknowledgment.
238    pub attn: bool,
239    /// Server error caused statement termination.
240    pub srverror: bool,
241}
242
243/// Done in procedure token.
244#[derive(Debug, Clone, Copy)]
245pub struct DoneInProc {
246    /// Status flags.
247    pub status: DoneStatus,
248    /// Current command.
249    pub cur_cmd: u16,
250    /// Row count.
251    pub row_count: u64,
252}
253
254/// Done procedure token.
255#[derive(Debug, Clone, Copy)]
256pub struct DoneProc {
257    /// Status flags.
258    pub status: DoneStatus,
259    /// Current command.
260    pub cur_cmd: u16,
261    /// Row count.
262    pub row_count: u64,
263}
264
265/// Return value from stored procedure.
266#[derive(Debug, Clone)]
267pub struct ReturnValue {
268    /// Parameter ordinal.
269    pub param_ordinal: u16,
270    /// Parameter name.
271    pub param_name: String,
272    /// Status flags.
273    pub status: u8,
274    /// User type.
275    pub user_type: u32,
276    /// Type flags.
277    pub flags: u16,
278    /// Type info.
279    pub type_info: TypeInfo,
280    /// Value data.
281    pub value: bytes::Bytes,
282}
283
284/// Server error message.
285#[derive(Debug, Clone)]
286pub struct ServerError {
287    /// Error number.
288    pub number: i32,
289    /// Error state.
290    pub state: u8,
291    /// Error severity class.
292    pub class: u8,
293    /// Error message text.
294    pub message: String,
295    /// Server name.
296    pub server: String,
297    /// Procedure name.
298    pub procedure: String,
299    /// Line number.
300    pub line: i32,
301}
302
303/// Server informational message.
304#[derive(Debug, Clone)]
305pub struct ServerInfo {
306    /// Info number.
307    pub number: i32,
308    /// Info state.
309    pub state: u8,
310    /// Info class (severity).
311    pub class: u8,
312    /// Info message text.
313    pub message: String,
314    /// Server name.
315    pub server: String,
316    /// Procedure name.
317    pub procedure: String,
318    /// Line number.
319    pub line: i32,
320}
321
322/// Login acknowledgment token.
323#[derive(Debug, Clone)]
324pub struct LoginAck {
325    /// Interface type.
326    pub interface: u8,
327    /// TDS version.
328    pub tds_version: u32,
329    /// Program name.
330    pub prog_name: String,
331    /// Program version.
332    pub prog_version: u32,
333}
334
335/// Environment change token.
336#[derive(Debug, Clone)]
337pub struct EnvChange {
338    /// Type of environment change.
339    pub env_type: EnvChangeType,
340    /// New value.
341    pub new_value: EnvChangeValue,
342    /// Old value.
343    pub old_value: EnvChangeValue,
344}
345
346/// Environment change type.
347#[derive(Debug, Clone, Copy, PartialEq, Eq)]
348#[repr(u8)]
349pub enum EnvChangeType {
350    /// Database changed.
351    Database = 1,
352    /// Language changed.
353    Language = 2,
354    /// Character set changed.
355    CharacterSet = 3,
356    /// Packet size changed.
357    PacketSize = 4,
358    /// Unicode data sorting locale ID.
359    UnicodeSortingLocalId = 5,
360    /// Unicode comparison flags.
361    UnicodeComparisonFlags = 6,
362    /// SQL collation.
363    SqlCollation = 7,
364    /// Begin transaction.
365    BeginTransaction = 8,
366    /// Commit transaction.
367    CommitTransaction = 9,
368    /// Rollback transaction.
369    RollbackTransaction = 10,
370    /// Enlist DTC transaction.
371    EnlistDtcTransaction = 11,
372    /// Defect DTC transaction.
373    DefectTransaction = 12,
374    /// Real-time log shipping.
375    RealTimeLogShipping = 13,
376    /// Promote transaction.
377    PromoteTransaction = 15,
378    /// Transaction manager address.
379    TransactionManagerAddress = 16,
380    /// Transaction ended.
381    TransactionEnded = 17,
382    /// Reset connection completion acknowledgment.
383    ResetConnectionCompletionAck = 18,
384    /// User instance started.
385    UserInstanceStarted = 19,
386    /// Routing information.
387    Routing = 20,
388}
389
390/// Environment change value.
391#[derive(Debug, Clone)]
392pub enum EnvChangeValue {
393    /// String value.
394    String(String),
395    /// Binary value.
396    Binary(bytes::Bytes),
397    /// Routing information.
398    Routing {
399        /// Host name.
400        host: String,
401        /// Port number.
402        port: u16,
403    },
404}
405
406/// Column ordering information.
407#[derive(Debug, Clone)]
408pub struct Order {
409    /// Ordered column indices.
410    pub columns: Vec<u16>,
411}
412
413/// Feature extension acknowledgment.
414#[derive(Debug, Clone)]
415pub struct FeatureExtAck {
416    /// Acknowledged features.
417    pub features: Vec<FeatureAck>,
418}
419
420/// Individual feature acknowledgment.
421#[derive(Debug, Clone)]
422pub struct FeatureAck {
423    /// Feature ID.
424    pub feature_id: u8,
425    /// Feature data.
426    pub data: bytes::Bytes,
427}
428
429/// SSPI authentication token.
430#[derive(Debug, Clone)]
431pub struct SspiToken {
432    /// SSPI data.
433    pub data: bytes::Bytes,
434}
435
436/// Session state token.
437#[derive(Debug, Clone)]
438pub struct SessionState {
439    /// Session state data.
440    pub data: bytes::Bytes,
441}
442
443/// Federated authentication info.
444#[derive(Debug, Clone)]
445pub struct FedAuthInfo {
446    /// STS URL.
447    pub sts_url: String,
448    /// Service principal name.
449    pub spn: String,
450}
451
452// =============================================================================
453// ColMetaData and Row Parsing Implementation
454// =============================================================================
455
456impl ColMetaData {
457    /// Special value indicating no metadata.
458    pub const NO_METADATA: u16 = 0xFFFF;
459
460    /// Decode a COLMETADATA token from bytes.
461    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
462        if src.remaining() < 2 {
463            return Err(ProtocolError::UnexpectedEof);
464        }
465
466        let column_count = src.get_u16_le();
467
468        // 0xFFFF means no metadata present
469        if column_count == Self::NO_METADATA {
470            return Ok(Self {
471                columns: Vec::new(),
472            });
473        }
474
475        let mut columns = Vec::with_capacity(column_count as usize);
476
477        for _ in 0..column_count {
478            let column = Self::decode_column(src)?;
479            columns.push(column);
480        }
481
482        Ok(Self { columns })
483    }
484
485    /// Decode a single column from the metadata.
486    fn decode_column(src: &mut impl Buf) -> Result<ColumnData, ProtocolError> {
487        // UserType (4 bytes) + Flags (2 bytes) + TypeId (1 byte)
488        if src.remaining() < 7 {
489            return Err(ProtocolError::UnexpectedEof);
490        }
491
492        let user_type = src.get_u32_le();
493        let flags = src.get_u16_le();
494        let col_type = src.get_u8();
495
496        let type_id = TypeId::from_u8(col_type).unwrap_or(TypeId::Null); // Default to Null for unknown types
497
498        // Parse type-specific metadata
499        let type_info = Self::decode_type_info(src, type_id, col_type)?;
500
501        // Read column name (B_VARCHAR format - 1 byte length in characters)
502        let name = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
503
504        Ok(ColumnData {
505            name,
506            type_id,
507            col_type,
508            flags,
509            user_type,
510            type_info,
511        })
512    }
513
514    /// Decode type-specific metadata based on the type ID.
515    fn decode_type_info(
516        src: &mut impl Buf,
517        type_id: TypeId,
518        col_type: u8,
519    ) -> Result<TypeInfo, ProtocolError> {
520        match type_id {
521            // Fixed-length types have no additional metadata
522            TypeId::Null => Ok(TypeInfo::default()),
523            TypeId::Int1 | TypeId::Bit => Ok(TypeInfo::default()),
524            TypeId::Int2 => Ok(TypeInfo::default()),
525            TypeId::Int4 => Ok(TypeInfo::default()),
526            TypeId::Int8 => Ok(TypeInfo::default()),
527            TypeId::Float4 => Ok(TypeInfo::default()),
528            TypeId::Float8 => Ok(TypeInfo::default()),
529            TypeId::Money => Ok(TypeInfo::default()),
530            TypeId::Money4 => Ok(TypeInfo::default()),
531            TypeId::DateTime => Ok(TypeInfo::default()),
532            TypeId::DateTime4 => Ok(TypeInfo::default()),
533
534            // Variable length integer/float/money (1-byte max length)
535            TypeId::IntN | TypeId::BitN | TypeId::FloatN | TypeId::MoneyN | TypeId::DateTimeN => {
536                if src.remaining() < 1 {
537                    return Err(ProtocolError::UnexpectedEof);
538                }
539                let max_length = src.get_u8() as u32;
540                Ok(TypeInfo {
541                    max_length: Some(max_length),
542                    ..Default::default()
543                })
544            }
545
546            // GUID has 1-byte length
547            TypeId::Guid => {
548                if src.remaining() < 1 {
549                    return Err(ProtocolError::UnexpectedEof);
550                }
551                let max_length = src.get_u8() as u32;
552                Ok(TypeInfo {
553                    max_length: Some(max_length),
554                    ..Default::default()
555                })
556            }
557
558            // Decimal/Numeric types (1-byte length + precision + scale)
559            TypeId::Decimal | TypeId::Numeric | TypeId::DecimalN | TypeId::NumericN => {
560                if src.remaining() < 3 {
561                    return Err(ProtocolError::UnexpectedEof);
562                }
563                let max_length = src.get_u8() as u32;
564                let precision = src.get_u8();
565                let scale = src.get_u8();
566                Ok(TypeInfo {
567                    max_length: Some(max_length),
568                    precision: Some(precision),
569                    scale: Some(scale),
570                    ..Default::default()
571                })
572            }
573
574            // Old-style byte-length strings (Char, VarChar, Binary, VarBinary)
575            TypeId::Char | TypeId::VarChar | TypeId::Binary | TypeId::VarBinary => {
576                if src.remaining() < 1 {
577                    return Err(ProtocolError::UnexpectedEof);
578                }
579                let max_length = src.get_u8() as u32;
580                Ok(TypeInfo {
581                    max_length: Some(max_length),
582                    ..Default::default()
583                })
584            }
585
586            // Big varchar/binary with 2-byte length + collation for strings
587            TypeId::BigVarChar | TypeId::BigChar => {
588                if src.remaining() < 7 {
589                    // 2 (length) + 5 (collation)
590                    return Err(ProtocolError::UnexpectedEof);
591                }
592                let max_length = src.get_u16_le() as u32;
593                let collation = Self::decode_collation(src)?;
594                Ok(TypeInfo {
595                    max_length: Some(max_length),
596                    collation: Some(collation),
597                    ..Default::default()
598                })
599            }
600
601            // Big binary (2-byte length, no collation)
602            TypeId::BigVarBinary | TypeId::BigBinary => {
603                if src.remaining() < 2 {
604                    return Err(ProtocolError::UnexpectedEof);
605                }
606                let max_length = src.get_u16_le() as u32;
607                Ok(TypeInfo {
608                    max_length: Some(max_length),
609                    ..Default::default()
610                })
611            }
612
613            // Unicode strings (NChar, NVarChar) - 2-byte length + collation
614            TypeId::NChar | TypeId::NVarChar => {
615                if src.remaining() < 7 {
616                    // 2 (length) + 5 (collation)
617                    return Err(ProtocolError::UnexpectedEof);
618                }
619                let max_length = src.get_u16_le() as u32;
620                let collation = Self::decode_collation(src)?;
621                Ok(TypeInfo {
622                    max_length: Some(max_length),
623                    collation: Some(collation),
624                    ..Default::default()
625                })
626            }
627
628            // Date type (no additional metadata)
629            TypeId::Date => Ok(TypeInfo::default()),
630
631            // Time, DateTime2, DateTimeOffset have scale
632            TypeId::Time | TypeId::DateTime2 | TypeId::DateTimeOffset => {
633                if src.remaining() < 1 {
634                    return Err(ProtocolError::UnexpectedEof);
635                }
636                let scale = src.get_u8();
637                Ok(TypeInfo {
638                    scale: Some(scale),
639                    ..Default::default()
640                })
641            }
642
643            // Text/NText/Image (deprecated LOB types)
644            TypeId::Text | TypeId::NText | TypeId::Image => {
645                // These have complex metadata: length (4) + collation (5) + table name parts
646                if src.remaining() < 4 {
647                    return Err(ProtocolError::UnexpectedEof);
648                }
649                let max_length = src.get_u32_le();
650
651                // For Text/NText, read collation
652                let collation = if type_id == TypeId::Text || type_id == TypeId::NText {
653                    if src.remaining() < 5 {
654                        return Err(ProtocolError::UnexpectedEof);
655                    }
656                    Some(Self::decode_collation(src)?)
657                } else {
658                    None
659                };
660
661                // Skip table name parts (variable length)
662                // Format: numParts (1 byte) followed by us_varchar for each part
663                if src.remaining() < 1 {
664                    return Err(ProtocolError::UnexpectedEof);
665                }
666                let num_parts = src.get_u8();
667                for _ in 0..num_parts {
668                    // Read and discard table name part
669                    let _ = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
670                }
671
672                Ok(TypeInfo {
673                    max_length: Some(max_length),
674                    collation,
675                    ..Default::default()
676                })
677            }
678
679            // XML type
680            TypeId::Xml => {
681                if src.remaining() < 1 {
682                    return Err(ProtocolError::UnexpectedEof);
683                }
684                let schema_present = src.get_u8();
685
686                if schema_present != 0 {
687                    // Read schema info (3 us_varchar strings)
688                    let _ = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?; // db name
689                    let _ = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?; // owning schema
690                    let _ = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?; // xml schema collection
691                }
692
693                Ok(TypeInfo::default())
694            }
695
696            // UDT (User-defined type) - complex metadata
697            TypeId::Udt => {
698                // Max length (2 bytes)
699                if src.remaining() < 2 {
700                    return Err(ProtocolError::UnexpectedEof);
701                }
702                let max_length = src.get_u16_le() as u32;
703
704                // UDT metadata: db name, schema name, type name, assembly qualified name
705                let _ = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?; // db name
706                let _ = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?; // schema name
707                let _ = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?; // type name
708                let _ = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?; // assembly qualified name
709
710                Ok(TypeInfo {
711                    max_length: Some(max_length),
712                    ..Default::default()
713                })
714            }
715
716            // Table-valued parameter - complex metadata (skip for now)
717            TypeId::Tvp => {
718                // TVP has very complex metadata, not commonly used
719                // For now, we can't properly parse this
720                Err(ProtocolError::InvalidTokenType(col_type))
721            }
722
723            // SQL Variant - 4-byte length
724            TypeId::Variant => {
725                if src.remaining() < 4 {
726                    return Err(ProtocolError::UnexpectedEof);
727                }
728                let max_length = src.get_u32_le();
729                Ok(TypeInfo {
730                    max_length: Some(max_length),
731                    ..Default::default()
732                })
733            }
734        }
735    }
736
737    /// Decode collation information (5 bytes).
738    fn decode_collation(src: &mut impl Buf) -> Result<Collation, ProtocolError> {
739        if src.remaining() < 5 {
740            return Err(ProtocolError::UnexpectedEof);
741        }
742        // Collation: LCID (4 bytes) + Sort ID (1 byte)
743        let lcid = src.get_u32_le();
744        let sort_id = src.get_u8();
745        Ok(Collation { lcid, sort_id })
746    }
747
748    /// Get the number of columns.
749    #[must_use]
750    pub fn column_count(&self) -> usize {
751        self.columns.len()
752    }
753
754    /// Check if this represents no metadata.
755    #[must_use]
756    pub fn is_empty(&self) -> bool {
757        self.columns.is_empty()
758    }
759}
760
761impl ColumnData {
762    /// Check if this column is nullable.
763    #[must_use]
764    pub fn is_nullable(&self) -> bool {
765        (self.flags & 0x0001) != 0
766    }
767
768    /// Get the fixed size in bytes for this column, if applicable.
769    ///
770    /// Returns `None` for variable-length types.
771    #[must_use]
772    pub fn fixed_size(&self) -> Option<usize> {
773        match self.type_id {
774            TypeId::Null => Some(0),
775            TypeId::Int1 | TypeId::Bit => Some(1),
776            TypeId::Int2 => Some(2),
777            TypeId::Int4 => Some(4),
778            TypeId::Int8 => Some(8),
779            TypeId::Float4 => Some(4),
780            TypeId::Float8 => Some(8),
781            TypeId::Money => Some(8),
782            TypeId::Money4 => Some(4),
783            TypeId::DateTime => Some(8),
784            TypeId::DateTime4 => Some(4),
785            TypeId::Date => Some(3),
786            _ => None,
787        }
788    }
789}
790
791// =============================================================================
792// Row Parsing Implementation
793// =============================================================================
794
795impl RawRow {
796    /// Decode a ROW token from bytes.
797    ///
798    /// This function requires the column metadata to know how to parse the row.
799    /// The row data is stored as raw bytes for later parsing.
800    pub fn decode(src: &mut impl Buf, metadata: &ColMetaData) -> Result<Self, ProtocolError> {
801        let mut data = bytes::BytesMut::new();
802
803        for col in &metadata.columns {
804            Self::decode_column_value(src, col, &mut data)?;
805        }
806
807        Ok(Self {
808            data: data.freeze(),
809        })
810    }
811
812    /// Decode a single column value and append to the output buffer.
813    fn decode_column_value(
814        src: &mut impl Buf,
815        col: &ColumnData,
816        dst: &mut bytes::BytesMut,
817    ) -> Result<(), ProtocolError> {
818        match col.type_id {
819            // Fixed-length types
820            TypeId::Null => {
821                // No data
822            }
823            TypeId::Int1 | TypeId::Bit => {
824                if src.remaining() < 1 {
825                    return Err(ProtocolError::UnexpectedEof);
826                }
827                dst.extend_from_slice(&[src.get_u8()]);
828            }
829            TypeId::Int2 => {
830                if src.remaining() < 2 {
831                    return Err(ProtocolError::UnexpectedEof);
832                }
833                dst.extend_from_slice(&src.get_u16_le().to_le_bytes());
834            }
835            TypeId::Int4 => {
836                if src.remaining() < 4 {
837                    return Err(ProtocolError::UnexpectedEof);
838                }
839                dst.extend_from_slice(&src.get_u32_le().to_le_bytes());
840            }
841            TypeId::Int8 => {
842                if src.remaining() < 8 {
843                    return Err(ProtocolError::UnexpectedEof);
844                }
845                dst.extend_from_slice(&src.get_u64_le().to_le_bytes());
846            }
847            TypeId::Float4 => {
848                if src.remaining() < 4 {
849                    return Err(ProtocolError::UnexpectedEof);
850                }
851                dst.extend_from_slice(&src.get_u32_le().to_le_bytes());
852            }
853            TypeId::Float8 => {
854                if src.remaining() < 8 {
855                    return Err(ProtocolError::UnexpectedEof);
856                }
857                dst.extend_from_slice(&src.get_u64_le().to_le_bytes());
858            }
859            TypeId::Money => {
860                if src.remaining() < 8 {
861                    return Err(ProtocolError::UnexpectedEof);
862                }
863                let hi = src.get_u32_le();
864                let lo = src.get_u32_le();
865                dst.extend_from_slice(&hi.to_le_bytes());
866                dst.extend_from_slice(&lo.to_le_bytes());
867            }
868            TypeId::Money4 => {
869                if src.remaining() < 4 {
870                    return Err(ProtocolError::UnexpectedEof);
871                }
872                dst.extend_from_slice(&src.get_u32_le().to_le_bytes());
873            }
874            TypeId::DateTime => {
875                if src.remaining() < 8 {
876                    return Err(ProtocolError::UnexpectedEof);
877                }
878                let days = src.get_u32_le();
879                let time = src.get_u32_le();
880                dst.extend_from_slice(&days.to_le_bytes());
881                dst.extend_from_slice(&time.to_le_bytes());
882            }
883            TypeId::DateTime4 => {
884                if src.remaining() < 4 {
885                    return Err(ProtocolError::UnexpectedEof);
886                }
887                dst.extend_from_slice(&src.get_u32_le().to_le_bytes());
888            }
889            TypeId::Date => {
890                if src.remaining() < 3 {
891                    return Err(ProtocolError::UnexpectedEof);
892                }
893                let b1 = src.get_u8();
894                let b2 = src.get_u8();
895                let b3 = src.get_u8();
896                dst.extend_from_slice(&[b1, b2, b3]);
897            }
898
899            // Variable-length nullable types (length-prefixed)
900            TypeId::IntN | TypeId::BitN | TypeId::FloatN | TypeId::MoneyN | TypeId::DateTimeN => {
901                Self::decode_bytelen_type(src, dst)?;
902            }
903
904            TypeId::Guid => {
905                Self::decode_bytelen_type(src, dst)?;
906            }
907
908            TypeId::Decimal | TypeId::Numeric | TypeId::DecimalN | TypeId::NumericN => {
909                Self::decode_bytelen_type(src, dst)?;
910            }
911
912            // Old-style byte-length strings
913            TypeId::Char | TypeId::VarChar | TypeId::Binary | TypeId::VarBinary => {
914                Self::decode_bytelen_type(src, dst)?;
915            }
916
917            // 2-byte length strings (or PLP for MAX types)
918            TypeId::BigVarChar | TypeId::BigVarBinary => {
919                // max_length == 0xFFFF indicates VARCHAR(MAX) or VARBINARY(MAX), which uses PLP
920                if col.type_info.max_length == Some(0xFFFF) {
921                    Self::decode_plp_type(src, dst)?;
922                } else {
923                    Self::decode_ushortlen_type(src, dst)?;
924                }
925            }
926
927            // Fixed-length types that don't have MAX variants
928            TypeId::BigChar | TypeId::BigBinary => {
929                Self::decode_ushortlen_type(src, dst)?;
930            }
931
932            // Unicode strings (2-byte length in bytes, or PLP for NVARCHAR(MAX))
933            TypeId::NVarChar => {
934                // max_length == 0xFFFF indicates NVARCHAR(MAX), which uses PLP
935                if col.type_info.max_length == Some(0xFFFF) {
936                    Self::decode_plp_type(src, dst)?;
937                } else {
938                    Self::decode_ushortlen_type(src, dst)?;
939                }
940            }
941
942            // Fixed-length NCHAR doesn't have MAX variant
943            TypeId::NChar => {
944                Self::decode_ushortlen_type(src, dst)?;
945            }
946
947            // Time types with scale
948            TypeId::Time | TypeId::DateTime2 | TypeId::DateTimeOffset => {
949                Self::decode_bytelen_type(src, dst)?;
950            }
951
952            // PLP (Partially Length Prefixed) types
953            TypeId::Text | TypeId::NText | TypeId::Image | TypeId::Xml => {
954                Self::decode_plp_type(src, dst)?;
955            }
956
957            // Complex types
958            TypeId::Variant => {
959                Self::decode_intlen_type(src, dst)?;
960            }
961
962            TypeId::Udt => {
963                // UDT uses PLP encoding
964                Self::decode_plp_type(src, dst)?;
965            }
966
967            TypeId::Tvp => {
968                // TVP not supported in row data
969                return Err(ProtocolError::InvalidTokenType(col.col_type));
970            }
971        }
972
973        Ok(())
974    }
975
976    /// Decode a 1-byte length-prefixed value.
977    fn decode_bytelen_type(
978        src: &mut impl Buf,
979        dst: &mut bytes::BytesMut,
980    ) -> Result<(), ProtocolError> {
981        if src.remaining() < 1 {
982            return Err(ProtocolError::UnexpectedEof);
983        }
984        let len = src.get_u8() as usize;
985        if len == 0xFF {
986            // NULL value - store as zero-length with NULL marker
987            dst.extend_from_slice(&[0xFF]);
988        } else if len == 0 {
989            // Empty value
990            dst.extend_from_slice(&[0x00]);
991        } else {
992            if src.remaining() < len {
993                return Err(ProtocolError::UnexpectedEof);
994            }
995            dst.extend_from_slice(&[len as u8]);
996            for _ in 0..len {
997                dst.extend_from_slice(&[src.get_u8()]);
998            }
999        }
1000        Ok(())
1001    }
1002
1003    /// Decode a 2-byte length-prefixed value.
1004    fn decode_ushortlen_type(
1005        src: &mut impl Buf,
1006        dst: &mut bytes::BytesMut,
1007    ) -> Result<(), ProtocolError> {
1008        if src.remaining() < 2 {
1009            return Err(ProtocolError::UnexpectedEof);
1010        }
1011        let len = src.get_u16_le() as usize;
1012        if len == 0xFFFF {
1013            // NULL value
1014            dst.extend_from_slice(&0xFFFFu16.to_le_bytes());
1015        } else if len == 0 {
1016            // Empty value
1017            dst.extend_from_slice(&0u16.to_le_bytes());
1018        } else {
1019            if src.remaining() < len {
1020                return Err(ProtocolError::UnexpectedEof);
1021            }
1022            dst.extend_from_slice(&(len as u16).to_le_bytes());
1023            for _ in 0..len {
1024                dst.extend_from_slice(&[src.get_u8()]);
1025            }
1026        }
1027        Ok(())
1028    }
1029
1030    /// Decode a 4-byte length-prefixed value.
1031    fn decode_intlen_type(
1032        src: &mut impl Buf,
1033        dst: &mut bytes::BytesMut,
1034    ) -> Result<(), ProtocolError> {
1035        if src.remaining() < 4 {
1036            return Err(ProtocolError::UnexpectedEof);
1037        }
1038        let len = src.get_u32_le() as usize;
1039        if len == 0xFFFFFFFF {
1040            // NULL value
1041            dst.extend_from_slice(&0xFFFFFFFFu32.to_le_bytes());
1042        } else if len == 0 {
1043            // Empty value
1044            dst.extend_from_slice(&0u32.to_le_bytes());
1045        } else {
1046            if src.remaining() < len {
1047                return Err(ProtocolError::UnexpectedEof);
1048            }
1049            dst.extend_from_slice(&(len as u32).to_le_bytes());
1050            for _ in 0..len {
1051                dst.extend_from_slice(&[src.get_u8()]);
1052            }
1053        }
1054        Ok(())
1055    }
1056
1057    /// Decode a PLP (Partially Length-Prefixed) value.
1058    ///
1059    /// PLP format:
1060    /// - 8 bytes: total length (0xFFFFFFFFFFFFFFFE = unknown, 0xFFFFFFFFFFFFFFFF = NULL)
1061    /// - If not NULL: chunks of (4 byte chunk length + data) until chunk length = 0
1062    fn decode_plp_type(src: &mut impl Buf, dst: &mut bytes::BytesMut) -> Result<(), ProtocolError> {
1063        if src.remaining() < 8 {
1064            return Err(ProtocolError::UnexpectedEof);
1065        }
1066
1067        let total_len = src.get_u64_le();
1068
1069        // Store the total length marker
1070        dst.extend_from_slice(&total_len.to_le_bytes());
1071
1072        if total_len == 0xFFFFFFFFFFFFFFFF {
1073            // NULL value - no more data
1074            return Ok(());
1075        }
1076
1077        // Read chunks until terminator
1078        loop {
1079            if src.remaining() < 4 {
1080                return Err(ProtocolError::UnexpectedEof);
1081            }
1082            let chunk_len = src.get_u32_le() as usize;
1083            dst.extend_from_slice(&(chunk_len as u32).to_le_bytes());
1084
1085            if chunk_len == 0 {
1086                // End of PLP data
1087                break;
1088            }
1089
1090            if src.remaining() < chunk_len {
1091                return Err(ProtocolError::UnexpectedEof);
1092            }
1093
1094            for _ in 0..chunk_len {
1095                dst.extend_from_slice(&[src.get_u8()]);
1096            }
1097        }
1098
1099        Ok(())
1100    }
1101}
1102
1103// =============================================================================
1104// NbcRow Parsing Implementation
1105// =============================================================================
1106
1107impl NbcRow {
1108    /// Decode an NBCROW token from bytes.
1109    ///
1110    /// NBCROW (Null Bitmap Compressed Row) stores a bitmap indicating which
1111    /// columns are NULL, followed by only the non-NULL values.
1112    pub fn decode(src: &mut impl Buf, metadata: &ColMetaData) -> Result<Self, ProtocolError> {
1113        let col_count = metadata.columns.len();
1114        let bitmap_len = (col_count + 7) / 8;
1115
1116        if src.remaining() < bitmap_len {
1117            return Err(ProtocolError::UnexpectedEof);
1118        }
1119
1120        // Read null bitmap
1121        let mut null_bitmap = vec![0u8; bitmap_len];
1122        for byte in &mut null_bitmap {
1123            *byte = src.get_u8();
1124        }
1125
1126        // Read non-null values
1127        let mut data = bytes::BytesMut::new();
1128
1129        for (i, col) in metadata.columns.iter().enumerate() {
1130            let byte_idx = i / 8;
1131            let bit_idx = i % 8;
1132            let is_null = (null_bitmap[byte_idx] & (1 << bit_idx)) != 0;
1133
1134            if !is_null {
1135                // Read the value - for NBCROW, we read without the length prefix
1136                // for fixed-length types, and with length prefix for variable types
1137                RawRow::decode_column_value(src, col, &mut data)?;
1138            }
1139        }
1140
1141        Ok(Self {
1142            null_bitmap,
1143            data: data.freeze(),
1144        })
1145    }
1146
1147    /// Check if a column at the given index is NULL.
1148    #[must_use]
1149    pub fn is_null(&self, column_index: usize) -> bool {
1150        let byte_idx = column_index / 8;
1151        let bit_idx = column_index % 8;
1152        if byte_idx < self.null_bitmap.len() {
1153            (self.null_bitmap[byte_idx] & (1 << bit_idx)) != 0
1154        } else {
1155            true // Out of bounds = NULL
1156        }
1157    }
1158}
1159
1160// =============================================================================
1161// ReturnValue Parsing Implementation
1162// =============================================================================
1163
1164impl ReturnValue {
1165    /// Decode a RETURNVALUE token from bytes.
1166    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1167        // Length (2 bytes)
1168        if src.remaining() < 2 {
1169            return Err(ProtocolError::UnexpectedEof);
1170        }
1171        let _length = src.get_u16_le();
1172
1173        // Parameter ordinal (2 bytes)
1174        if src.remaining() < 2 {
1175            return Err(ProtocolError::UnexpectedEof);
1176        }
1177        let param_ordinal = src.get_u16_le();
1178
1179        // Parameter name (B_VARCHAR)
1180        let param_name = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1181
1182        // Status (1 byte)
1183        if src.remaining() < 1 {
1184            return Err(ProtocolError::UnexpectedEof);
1185        }
1186        let status = src.get_u8();
1187
1188        // User type (4 bytes) + flags (2 bytes) + type id (1 byte)
1189        if src.remaining() < 7 {
1190            return Err(ProtocolError::UnexpectedEof);
1191        }
1192        let user_type = src.get_u32_le();
1193        let flags = src.get_u16_le();
1194        let col_type = src.get_u8();
1195
1196        let type_id = TypeId::from_u8(col_type).unwrap_or(TypeId::Null);
1197
1198        // Parse type info
1199        let type_info = ColMetaData::decode_type_info(src, type_id, col_type)?;
1200
1201        // Read the value data
1202        let mut value_buf = bytes::BytesMut::new();
1203
1204        // Create a temporary column for value parsing
1205        let temp_col = ColumnData {
1206            name: String::new(),
1207            type_id,
1208            col_type,
1209            flags,
1210            user_type,
1211            type_info: type_info.clone(),
1212        };
1213
1214        RawRow::decode_column_value(src, &temp_col, &mut value_buf)?;
1215
1216        Ok(Self {
1217            param_ordinal,
1218            param_name,
1219            status,
1220            user_type,
1221            flags,
1222            type_info,
1223            value: value_buf.freeze(),
1224        })
1225    }
1226}
1227
1228// =============================================================================
1229// SessionState Parsing Implementation
1230// =============================================================================
1231
1232impl SessionState {
1233    /// Decode a SESSIONSTATE token from bytes.
1234    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1235        if src.remaining() < 4 {
1236            return Err(ProtocolError::UnexpectedEof);
1237        }
1238
1239        let length = src.get_u32_le() as usize;
1240
1241        if src.remaining() < length {
1242            return Err(ProtocolError::IncompletePacket {
1243                expected: length,
1244                actual: src.remaining(),
1245            });
1246        }
1247
1248        let data = src.copy_to_bytes(length);
1249
1250        Ok(Self { data })
1251    }
1252}
1253
1254// =============================================================================
1255// Token Parsing Implementation
1256// =============================================================================
1257
1258/// Done token status flags bit positions.
1259mod done_status_bits {
1260    pub const DONE_MORE: u16 = 0x0001;
1261    pub const DONE_ERROR: u16 = 0x0002;
1262    pub const DONE_INXACT: u16 = 0x0004;
1263    pub const DONE_COUNT: u16 = 0x0010;
1264    pub const DONE_ATTN: u16 = 0x0020;
1265    pub const DONE_SRVERROR: u16 = 0x0100;
1266}
1267
1268impl DoneStatus {
1269    /// Parse done status from raw bits.
1270    #[must_use]
1271    pub fn from_bits(bits: u16) -> Self {
1272        use done_status_bits::*;
1273        Self {
1274            more: (bits & DONE_MORE) != 0,
1275            error: (bits & DONE_ERROR) != 0,
1276            in_xact: (bits & DONE_INXACT) != 0,
1277            count: (bits & DONE_COUNT) != 0,
1278            attn: (bits & DONE_ATTN) != 0,
1279            srverror: (bits & DONE_SRVERROR) != 0,
1280        }
1281    }
1282
1283    /// Convert to raw bits.
1284    #[must_use]
1285    pub fn to_bits(&self) -> u16 {
1286        use done_status_bits::*;
1287        let mut bits = 0u16;
1288        if self.more {
1289            bits |= DONE_MORE;
1290        }
1291        if self.error {
1292            bits |= DONE_ERROR;
1293        }
1294        if self.in_xact {
1295            bits |= DONE_INXACT;
1296        }
1297        if self.count {
1298            bits |= DONE_COUNT;
1299        }
1300        if self.attn {
1301            bits |= DONE_ATTN;
1302        }
1303        if self.srverror {
1304            bits |= DONE_SRVERROR;
1305        }
1306        bits
1307    }
1308}
1309
1310impl Done {
1311    /// Size of the DONE token in bytes (excluding token type byte).
1312    pub const SIZE: usize = 12; // 2 (status) + 2 (curcmd) + 8 (rowcount)
1313
1314    /// Decode a DONE token from bytes.
1315    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1316        if src.remaining() < Self::SIZE {
1317            return Err(ProtocolError::IncompletePacket {
1318                expected: Self::SIZE,
1319                actual: src.remaining(),
1320            });
1321        }
1322
1323        let status = DoneStatus::from_bits(src.get_u16_le());
1324        let cur_cmd = src.get_u16_le();
1325        let row_count = src.get_u64_le();
1326
1327        Ok(Self {
1328            status,
1329            cur_cmd,
1330            row_count,
1331        })
1332    }
1333
1334    /// Encode the DONE token to bytes.
1335    pub fn encode(&self, dst: &mut impl BufMut) {
1336        dst.put_u8(TokenType::Done as u8);
1337        dst.put_u16_le(self.status.to_bits());
1338        dst.put_u16_le(self.cur_cmd);
1339        dst.put_u64_le(self.row_count);
1340    }
1341
1342    /// Check if more results follow this DONE token.
1343    #[must_use]
1344    pub const fn has_more(&self) -> bool {
1345        self.status.more
1346    }
1347
1348    /// Check if an error occurred.
1349    #[must_use]
1350    pub const fn has_error(&self) -> bool {
1351        self.status.error
1352    }
1353
1354    /// Check if the row count is valid.
1355    #[must_use]
1356    pub const fn has_count(&self) -> bool {
1357        self.status.count
1358    }
1359}
1360
1361impl DoneProc {
1362    /// Size of the DONEPROC token in bytes (excluding token type byte).
1363    pub const SIZE: usize = 12;
1364
1365    /// Decode a DONEPROC token from bytes.
1366    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1367        if src.remaining() < Self::SIZE {
1368            return Err(ProtocolError::IncompletePacket {
1369                expected: Self::SIZE,
1370                actual: src.remaining(),
1371            });
1372        }
1373
1374        let status = DoneStatus::from_bits(src.get_u16_le());
1375        let cur_cmd = src.get_u16_le();
1376        let row_count = src.get_u64_le();
1377
1378        Ok(Self {
1379            status,
1380            cur_cmd,
1381            row_count,
1382        })
1383    }
1384
1385    /// Encode the DONEPROC token to bytes.
1386    pub fn encode(&self, dst: &mut impl BufMut) {
1387        dst.put_u8(TokenType::DoneProc as u8);
1388        dst.put_u16_le(self.status.to_bits());
1389        dst.put_u16_le(self.cur_cmd);
1390        dst.put_u64_le(self.row_count);
1391    }
1392}
1393
1394impl DoneInProc {
1395    /// Size of the DONEINPROC token in bytes (excluding token type byte).
1396    pub const SIZE: usize = 12;
1397
1398    /// Decode a DONEINPROC token from bytes.
1399    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1400        if src.remaining() < Self::SIZE {
1401            return Err(ProtocolError::IncompletePacket {
1402                expected: Self::SIZE,
1403                actual: src.remaining(),
1404            });
1405        }
1406
1407        let status = DoneStatus::from_bits(src.get_u16_le());
1408        let cur_cmd = src.get_u16_le();
1409        let row_count = src.get_u64_le();
1410
1411        Ok(Self {
1412            status,
1413            cur_cmd,
1414            row_count,
1415        })
1416    }
1417
1418    /// Encode the DONEINPROC token to bytes.
1419    pub fn encode(&self, dst: &mut impl BufMut) {
1420        dst.put_u8(TokenType::DoneInProc as u8);
1421        dst.put_u16_le(self.status.to_bits());
1422        dst.put_u16_le(self.cur_cmd);
1423        dst.put_u64_le(self.row_count);
1424    }
1425}
1426
1427impl ServerError {
1428    /// Decode an ERROR token from bytes.
1429    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1430        // ERROR token: length (2) + number (4) + state (1) + class (1) +
1431        //              message (us_varchar) + server (b_varchar) + procedure (b_varchar) + line (4)
1432        if src.remaining() < 2 {
1433            return Err(ProtocolError::UnexpectedEof);
1434        }
1435
1436        let _length = src.get_u16_le();
1437
1438        if src.remaining() < 6 {
1439            return Err(ProtocolError::UnexpectedEof);
1440        }
1441
1442        let number = src.get_i32_le();
1443        let state = src.get_u8();
1444        let class = src.get_u8();
1445
1446        let message = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1447        let server = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1448        let procedure = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1449
1450        if src.remaining() < 4 {
1451            return Err(ProtocolError::UnexpectedEof);
1452        }
1453        let line = src.get_i32_le();
1454
1455        Ok(Self {
1456            number,
1457            state,
1458            class,
1459            message,
1460            server,
1461            procedure,
1462            line,
1463        })
1464    }
1465
1466    /// Check if this is a fatal error (severity >= 20).
1467    #[must_use]
1468    pub const fn is_fatal(&self) -> bool {
1469        self.class >= 20
1470    }
1471
1472    /// Check if this error indicates the batch was aborted (severity >= 16).
1473    #[must_use]
1474    pub const fn is_batch_abort(&self) -> bool {
1475        self.class >= 16
1476    }
1477}
1478
1479impl ServerInfo {
1480    /// Decode an INFO token from bytes.
1481    ///
1482    /// INFO tokens have the same structure as ERROR tokens but with lower severity.
1483    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1484        if src.remaining() < 2 {
1485            return Err(ProtocolError::UnexpectedEof);
1486        }
1487
1488        let _length = src.get_u16_le();
1489
1490        if src.remaining() < 6 {
1491            return Err(ProtocolError::UnexpectedEof);
1492        }
1493
1494        let number = src.get_i32_le();
1495        let state = src.get_u8();
1496        let class = src.get_u8();
1497
1498        let message = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1499        let server = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1500        let procedure = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1501
1502        if src.remaining() < 4 {
1503            return Err(ProtocolError::UnexpectedEof);
1504        }
1505        let line = src.get_i32_le();
1506
1507        Ok(Self {
1508            number,
1509            state,
1510            class,
1511            message,
1512            server,
1513            procedure,
1514            line,
1515        })
1516    }
1517}
1518
1519impl LoginAck {
1520    /// Decode a LOGINACK token from bytes.
1521    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1522        // LOGINACK: length (2) + interface (1) + tds_version (4) + prog_name (b_varchar) + prog_version (4)
1523        if src.remaining() < 2 {
1524            return Err(ProtocolError::UnexpectedEof);
1525        }
1526
1527        let _length = src.get_u16_le();
1528
1529        if src.remaining() < 5 {
1530            return Err(ProtocolError::UnexpectedEof);
1531        }
1532
1533        let interface = src.get_u8();
1534        let tds_version = src.get_u32_le();
1535        let prog_name = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1536
1537        if src.remaining() < 4 {
1538            return Err(ProtocolError::UnexpectedEof);
1539        }
1540        let prog_version = src.get_u32_le();
1541
1542        Ok(Self {
1543            interface,
1544            tds_version,
1545            prog_name,
1546            prog_version,
1547        })
1548    }
1549
1550    /// Get the TDS version as a `TdsVersion`.
1551    #[must_use]
1552    pub fn tds_version(&self) -> crate::version::TdsVersion {
1553        crate::version::TdsVersion::new(self.tds_version)
1554    }
1555}
1556
1557impl EnvChangeType {
1558    /// Create from raw byte value.
1559    pub fn from_u8(value: u8) -> Option<Self> {
1560        match value {
1561            1 => Some(Self::Database),
1562            2 => Some(Self::Language),
1563            3 => Some(Self::CharacterSet),
1564            4 => Some(Self::PacketSize),
1565            5 => Some(Self::UnicodeSortingLocalId),
1566            6 => Some(Self::UnicodeComparisonFlags),
1567            7 => Some(Self::SqlCollation),
1568            8 => Some(Self::BeginTransaction),
1569            9 => Some(Self::CommitTransaction),
1570            10 => Some(Self::RollbackTransaction),
1571            11 => Some(Self::EnlistDtcTransaction),
1572            12 => Some(Self::DefectTransaction),
1573            13 => Some(Self::RealTimeLogShipping),
1574            15 => Some(Self::PromoteTransaction),
1575            16 => Some(Self::TransactionManagerAddress),
1576            17 => Some(Self::TransactionEnded),
1577            18 => Some(Self::ResetConnectionCompletionAck),
1578            19 => Some(Self::UserInstanceStarted),
1579            20 => Some(Self::Routing),
1580            _ => None,
1581        }
1582    }
1583}
1584
1585impl EnvChange {
1586    /// Decode an ENVCHANGE token from bytes.
1587    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1588        if src.remaining() < 3 {
1589            return Err(ProtocolError::UnexpectedEof);
1590        }
1591
1592        let length = src.get_u16_le() as usize;
1593        if src.remaining() < length {
1594            return Err(ProtocolError::IncompletePacket {
1595                expected: length,
1596                actual: src.remaining(),
1597            });
1598        }
1599
1600        let env_type_byte = src.get_u8();
1601        let env_type = EnvChangeType::from_u8(env_type_byte)
1602            .ok_or(ProtocolError::InvalidTokenType(env_type_byte))?;
1603
1604        let (new_value, old_value) = match env_type {
1605            EnvChangeType::Routing => {
1606                // Routing has special format
1607                let new_value = Self::decode_routing_value(src)?;
1608                let old_value = EnvChangeValue::Binary(Bytes::new());
1609                (new_value, old_value)
1610            }
1611            EnvChangeType::BeginTransaction
1612            | EnvChangeType::CommitTransaction
1613            | EnvChangeType::RollbackTransaction
1614            | EnvChangeType::EnlistDtcTransaction
1615            | EnvChangeType::SqlCollation => {
1616                // These use binary format per MS-TDS spec:
1617                // - Transaction tokens: transaction descriptor (8 bytes)
1618                // - SqlCollation: collation info (5 bytes: LCID + sort flags)
1619                let new_len = src.get_u8() as usize;
1620                let new_value = if new_len > 0 && src.remaining() >= new_len {
1621                    EnvChangeValue::Binary(src.copy_to_bytes(new_len))
1622                } else {
1623                    EnvChangeValue::Binary(Bytes::new())
1624                };
1625
1626                let old_len = src.get_u8() as usize;
1627                let old_value = if old_len > 0 && src.remaining() >= old_len {
1628                    EnvChangeValue::Binary(src.copy_to_bytes(old_len))
1629                } else {
1630                    EnvChangeValue::Binary(Bytes::new())
1631                };
1632
1633                (new_value, old_value)
1634            }
1635            _ => {
1636                // String format for most env changes
1637                let new_value = read_b_varchar(src)
1638                    .map(EnvChangeValue::String)
1639                    .unwrap_or(EnvChangeValue::String(String::new()));
1640
1641                let old_value = read_b_varchar(src)
1642                    .map(EnvChangeValue::String)
1643                    .unwrap_or(EnvChangeValue::String(String::new()));
1644
1645                (new_value, old_value)
1646            }
1647        };
1648
1649        Ok(Self {
1650            env_type,
1651            new_value,
1652            old_value,
1653        })
1654    }
1655
1656    fn decode_routing_value(src: &mut impl Buf) -> Result<EnvChangeValue, ProtocolError> {
1657        // Routing format: length (2) + protocol (1) + port (2) + server_len (2) + server (utf16)
1658        if src.remaining() < 2 {
1659            return Err(ProtocolError::UnexpectedEof);
1660        }
1661
1662        let _routing_len = src.get_u16_le();
1663
1664        if src.remaining() < 5 {
1665            return Err(ProtocolError::UnexpectedEof);
1666        }
1667
1668        let _protocol = src.get_u8();
1669        let port = src.get_u16_le();
1670        let server_len = src.get_u16_le() as usize;
1671
1672        // Read UTF-16LE server name
1673        if src.remaining() < server_len * 2 {
1674            return Err(ProtocolError::UnexpectedEof);
1675        }
1676
1677        let mut chars = Vec::with_capacity(server_len);
1678        for _ in 0..server_len {
1679            chars.push(src.get_u16_le());
1680        }
1681
1682        let host = String::from_utf16(&chars).map_err(|_| {
1683            ProtocolError::StringEncoding(
1684                #[cfg(feature = "std")]
1685                "invalid UTF-16 in routing hostname".to_string(),
1686                #[cfg(not(feature = "std"))]
1687                "invalid UTF-16 in routing hostname",
1688            )
1689        })?;
1690
1691        Ok(EnvChangeValue::Routing { host, port })
1692    }
1693
1694    /// Check if this is a routing redirect.
1695    #[must_use]
1696    pub fn is_routing(&self) -> bool {
1697        self.env_type == EnvChangeType::Routing
1698    }
1699
1700    /// Get routing information if this is a routing change.
1701    #[must_use]
1702    pub fn routing_info(&self) -> Option<(&str, u16)> {
1703        if let EnvChangeValue::Routing { host, port } = &self.new_value {
1704            Some((host, *port))
1705        } else {
1706            None
1707        }
1708    }
1709
1710    /// Get the new database name if this is a database change.
1711    #[must_use]
1712    pub fn new_database(&self) -> Option<&str> {
1713        if self.env_type == EnvChangeType::Database {
1714            if let EnvChangeValue::String(s) = &self.new_value {
1715                return Some(s);
1716            }
1717        }
1718        None
1719    }
1720}
1721
1722impl Order {
1723    /// Decode an ORDER token from bytes.
1724    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1725        if src.remaining() < 2 {
1726            return Err(ProtocolError::UnexpectedEof);
1727        }
1728
1729        let length = src.get_u16_le() as usize;
1730        let column_count = length / 2;
1731
1732        if src.remaining() < length {
1733            return Err(ProtocolError::IncompletePacket {
1734                expected: length,
1735                actual: src.remaining(),
1736            });
1737        }
1738
1739        let mut columns = Vec::with_capacity(column_count);
1740        for _ in 0..column_count {
1741            columns.push(src.get_u16_le());
1742        }
1743
1744        Ok(Self { columns })
1745    }
1746}
1747
1748impl FeatureExtAck {
1749    /// Feature terminator byte.
1750    pub const TERMINATOR: u8 = 0xFF;
1751
1752    /// Decode a FEATUREEXTACK token from bytes.
1753    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1754        let mut features = Vec::new();
1755
1756        loop {
1757            if !src.has_remaining() {
1758                return Err(ProtocolError::UnexpectedEof);
1759            }
1760
1761            let feature_id = src.get_u8();
1762            if feature_id == Self::TERMINATOR {
1763                break;
1764            }
1765
1766            if src.remaining() < 4 {
1767                return Err(ProtocolError::UnexpectedEof);
1768            }
1769
1770            let data_len = src.get_u32_le() as usize;
1771
1772            if src.remaining() < data_len {
1773                return Err(ProtocolError::IncompletePacket {
1774                    expected: data_len,
1775                    actual: src.remaining(),
1776                });
1777            }
1778
1779            let data = src.copy_to_bytes(data_len);
1780            features.push(FeatureAck { feature_id, data });
1781        }
1782
1783        Ok(Self { features })
1784    }
1785}
1786
1787impl SspiToken {
1788    /// Decode an SSPI token from bytes.
1789    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1790        if src.remaining() < 2 {
1791            return Err(ProtocolError::UnexpectedEof);
1792        }
1793
1794        let length = src.get_u16_le() as usize;
1795
1796        if src.remaining() < length {
1797            return Err(ProtocolError::IncompletePacket {
1798                expected: length,
1799                actual: src.remaining(),
1800            });
1801        }
1802
1803        let data = src.copy_to_bytes(length);
1804        Ok(Self { data })
1805    }
1806}
1807
1808impl FedAuthInfo {
1809    /// Decode a FEDAUTHINFO token from bytes.
1810    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1811        if src.remaining() < 4 {
1812            return Err(ProtocolError::UnexpectedEof);
1813        }
1814
1815        let _length = src.get_u32_le();
1816
1817        if src.remaining() < 5 {
1818            return Err(ProtocolError::UnexpectedEof);
1819        }
1820
1821        let _count = src.get_u8();
1822
1823        // Read option data
1824        let mut sts_url = String::new();
1825        let mut spn = String::new();
1826
1827        // Parse info options until we have both
1828        while src.has_remaining() {
1829            if src.remaining() < 9 {
1830                break;
1831            }
1832
1833            let info_id = src.get_u8();
1834            let info_len = src.get_u32_le() as usize;
1835            let _info_offset = src.get_u32_le();
1836
1837            if src.remaining() < info_len {
1838                break;
1839            }
1840
1841            // Read UTF-16LE string
1842            let char_count = info_len / 2;
1843            let mut chars = Vec::with_capacity(char_count);
1844            for _ in 0..char_count {
1845                chars.push(src.get_u16_le());
1846            }
1847
1848            if let Ok(value) = String::from_utf16(&chars) {
1849                match info_id {
1850                    0x01 => spn = value,
1851                    0x02 => sts_url = value,
1852                    _ => {}
1853                }
1854            }
1855        }
1856
1857        Ok(Self { sts_url, spn })
1858    }
1859}
1860
1861// =============================================================================
1862// Token Parser
1863// =============================================================================
1864
1865/// Token stream parser.
1866///
1867/// Parses a stream of TDS tokens from a byte buffer.
1868///
1869/// # Basic vs Context-Aware Parsing
1870///
1871/// Some tokens (like `Done`, `Error`, `LoginAck`) can be parsed without context.
1872/// Use [`next_token()`](TokenParser::next_token) for these.
1873///
1874/// Other tokens (like `ColMetaData`, `Row`, `NbcRow`) require column metadata
1875/// to parse correctly. Use [`next_token_with_metadata()`](TokenParser::next_token_with_metadata)
1876/// for these.
1877///
1878/// # Example
1879///
1880/// ```rust,ignore
1881/// let mut parser = TokenParser::new(data);
1882/// let mut metadata = None;
1883///
1884/// while let Some(token) = parser.next_token_with_metadata(metadata.as_ref())? {
1885///     match token {
1886///         Token::ColMetaData(meta) => {
1887///             metadata = Some(meta);
1888///         }
1889///         Token::Row(row) => {
1890///             // Process row using metadata
1891///         }
1892///         Token::Done(done) => {
1893///             if !done.has_more() {
1894///                 break;
1895///             }
1896///         }
1897///         _ => {}
1898///     }
1899/// }
1900/// ```
1901pub struct TokenParser {
1902    data: Bytes,
1903    position: usize,
1904}
1905
1906impl TokenParser {
1907    /// Create a new token parser from bytes.
1908    #[must_use]
1909    pub fn new(data: Bytes) -> Self {
1910        Self { data, position: 0 }
1911    }
1912
1913    /// Get remaining bytes in the buffer.
1914    #[must_use]
1915    pub fn remaining(&self) -> usize {
1916        self.data.len().saturating_sub(self.position)
1917    }
1918
1919    /// Check if there are more bytes to parse.
1920    #[must_use]
1921    pub fn has_remaining(&self) -> bool {
1922        self.position < self.data.len()
1923    }
1924
1925    /// Peek at the next token type without consuming it.
1926    #[must_use]
1927    pub fn peek_token_type(&self) -> Option<TokenType> {
1928        if self.position < self.data.len() {
1929            TokenType::from_u8(self.data[self.position])
1930        } else {
1931            None
1932        }
1933    }
1934
1935    /// Parse the next token from the stream.
1936    ///
1937    /// This method can only parse context-independent tokens. For tokens that
1938    /// require column metadata (ColMetaData, Row, NbcRow), use
1939    /// [`next_token_with_metadata()`](TokenParser::next_token_with_metadata).
1940    ///
1941    /// Returns `None` if no more tokens are available.
1942    pub fn next_token(&mut self) -> Result<Option<Token>, ProtocolError> {
1943        self.next_token_with_metadata(None)
1944    }
1945
1946    /// Parse the next token with optional column metadata context.
1947    ///
1948    /// When `metadata` is provided, this method can parse Row and NbcRow tokens.
1949    /// Without metadata, those tokens will return an error.
1950    ///
1951    /// Returns `None` if no more tokens are available.
1952    pub fn next_token_with_metadata(
1953        &mut self,
1954        metadata: Option<&ColMetaData>,
1955    ) -> Result<Option<Token>, ProtocolError> {
1956        if !self.has_remaining() {
1957            return Ok(None);
1958        }
1959
1960        let mut buf = &self.data[self.position..];
1961        let start_pos = self.position;
1962
1963        let token_type_byte = buf.get_u8();
1964        let token_type = TokenType::from_u8(token_type_byte);
1965
1966        let token = match token_type {
1967            Some(TokenType::Done) => {
1968                let done = Done::decode(&mut buf)?;
1969                Token::Done(done)
1970            }
1971            Some(TokenType::DoneProc) => {
1972                let done = DoneProc::decode(&mut buf)?;
1973                Token::DoneProc(done)
1974            }
1975            Some(TokenType::DoneInProc) => {
1976                let done = DoneInProc::decode(&mut buf)?;
1977                Token::DoneInProc(done)
1978            }
1979            Some(TokenType::Error) => {
1980                let error = ServerError::decode(&mut buf)?;
1981                Token::Error(error)
1982            }
1983            Some(TokenType::Info) => {
1984                let info = ServerInfo::decode(&mut buf)?;
1985                Token::Info(info)
1986            }
1987            Some(TokenType::LoginAck) => {
1988                let login_ack = LoginAck::decode(&mut buf)?;
1989                Token::LoginAck(login_ack)
1990            }
1991            Some(TokenType::EnvChange) => {
1992                let env_change = EnvChange::decode(&mut buf)?;
1993                Token::EnvChange(env_change)
1994            }
1995            Some(TokenType::Order) => {
1996                let order = Order::decode(&mut buf)?;
1997                Token::Order(order)
1998            }
1999            Some(TokenType::FeatureExtAck) => {
2000                let ack = FeatureExtAck::decode(&mut buf)?;
2001                Token::FeatureExtAck(ack)
2002            }
2003            Some(TokenType::Sspi) => {
2004                let sspi = SspiToken::decode(&mut buf)?;
2005                Token::Sspi(sspi)
2006            }
2007            Some(TokenType::FedAuthInfo) => {
2008                let info = FedAuthInfo::decode(&mut buf)?;
2009                Token::FedAuthInfo(info)
2010            }
2011            Some(TokenType::ReturnStatus) => {
2012                if buf.remaining() < 4 {
2013                    return Err(ProtocolError::UnexpectedEof);
2014                }
2015                let status = buf.get_i32_le();
2016                Token::ReturnStatus(status)
2017            }
2018            Some(TokenType::ColMetaData) => {
2019                let col_meta = ColMetaData::decode(&mut buf)?;
2020                Token::ColMetaData(col_meta)
2021            }
2022            Some(TokenType::Row) => {
2023                let meta = metadata.ok_or_else(|| {
2024                    ProtocolError::StringEncoding(
2025                        #[cfg(feature = "std")]
2026                        "Row token requires column metadata".to_string(),
2027                        #[cfg(not(feature = "std"))]
2028                        "Row token requires column metadata",
2029                    )
2030                })?;
2031                let row = RawRow::decode(&mut buf, meta)?;
2032                Token::Row(row)
2033            }
2034            Some(TokenType::NbcRow) => {
2035                let meta = metadata.ok_or_else(|| {
2036                    ProtocolError::StringEncoding(
2037                        #[cfg(feature = "std")]
2038                        "NbcRow token requires column metadata".to_string(),
2039                        #[cfg(not(feature = "std"))]
2040                        "NbcRow token requires column metadata",
2041                    )
2042                })?;
2043                let row = NbcRow::decode(&mut buf, meta)?;
2044                Token::NbcRow(row)
2045            }
2046            Some(TokenType::ReturnValue) => {
2047                let ret_val = ReturnValue::decode(&mut buf)?;
2048                Token::ReturnValue(ret_val)
2049            }
2050            Some(TokenType::SessionState) => {
2051                let session = SessionState::decode(&mut buf)?;
2052                Token::SessionState(session)
2053            }
2054            Some(TokenType::ColInfo) | Some(TokenType::TabName) | Some(TokenType::Offset) => {
2055                // These tokens are rarely used and have complex formats.
2056                // Skip them by reading the length and advancing.
2057                if buf.remaining() < 2 {
2058                    return Err(ProtocolError::UnexpectedEof);
2059                }
2060                let length = buf.get_u16_le() as usize;
2061                if buf.remaining() < length {
2062                    return Err(ProtocolError::IncompletePacket {
2063                        expected: length,
2064                        actual: buf.remaining(),
2065                    });
2066                }
2067                // Skip the data
2068                buf.advance(length);
2069                // Recursively get the next token
2070                self.position = start_pos + (self.data.len() - start_pos - buf.remaining());
2071                return self.next_token_with_metadata(metadata);
2072            }
2073            None => {
2074                return Err(ProtocolError::InvalidTokenType(token_type_byte));
2075            }
2076        };
2077
2078        // Update position based on how much was consumed
2079        let consumed = self.data.len() - start_pos - buf.remaining();
2080        self.position = start_pos + consumed;
2081
2082        Ok(Some(token))
2083    }
2084
2085    /// Skip the current token without fully parsing it.
2086    ///
2087    /// This is useful for skipping unknown or uninteresting tokens.
2088    pub fn skip_token(&mut self) -> Result<(), ProtocolError> {
2089        if !self.has_remaining() {
2090            return Ok(());
2091        }
2092
2093        let token_type_byte = self.data[self.position];
2094        let token_type = TokenType::from_u8(token_type_byte);
2095
2096        // Calculate how many bytes to skip based on token type
2097        let skip_amount = match token_type {
2098            // Fixed-size tokens
2099            Some(TokenType::Done) | Some(TokenType::DoneProc) | Some(TokenType::DoneInProc) => {
2100                1 + Done::SIZE // token type + 12 bytes
2101            }
2102            Some(TokenType::ReturnStatus) => {
2103                1 + 4 // token type + 4 bytes
2104            }
2105            // Variable-length tokens with 2-byte length prefix
2106            Some(TokenType::Error)
2107            | Some(TokenType::Info)
2108            | Some(TokenType::LoginAck)
2109            | Some(TokenType::EnvChange)
2110            | Some(TokenType::Order)
2111            | Some(TokenType::Sspi)
2112            | Some(TokenType::ColInfo)
2113            | Some(TokenType::TabName)
2114            | Some(TokenType::Offset)
2115            | Some(TokenType::ReturnValue) => {
2116                if self.remaining() < 3 {
2117                    return Err(ProtocolError::UnexpectedEof);
2118                }
2119                let length = u16::from_le_bytes([
2120                    self.data[self.position + 1],
2121                    self.data[self.position + 2],
2122                ]) as usize;
2123                1 + 2 + length // token type + length prefix + data
2124            }
2125            // Tokens with 4-byte length prefix
2126            Some(TokenType::SessionState) | Some(TokenType::FedAuthInfo) => {
2127                if self.remaining() < 5 {
2128                    return Err(ProtocolError::UnexpectedEof);
2129                }
2130                let length = u32::from_le_bytes([
2131                    self.data[self.position + 1],
2132                    self.data[self.position + 2],
2133                    self.data[self.position + 3],
2134                    self.data[self.position + 4],
2135                ]) as usize;
2136                1 + 4 + length
2137            }
2138            // FeatureExtAck has no length prefix - must parse
2139            Some(TokenType::FeatureExtAck) => {
2140                // Parse to find end
2141                let mut buf = &self.data[self.position + 1..];
2142                let _ = FeatureExtAck::decode(&mut buf)?;
2143                self.data.len() - self.position - buf.remaining()
2144            }
2145            // ColMetaData, Row, NbcRow require context and can't be easily skipped
2146            Some(TokenType::ColMetaData) | Some(TokenType::Row) | Some(TokenType::NbcRow) => {
2147                return Err(ProtocolError::InvalidTokenType(token_type_byte));
2148            }
2149            None => {
2150                return Err(ProtocolError::InvalidTokenType(token_type_byte));
2151            }
2152        };
2153
2154        if self.remaining() < skip_amount {
2155            return Err(ProtocolError::UnexpectedEof);
2156        }
2157
2158        self.position += skip_amount;
2159        Ok(())
2160    }
2161
2162    /// Get the current position in the buffer.
2163    #[must_use]
2164    pub fn position(&self) -> usize {
2165        self.position
2166    }
2167
2168    /// Reset the parser to the beginning.
2169    pub fn reset(&mut self) {
2170        self.position = 0;
2171    }
2172}
2173
2174// =============================================================================
2175// no_std support
2176// =============================================================================
2177
2178#[cfg(not(feature = "std"))]
2179use alloc::string::String;
2180#[cfg(not(feature = "std"))]
2181use alloc::vec::Vec;
2182
2183// =============================================================================
2184// Tests
2185// =============================================================================
2186
2187#[cfg(test)]
2188#[allow(clippy::unwrap_used, clippy::panic)]
2189mod tests {
2190    use super::*;
2191    use bytes::BytesMut;
2192
2193    #[test]
2194    fn test_done_roundtrip() {
2195        let done = Done {
2196            status: DoneStatus {
2197                more: false,
2198                error: false,
2199                in_xact: false,
2200                count: true,
2201                attn: false,
2202                srverror: false,
2203            },
2204            cur_cmd: 193, // SELECT
2205            row_count: 42,
2206        };
2207
2208        let mut buf = BytesMut::new();
2209        done.encode(&mut buf);
2210
2211        // Skip the token type byte
2212        let mut cursor = &buf[1..];
2213        let decoded = Done::decode(&mut cursor).unwrap();
2214
2215        assert_eq!(decoded.status.count, done.status.count);
2216        assert_eq!(decoded.cur_cmd, done.cur_cmd);
2217        assert_eq!(decoded.row_count, done.row_count);
2218    }
2219
2220    #[test]
2221    fn test_done_status_bits() {
2222        let status = DoneStatus {
2223            more: true,
2224            error: true,
2225            in_xact: true,
2226            count: true,
2227            attn: false,
2228            srverror: false,
2229        };
2230
2231        let bits = status.to_bits();
2232        let restored = DoneStatus::from_bits(bits);
2233
2234        assert_eq!(status.more, restored.more);
2235        assert_eq!(status.error, restored.error);
2236        assert_eq!(status.in_xact, restored.in_xact);
2237        assert_eq!(status.count, restored.count);
2238    }
2239
2240    #[test]
2241    fn test_token_parser_done() {
2242        // DONE token: type (1) + status (2) + curcmd (2) + rowcount (8)
2243        let data = Bytes::from_static(&[
2244            0xFD, // DONE token type
2245            0x10, 0x00, // status: DONE_COUNT
2246            0xC1, 0x00, // cur_cmd: 193 (SELECT)
2247            0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row_count: 5
2248        ]);
2249
2250        let mut parser = TokenParser::new(data);
2251        let token = parser.next_token().unwrap().unwrap();
2252
2253        match token {
2254            Token::Done(done) => {
2255                assert!(done.status.count);
2256                assert!(!done.status.more);
2257                assert_eq!(done.cur_cmd, 193);
2258                assert_eq!(done.row_count, 5);
2259            }
2260            _ => panic!("Expected Done token"),
2261        }
2262
2263        // No more tokens
2264        assert!(parser.next_token().unwrap().is_none());
2265    }
2266
2267    #[test]
2268    fn test_env_change_type_from_u8() {
2269        assert_eq!(EnvChangeType::from_u8(1), Some(EnvChangeType::Database));
2270        assert_eq!(EnvChangeType::from_u8(20), Some(EnvChangeType::Routing));
2271        assert_eq!(EnvChangeType::from_u8(100), None);
2272    }
2273
2274    #[test]
2275    fn test_colmetadata_no_columns() {
2276        // No metadata marker (0xFFFF)
2277        let data = Bytes::from_static(&[0xFF, 0xFF]);
2278        let mut cursor: &[u8] = &data;
2279        let meta = ColMetaData::decode(&mut cursor).unwrap();
2280        assert!(meta.is_empty());
2281        assert_eq!(meta.column_count(), 0);
2282    }
2283
2284    #[test]
2285    fn test_colmetadata_single_int_column() {
2286        // COLMETADATA with 1 INT column
2287        // Format: column_count (2) + [user_type (4) + flags (2) + type_id (1) + name (b_varchar)]
2288        let mut data = BytesMut::new();
2289        data.extend_from_slice(&[0x01, 0x00]); // 1 column
2290        data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // user_type = 0
2291        data.extend_from_slice(&[0x01, 0x00]); // flags (nullable)
2292        data.extend_from_slice(&[0x38]); // TypeId::Int4
2293        // Column name "id" as B_VARCHAR (1 byte length + UTF-16LE)
2294        data.extend_from_slice(&[0x02]); // 2 characters
2295        data.extend_from_slice(&[b'i', 0x00, b'd', 0x00]); // "id" in UTF-16LE
2296
2297        let mut cursor: &[u8] = &data;
2298        let meta = ColMetaData::decode(&mut cursor).unwrap();
2299
2300        assert_eq!(meta.column_count(), 1);
2301        assert_eq!(meta.columns[0].name, "id");
2302        assert_eq!(meta.columns[0].type_id, TypeId::Int4);
2303        assert!(meta.columns[0].is_nullable());
2304    }
2305
2306    #[test]
2307    fn test_colmetadata_nvarchar_column() {
2308        // COLMETADATA with 1 NVARCHAR(50) column
2309        let mut data = BytesMut::new();
2310        data.extend_from_slice(&[0x01, 0x00]); // 1 column
2311        data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // user_type = 0
2312        data.extend_from_slice(&[0x01, 0x00]); // flags (nullable)
2313        data.extend_from_slice(&[0xE7]); // TypeId::NVarChar
2314        // Type info: max_length (2 bytes) + collation (5 bytes)
2315        data.extend_from_slice(&[0x64, 0x00]); // max_length = 100 (50 chars * 2)
2316        data.extend_from_slice(&[0x09, 0x04, 0xD0, 0x00, 0x34]); // collation
2317        // Column name "name"
2318        data.extend_from_slice(&[0x04]); // 4 characters
2319        data.extend_from_slice(&[b'n', 0x00, b'a', 0x00, b'm', 0x00, b'e', 0x00]);
2320
2321        let mut cursor: &[u8] = &data;
2322        let meta = ColMetaData::decode(&mut cursor).unwrap();
2323
2324        assert_eq!(meta.column_count(), 1);
2325        assert_eq!(meta.columns[0].name, "name");
2326        assert_eq!(meta.columns[0].type_id, TypeId::NVarChar);
2327        assert_eq!(meta.columns[0].type_info.max_length, Some(100));
2328        assert!(meta.columns[0].type_info.collation.is_some());
2329    }
2330
2331    #[test]
2332    fn test_raw_row_decode_int() {
2333        // Create metadata for a single INT column
2334        let metadata = ColMetaData {
2335            columns: vec![ColumnData {
2336                name: "id".to_string(),
2337                type_id: TypeId::Int4,
2338                col_type: 0x38,
2339                flags: 0,
2340                user_type: 0,
2341                type_info: TypeInfo::default(),
2342            }],
2343        };
2344
2345        // Row data: just 4 bytes for the int value 42
2346        let data = Bytes::from_static(&[0x2A, 0x00, 0x00, 0x00]); // 42 in little-endian
2347        let mut cursor: &[u8] = &data;
2348        let row = RawRow::decode(&mut cursor, &metadata).unwrap();
2349
2350        // The raw data should contain the 4 bytes
2351        assert_eq!(row.data.len(), 4);
2352        assert_eq!(&row.data[..], &[0x2A, 0x00, 0x00, 0x00]);
2353    }
2354
2355    #[test]
2356    fn test_raw_row_decode_nullable_int() {
2357        // Create metadata for a nullable INT column (IntN)
2358        let metadata = ColMetaData {
2359            columns: vec![ColumnData {
2360                name: "id".to_string(),
2361                type_id: TypeId::IntN,
2362                col_type: 0x26,
2363                flags: 0x01, // nullable
2364                user_type: 0,
2365                type_info: TypeInfo {
2366                    max_length: Some(4),
2367                    ..Default::default()
2368                },
2369            }],
2370        };
2371
2372        // Row data with value: 1 byte length + 4 bytes value
2373        let data = Bytes::from_static(&[0x04, 0x2A, 0x00, 0x00, 0x00]); // length=4, value=42
2374        let mut cursor: &[u8] = &data;
2375        let row = RawRow::decode(&mut cursor, &metadata).unwrap();
2376
2377        assert_eq!(row.data.len(), 5);
2378        assert_eq!(row.data[0], 4); // length
2379        assert_eq!(&row.data[1..], &[0x2A, 0x00, 0x00, 0x00]);
2380    }
2381
2382    #[test]
2383    fn test_raw_row_decode_null_value() {
2384        // Create metadata for a nullable INT column (IntN)
2385        let metadata = ColMetaData {
2386            columns: vec![ColumnData {
2387                name: "id".to_string(),
2388                type_id: TypeId::IntN,
2389                col_type: 0x26,
2390                flags: 0x01, // nullable
2391                user_type: 0,
2392                type_info: TypeInfo {
2393                    max_length: Some(4),
2394                    ..Default::default()
2395                },
2396            }],
2397        };
2398
2399        // NULL value: length = 0xFF (for bytelen types)
2400        let data = Bytes::from_static(&[0xFF]);
2401        let mut cursor: &[u8] = &data;
2402        let row = RawRow::decode(&mut cursor, &metadata).unwrap();
2403
2404        assert_eq!(row.data.len(), 1);
2405        assert_eq!(row.data[0], 0xFF); // NULL marker
2406    }
2407
2408    #[test]
2409    fn test_nbcrow_null_bitmap() {
2410        let row = NbcRow {
2411            null_bitmap: vec![0b00000101], // columns 0 and 2 are NULL
2412            data: Bytes::new(),
2413        };
2414
2415        assert!(row.is_null(0));
2416        assert!(!row.is_null(1));
2417        assert!(row.is_null(2));
2418        assert!(!row.is_null(3));
2419    }
2420
2421    #[test]
2422    fn test_token_parser_colmetadata() {
2423        // Build a COLMETADATA token with 1 INT column
2424        let mut data = BytesMut::new();
2425        data.extend_from_slice(&[0x81]); // COLMETADATA token type
2426        data.extend_from_slice(&[0x01, 0x00]); // 1 column
2427        data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // user_type = 0
2428        data.extend_from_slice(&[0x01, 0x00]); // flags (nullable)
2429        data.extend_from_slice(&[0x38]); // TypeId::Int4
2430        data.extend_from_slice(&[0x02]); // column name length
2431        data.extend_from_slice(&[b'i', 0x00, b'd', 0x00]); // "id"
2432
2433        let mut parser = TokenParser::new(data.freeze());
2434        let token = parser.next_token().unwrap().unwrap();
2435
2436        match token {
2437            Token::ColMetaData(meta) => {
2438                assert_eq!(meta.column_count(), 1);
2439                assert_eq!(meta.columns[0].name, "id");
2440                assert_eq!(meta.columns[0].type_id, TypeId::Int4);
2441            }
2442            _ => panic!("Expected ColMetaData token"),
2443        }
2444    }
2445
2446    #[test]
2447    fn test_token_parser_row_with_metadata() {
2448        // Build metadata
2449        let metadata = ColMetaData {
2450            columns: vec![ColumnData {
2451                name: "id".to_string(),
2452                type_id: TypeId::Int4,
2453                col_type: 0x38,
2454                flags: 0,
2455                user_type: 0,
2456                type_info: TypeInfo::default(),
2457            }],
2458        };
2459
2460        // Build ROW token
2461        let mut data = BytesMut::new();
2462        data.extend_from_slice(&[0xD1]); // ROW token type
2463        data.extend_from_slice(&[0x2A, 0x00, 0x00, 0x00]); // value = 42
2464
2465        let mut parser = TokenParser::new(data.freeze());
2466        let token = parser
2467            .next_token_with_metadata(Some(&metadata))
2468            .unwrap()
2469            .unwrap();
2470
2471        match token {
2472            Token::Row(row) => {
2473                assert_eq!(row.data.len(), 4);
2474            }
2475            _ => panic!("Expected Row token"),
2476        }
2477    }
2478
2479    #[test]
2480    fn test_token_parser_row_without_metadata_fails() {
2481        // Build ROW token
2482        let mut data = BytesMut::new();
2483        data.extend_from_slice(&[0xD1]); // ROW token type
2484        data.extend_from_slice(&[0x2A, 0x00, 0x00, 0x00]); // value = 42
2485
2486        let mut parser = TokenParser::new(data.freeze());
2487        let result = parser.next_token(); // No metadata provided
2488
2489        assert!(result.is_err());
2490    }
2491
2492    #[test]
2493    fn test_token_parser_peek() {
2494        let data = Bytes::from_static(&[
2495            0xFD, // DONE token type
2496            0x10, 0x00, // status
2497            0xC1, 0x00, // cur_cmd
2498            0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row_count
2499        ]);
2500
2501        let parser = TokenParser::new(data);
2502        assert_eq!(parser.peek_token_type(), Some(TokenType::Done));
2503    }
2504
2505    #[test]
2506    fn test_column_data_fixed_size() {
2507        let col = ColumnData {
2508            name: String::new(),
2509            type_id: TypeId::Int4,
2510            col_type: 0x38,
2511            flags: 0,
2512            user_type: 0,
2513            type_info: TypeInfo::default(),
2514        };
2515        assert_eq!(col.fixed_size(), Some(4));
2516
2517        let col2 = ColumnData {
2518            name: String::new(),
2519            type_id: TypeId::NVarChar,
2520            col_type: 0xE7,
2521            flags: 0,
2522            user_type: 0,
2523            type_info: TypeInfo::default(),
2524        };
2525        assert_eq!(col2.fixed_size(), None);
2526    }
2527}