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
918            TypeId::BigVarChar | TypeId::BigChar | TypeId::BigVarBinary | TypeId::BigBinary => {
919                Self::decode_ushortlen_type(src, dst)?;
920            }
921
922            // Unicode strings (2-byte length in bytes, not characters)
923            TypeId::NChar | TypeId::NVarChar => {
924                Self::decode_ushortlen_type(src, dst)?;
925            }
926
927            // Time types with scale
928            TypeId::Time | TypeId::DateTime2 | TypeId::DateTimeOffset => {
929                Self::decode_bytelen_type(src, dst)?;
930            }
931
932            // PLP (Partially Length Prefixed) types
933            TypeId::Text | TypeId::NText | TypeId::Image | TypeId::Xml => {
934                Self::decode_plp_type(src, dst)?;
935            }
936
937            // Complex types
938            TypeId::Variant => {
939                Self::decode_intlen_type(src, dst)?;
940            }
941
942            TypeId::Udt => {
943                // UDT uses PLP encoding
944                Self::decode_plp_type(src, dst)?;
945            }
946
947            TypeId::Tvp => {
948                // TVP not supported in row data
949                return Err(ProtocolError::InvalidTokenType(col.col_type));
950            }
951        }
952
953        Ok(())
954    }
955
956    /// Decode a 1-byte length-prefixed value.
957    fn decode_bytelen_type(
958        src: &mut impl Buf,
959        dst: &mut bytes::BytesMut,
960    ) -> Result<(), ProtocolError> {
961        if src.remaining() < 1 {
962            return Err(ProtocolError::UnexpectedEof);
963        }
964        let len = src.get_u8() as usize;
965        if len == 0xFF {
966            // NULL value - store as zero-length with NULL marker
967            dst.extend_from_slice(&[0xFF]);
968        } else if len == 0 {
969            // Empty value
970            dst.extend_from_slice(&[0x00]);
971        } else {
972            if src.remaining() < len {
973                return Err(ProtocolError::UnexpectedEof);
974            }
975            dst.extend_from_slice(&[len as u8]);
976            for _ in 0..len {
977                dst.extend_from_slice(&[src.get_u8()]);
978            }
979        }
980        Ok(())
981    }
982
983    /// Decode a 2-byte length-prefixed value.
984    fn decode_ushortlen_type(
985        src: &mut impl Buf,
986        dst: &mut bytes::BytesMut,
987    ) -> Result<(), ProtocolError> {
988        if src.remaining() < 2 {
989            return Err(ProtocolError::UnexpectedEof);
990        }
991        let len = src.get_u16_le() as usize;
992        if len == 0xFFFF {
993            // NULL value
994            dst.extend_from_slice(&0xFFFFu16.to_le_bytes());
995        } else if len == 0 {
996            // Empty value
997            dst.extend_from_slice(&0u16.to_le_bytes());
998        } else {
999            if src.remaining() < len {
1000                return Err(ProtocolError::UnexpectedEof);
1001            }
1002            dst.extend_from_slice(&(len as u16).to_le_bytes());
1003            for _ in 0..len {
1004                dst.extend_from_slice(&[src.get_u8()]);
1005            }
1006        }
1007        Ok(())
1008    }
1009
1010    /// Decode a 4-byte length-prefixed value.
1011    fn decode_intlen_type(
1012        src: &mut impl Buf,
1013        dst: &mut bytes::BytesMut,
1014    ) -> Result<(), ProtocolError> {
1015        if src.remaining() < 4 {
1016            return Err(ProtocolError::UnexpectedEof);
1017        }
1018        let len = src.get_u32_le() as usize;
1019        if len == 0xFFFFFFFF {
1020            // NULL value
1021            dst.extend_from_slice(&0xFFFFFFFFu32.to_le_bytes());
1022        } else if len == 0 {
1023            // Empty value
1024            dst.extend_from_slice(&0u32.to_le_bytes());
1025        } else {
1026            if src.remaining() < len {
1027                return Err(ProtocolError::UnexpectedEof);
1028            }
1029            dst.extend_from_slice(&(len as u32).to_le_bytes());
1030            for _ in 0..len {
1031                dst.extend_from_slice(&[src.get_u8()]);
1032            }
1033        }
1034        Ok(())
1035    }
1036
1037    /// Decode a PLP (Partially Length-Prefixed) value.
1038    ///
1039    /// PLP format:
1040    /// - 8 bytes: total length (0xFFFFFFFFFFFFFFFE = unknown, 0xFFFFFFFFFFFFFFFF = NULL)
1041    /// - If not NULL: chunks of (4 byte chunk length + data) until chunk length = 0
1042    fn decode_plp_type(src: &mut impl Buf, dst: &mut bytes::BytesMut) -> Result<(), ProtocolError> {
1043        if src.remaining() < 8 {
1044            return Err(ProtocolError::UnexpectedEof);
1045        }
1046
1047        let total_len = src.get_u64_le();
1048
1049        // Store the total length marker
1050        dst.extend_from_slice(&total_len.to_le_bytes());
1051
1052        if total_len == 0xFFFFFFFFFFFFFFFF {
1053            // NULL value - no more data
1054            return Ok(());
1055        }
1056
1057        // Read chunks until terminator
1058        loop {
1059            if src.remaining() < 4 {
1060                return Err(ProtocolError::UnexpectedEof);
1061            }
1062            let chunk_len = src.get_u32_le() as usize;
1063            dst.extend_from_slice(&(chunk_len as u32).to_le_bytes());
1064
1065            if chunk_len == 0 {
1066                // End of PLP data
1067                break;
1068            }
1069
1070            if src.remaining() < chunk_len {
1071                return Err(ProtocolError::UnexpectedEof);
1072            }
1073
1074            for _ in 0..chunk_len {
1075                dst.extend_from_slice(&[src.get_u8()]);
1076            }
1077        }
1078
1079        Ok(())
1080    }
1081}
1082
1083// =============================================================================
1084// NbcRow Parsing Implementation
1085// =============================================================================
1086
1087impl NbcRow {
1088    /// Decode an NBCROW token from bytes.
1089    ///
1090    /// NBCROW (Null Bitmap Compressed Row) stores a bitmap indicating which
1091    /// columns are NULL, followed by only the non-NULL values.
1092    pub fn decode(src: &mut impl Buf, metadata: &ColMetaData) -> Result<Self, ProtocolError> {
1093        let col_count = metadata.columns.len();
1094        let bitmap_len = (col_count + 7) / 8;
1095
1096        if src.remaining() < bitmap_len {
1097            return Err(ProtocolError::UnexpectedEof);
1098        }
1099
1100        // Read null bitmap
1101        let mut null_bitmap = vec![0u8; bitmap_len];
1102        for byte in &mut null_bitmap {
1103            *byte = src.get_u8();
1104        }
1105
1106        // Read non-null values
1107        let mut data = bytes::BytesMut::new();
1108
1109        for (i, col) in metadata.columns.iter().enumerate() {
1110            let byte_idx = i / 8;
1111            let bit_idx = i % 8;
1112            let is_null = (null_bitmap[byte_idx] & (1 << bit_idx)) != 0;
1113
1114            if !is_null {
1115                // Read the value - for NBCROW, we read without the length prefix
1116                // for fixed-length types, and with length prefix for variable types
1117                RawRow::decode_column_value(src, col, &mut data)?;
1118            }
1119        }
1120
1121        Ok(Self {
1122            null_bitmap,
1123            data: data.freeze(),
1124        })
1125    }
1126
1127    /// Check if a column at the given index is NULL.
1128    #[must_use]
1129    pub fn is_null(&self, column_index: usize) -> bool {
1130        let byte_idx = column_index / 8;
1131        let bit_idx = column_index % 8;
1132        if byte_idx < self.null_bitmap.len() {
1133            (self.null_bitmap[byte_idx] & (1 << bit_idx)) != 0
1134        } else {
1135            true // Out of bounds = NULL
1136        }
1137    }
1138}
1139
1140// =============================================================================
1141// ReturnValue Parsing Implementation
1142// =============================================================================
1143
1144impl ReturnValue {
1145    /// Decode a RETURNVALUE token from bytes.
1146    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1147        // Length (2 bytes)
1148        if src.remaining() < 2 {
1149            return Err(ProtocolError::UnexpectedEof);
1150        }
1151        let _length = src.get_u16_le();
1152
1153        // Parameter ordinal (2 bytes)
1154        if src.remaining() < 2 {
1155            return Err(ProtocolError::UnexpectedEof);
1156        }
1157        let param_ordinal = src.get_u16_le();
1158
1159        // Parameter name (B_VARCHAR)
1160        let param_name = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1161
1162        // Status (1 byte)
1163        if src.remaining() < 1 {
1164            return Err(ProtocolError::UnexpectedEof);
1165        }
1166        let status = src.get_u8();
1167
1168        // User type (4 bytes) + flags (2 bytes) + type id (1 byte)
1169        if src.remaining() < 7 {
1170            return Err(ProtocolError::UnexpectedEof);
1171        }
1172        let user_type = src.get_u32_le();
1173        let flags = src.get_u16_le();
1174        let col_type = src.get_u8();
1175
1176        let type_id = TypeId::from_u8(col_type).unwrap_or(TypeId::Null);
1177
1178        // Parse type info
1179        let type_info = ColMetaData::decode_type_info(src, type_id, col_type)?;
1180
1181        // Read the value data
1182        let mut value_buf = bytes::BytesMut::new();
1183
1184        // Create a temporary column for value parsing
1185        let temp_col = ColumnData {
1186            name: String::new(),
1187            type_id,
1188            col_type,
1189            flags,
1190            user_type,
1191            type_info: type_info.clone(),
1192        };
1193
1194        RawRow::decode_column_value(src, &temp_col, &mut value_buf)?;
1195
1196        Ok(Self {
1197            param_ordinal,
1198            param_name,
1199            status,
1200            user_type,
1201            flags,
1202            type_info,
1203            value: value_buf.freeze(),
1204        })
1205    }
1206}
1207
1208// =============================================================================
1209// SessionState Parsing Implementation
1210// =============================================================================
1211
1212impl SessionState {
1213    /// Decode a SESSIONSTATE token from bytes.
1214    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1215        if src.remaining() < 4 {
1216            return Err(ProtocolError::UnexpectedEof);
1217        }
1218
1219        let length = src.get_u32_le() as usize;
1220
1221        if src.remaining() < length {
1222            return Err(ProtocolError::IncompletePacket {
1223                expected: length,
1224                actual: src.remaining(),
1225            });
1226        }
1227
1228        let data = src.copy_to_bytes(length);
1229
1230        Ok(Self { data })
1231    }
1232}
1233
1234// =============================================================================
1235// Token Parsing Implementation
1236// =============================================================================
1237
1238/// Done token status flags bit positions.
1239mod done_status_bits {
1240    pub const DONE_MORE: u16 = 0x0001;
1241    pub const DONE_ERROR: u16 = 0x0002;
1242    pub const DONE_INXACT: u16 = 0x0004;
1243    pub const DONE_COUNT: u16 = 0x0010;
1244    pub const DONE_ATTN: u16 = 0x0020;
1245    pub const DONE_SRVERROR: u16 = 0x0100;
1246}
1247
1248impl DoneStatus {
1249    /// Parse done status from raw bits.
1250    #[must_use]
1251    pub fn from_bits(bits: u16) -> Self {
1252        use done_status_bits::*;
1253        Self {
1254            more: (bits & DONE_MORE) != 0,
1255            error: (bits & DONE_ERROR) != 0,
1256            in_xact: (bits & DONE_INXACT) != 0,
1257            count: (bits & DONE_COUNT) != 0,
1258            attn: (bits & DONE_ATTN) != 0,
1259            srverror: (bits & DONE_SRVERROR) != 0,
1260        }
1261    }
1262
1263    /// Convert to raw bits.
1264    #[must_use]
1265    pub fn to_bits(&self) -> u16 {
1266        use done_status_bits::*;
1267        let mut bits = 0u16;
1268        if self.more {
1269            bits |= DONE_MORE;
1270        }
1271        if self.error {
1272            bits |= DONE_ERROR;
1273        }
1274        if self.in_xact {
1275            bits |= DONE_INXACT;
1276        }
1277        if self.count {
1278            bits |= DONE_COUNT;
1279        }
1280        if self.attn {
1281            bits |= DONE_ATTN;
1282        }
1283        if self.srverror {
1284            bits |= DONE_SRVERROR;
1285        }
1286        bits
1287    }
1288}
1289
1290impl Done {
1291    /// Size of the DONE token in bytes (excluding token type byte).
1292    pub const SIZE: usize = 12; // 2 (status) + 2 (curcmd) + 8 (rowcount)
1293
1294    /// Decode a DONE token from bytes.
1295    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1296        if src.remaining() < Self::SIZE {
1297            return Err(ProtocolError::IncompletePacket {
1298                expected: Self::SIZE,
1299                actual: src.remaining(),
1300            });
1301        }
1302
1303        let status = DoneStatus::from_bits(src.get_u16_le());
1304        let cur_cmd = src.get_u16_le();
1305        let row_count = src.get_u64_le();
1306
1307        Ok(Self {
1308            status,
1309            cur_cmd,
1310            row_count,
1311        })
1312    }
1313
1314    /// Encode the DONE token to bytes.
1315    pub fn encode(&self, dst: &mut impl BufMut) {
1316        dst.put_u8(TokenType::Done as u8);
1317        dst.put_u16_le(self.status.to_bits());
1318        dst.put_u16_le(self.cur_cmd);
1319        dst.put_u64_le(self.row_count);
1320    }
1321
1322    /// Check if more results follow this DONE token.
1323    #[must_use]
1324    pub const fn has_more(&self) -> bool {
1325        self.status.more
1326    }
1327
1328    /// Check if an error occurred.
1329    #[must_use]
1330    pub const fn has_error(&self) -> bool {
1331        self.status.error
1332    }
1333
1334    /// Check if the row count is valid.
1335    #[must_use]
1336    pub const fn has_count(&self) -> bool {
1337        self.status.count
1338    }
1339}
1340
1341impl DoneProc {
1342    /// Size of the DONEPROC token in bytes (excluding token type byte).
1343    pub const SIZE: usize = 12;
1344
1345    /// Decode a DONEPROC token from bytes.
1346    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1347        if src.remaining() < Self::SIZE {
1348            return Err(ProtocolError::IncompletePacket {
1349                expected: Self::SIZE,
1350                actual: src.remaining(),
1351            });
1352        }
1353
1354        let status = DoneStatus::from_bits(src.get_u16_le());
1355        let cur_cmd = src.get_u16_le();
1356        let row_count = src.get_u64_le();
1357
1358        Ok(Self {
1359            status,
1360            cur_cmd,
1361            row_count,
1362        })
1363    }
1364
1365    /// Encode the DONEPROC token to bytes.
1366    pub fn encode(&self, dst: &mut impl BufMut) {
1367        dst.put_u8(TokenType::DoneProc as u8);
1368        dst.put_u16_le(self.status.to_bits());
1369        dst.put_u16_le(self.cur_cmd);
1370        dst.put_u64_le(self.row_count);
1371    }
1372}
1373
1374impl DoneInProc {
1375    /// Size of the DONEINPROC token in bytes (excluding token type byte).
1376    pub const SIZE: usize = 12;
1377
1378    /// Decode a DONEINPROC token from bytes.
1379    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1380        if src.remaining() < Self::SIZE {
1381            return Err(ProtocolError::IncompletePacket {
1382                expected: Self::SIZE,
1383                actual: src.remaining(),
1384            });
1385        }
1386
1387        let status = DoneStatus::from_bits(src.get_u16_le());
1388        let cur_cmd = src.get_u16_le();
1389        let row_count = src.get_u64_le();
1390
1391        Ok(Self {
1392            status,
1393            cur_cmd,
1394            row_count,
1395        })
1396    }
1397
1398    /// Encode the DONEINPROC token to bytes.
1399    pub fn encode(&self, dst: &mut impl BufMut) {
1400        dst.put_u8(TokenType::DoneInProc as u8);
1401        dst.put_u16_le(self.status.to_bits());
1402        dst.put_u16_le(self.cur_cmd);
1403        dst.put_u64_le(self.row_count);
1404    }
1405}
1406
1407impl ServerError {
1408    /// Decode an ERROR token from bytes.
1409    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1410        // ERROR token: length (2) + number (4) + state (1) + class (1) +
1411        //              message (us_varchar) + server (b_varchar) + procedure (b_varchar) + line (4)
1412        if src.remaining() < 2 {
1413            return Err(ProtocolError::UnexpectedEof);
1414        }
1415
1416        let _length = src.get_u16_le();
1417
1418        if src.remaining() < 6 {
1419            return Err(ProtocolError::UnexpectedEof);
1420        }
1421
1422        let number = src.get_i32_le();
1423        let state = src.get_u8();
1424        let class = src.get_u8();
1425
1426        let message = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1427        let server = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1428        let procedure = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1429
1430        if src.remaining() < 4 {
1431            return Err(ProtocolError::UnexpectedEof);
1432        }
1433        let line = src.get_i32_le();
1434
1435        Ok(Self {
1436            number,
1437            state,
1438            class,
1439            message,
1440            server,
1441            procedure,
1442            line,
1443        })
1444    }
1445
1446    /// Check if this is a fatal error (severity >= 20).
1447    #[must_use]
1448    pub const fn is_fatal(&self) -> bool {
1449        self.class >= 20
1450    }
1451
1452    /// Check if this error indicates the batch was aborted (severity >= 16).
1453    #[must_use]
1454    pub const fn is_batch_abort(&self) -> bool {
1455        self.class >= 16
1456    }
1457}
1458
1459impl ServerInfo {
1460    /// Decode an INFO token from bytes.
1461    ///
1462    /// INFO tokens have the same structure as ERROR tokens but with lower severity.
1463    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1464        if src.remaining() < 2 {
1465            return Err(ProtocolError::UnexpectedEof);
1466        }
1467
1468        let _length = src.get_u16_le();
1469
1470        if src.remaining() < 6 {
1471            return Err(ProtocolError::UnexpectedEof);
1472        }
1473
1474        let number = src.get_i32_le();
1475        let state = src.get_u8();
1476        let class = src.get_u8();
1477
1478        let message = read_us_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1479        let server = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1480        let procedure = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1481
1482        if src.remaining() < 4 {
1483            return Err(ProtocolError::UnexpectedEof);
1484        }
1485        let line = src.get_i32_le();
1486
1487        Ok(Self {
1488            number,
1489            state,
1490            class,
1491            message,
1492            server,
1493            procedure,
1494            line,
1495        })
1496    }
1497}
1498
1499impl LoginAck {
1500    /// Decode a LOGINACK token from bytes.
1501    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1502        // LOGINACK: length (2) + interface (1) + tds_version (4) + prog_name (b_varchar) + prog_version (4)
1503        if src.remaining() < 2 {
1504            return Err(ProtocolError::UnexpectedEof);
1505        }
1506
1507        let _length = src.get_u16_le();
1508
1509        if src.remaining() < 5 {
1510            return Err(ProtocolError::UnexpectedEof);
1511        }
1512
1513        let interface = src.get_u8();
1514        let tds_version = src.get_u32_le();
1515        let prog_name = read_b_varchar(src).ok_or(ProtocolError::UnexpectedEof)?;
1516
1517        if src.remaining() < 4 {
1518            return Err(ProtocolError::UnexpectedEof);
1519        }
1520        let prog_version = src.get_u32_le();
1521
1522        Ok(Self {
1523            interface,
1524            tds_version,
1525            prog_name,
1526            prog_version,
1527        })
1528    }
1529
1530    /// Get the TDS version as a `TdsVersion`.
1531    #[must_use]
1532    pub fn tds_version(&self) -> crate::version::TdsVersion {
1533        crate::version::TdsVersion::new(self.tds_version)
1534    }
1535}
1536
1537impl EnvChangeType {
1538    /// Create from raw byte value.
1539    pub fn from_u8(value: u8) -> Option<Self> {
1540        match value {
1541            1 => Some(Self::Database),
1542            2 => Some(Self::Language),
1543            3 => Some(Self::CharacterSet),
1544            4 => Some(Self::PacketSize),
1545            5 => Some(Self::UnicodeSortingLocalId),
1546            6 => Some(Self::UnicodeComparisonFlags),
1547            7 => Some(Self::SqlCollation),
1548            8 => Some(Self::BeginTransaction),
1549            9 => Some(Self::CommitTransaction),
1550            10 => Some(Self::RollbackTransaction),
1551            11 => Some(Self::EnlistDtcTransaction),
1552            12 => Some(Self::DefectTransaction),
1553            13 => Some(Self::RealTimeLogShipping),
1554            15 => Some(Self::PromoteTransaction),
1555            16 => Some(Self::TransactionManagerAddress),
1556            17 => Some(Self::TransactionEnded),
1557            18 => Some(Self::ResetConnectionCompletionAck),
1558            19 => Some(Self::UserInstanceStarted),
1559            20 => Some(Self::Routing),
1560            _ => None,
1561        }
1562    }
1563}
1564
1565impl EnvChange {
1566    /// Decode an ENVCHANGE token from bytes.
1567    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1568        if src.remaining() < 3 {
1569            return Err(ProtocolError::UnexpectedEof);
1570        }
1571
1572        let length = src.get_u16_le() as usize;
1573        if src.remaining() < length {
1574            return Err(ProtocolError::IncompletePacket {
1575                expected: length,
1576                actual: src.remaining(),
1577            });
1578        }
1579
1580        let env_type_byte = src.get_u8();
1581        let env_type = EnvChangeType::from_u8(env_type_byte)
1582            .ok_or(ProtocolError::InvalidTokenType(env_type_byte))?;
1583
1584        let (new_value, old_value) = match env_type {
1585            EnvChangeType::Routing => {
1586                // Routing has special format
1587                let new_value = Self::decode_routing_value(src)?;
1588                let old_value = EnvChangeValue::Binary(Bytes::new());
1589                (new_value, old_value)
1590            }
1591            EnvChangeType::BeginTransaction
1592            | EnvChangeType::CommitTransaction
1593            | EnvChangeType::RollbackTransaction
1594            | EnvChangeType::EnlistDtcTransaction
1595            | EnvChangeType::SqlCollation => {
1596                // These use binary format per MS-TDS spec:
1597                // - Transaction tokens: transaction descriptor (8 bytes)
1598                // - SqlCollation: collation info (5 bytes: LCID + sort flags)
1599                let new_len = src.get_u8() as usize;
1600                let new_value = if new_len > 0 && src.remaining() >= new_len {
1601                    EnvChangeValue::Binary(src.copy_to_bytes(new_len))
1602                } else {
1603                    EnvChangeValue::Binary(Bytes::new())
1604                };
1605
1606                let old_len = src.get_u8() as usize;
1607                let old_value = if old_len > 0 && src.remaining() >= old_len {
1608                    EnvChangeValue::Binary(src.copy_to_bytes(old_len))
1609                } else {
1610                    EnvChangeValue::Binary(Bytes::new())
1611                };
1612
1613                (new_value, old_value)
1614            }
1615            _ => {
1616                // String format for most env changes
1617                let new_value = read_b_varchar(src)
1618                    .map(EnvChangeValue::String)
1619                    .unwrap_or(EnvChangeValue::String(String::new()));
1620
1621                let old_value = read_b_varchar(src)
1622                    .map(EnvChangeValue::String)
1623                    .unwrap_or(EnvChangeValue::String(String::new()));
1624
1625                (new_value, old_value)
1626            }
1627        };
1628
1629        Ok(Self {
1630            env_type,
1631            new_value,
1632            old_value,
1633        })
1634    }
1635
1636    fn decode_routing_value(src: &mut impl Buf) -> Result<EnvChangeValue, ProtocolError> {
1637        // Routing format: length (2) + protocol (1) + port (2) + server_len (2) + server (utf16)
1638        if src.remaining() < 2 {
1639            return Err(ProtocolError::UnexpectedEof);
1640        }
1641
1642        let _routing_len = src.get_u16_le();
1643
1644        if src.remaining() < 5 {
1645            return Err(ProtocolError::UnexpectedEof);
1646        }
1647
1648        let _protocol = src.get_u8();
1649        let port = src.get_u16_le();
1650        let server_len = src.get_u16_le() as usize;
1651
1652        // Read UTF-16LE server name
1653        if src.remaining() < server_len * 2 {
1654            return Err(ProtocolError::UnexpectedEof);
1655        }
1656
1657        let mut chars = Vec::with_capacity(server_len);
1658        for _ in 0..server_len {
1659            chars.push(src.get_u16_le());
1660        }
1661
1662        let host = String::from_utf16(&chars).map_err(|_| {
1663            ProtocolError::StringEncoding(
1664                #[cfg(feature = "std")]
1665                "invalid UTF-16 in routing hostname".to_string(),
1666                #[cfg(not(feature = "std"))]
1667                "invalid UTF-16 in routing hostname",
1668            )
1669        })?;
1670
1671        Ok(EnvChangeValue::Routing { host, port })
1672    }
1673
1674    /// Check if this is a routing redirect.
1675    #[must_use]
1676    pub fn is_routing(&self) -> bool {
1677        self.env_type == EnvChangeType::Routing
1678    }
1679
1680    /// Get routing information if this is a routing change.
1681    #[must_use]
1682    pub fn routing_info(&self) -> Option<(&str, u16)> {
1683        if let EnvChangeValue::Routing { host, port } = &self.new_value {
1684            Some((host, *port))
1685        } else {
1686            None
1687        }
1688    }
1689
1690    /// Get the new database name if this is a database change.
1691    #[must_use]
1692    pub fn new_database(&self) -> Option<&str> {
1693        if self.env_type == EnvChangeType::Database {
1694            if let EnvChangeValue::String(s) = &self.new_value {
1695                return Some(s);
1696            }
1697        }
1698        None
1699    }
1700}
1701
1702impl Order {
1703    /// Decode an ORDER token from bytes.
1704    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1705        if src.remaining() < 2 {
1706            return Err(ProtocolError::UnexpectedEof);
1707        }
1708
1709        let length = src.get_u16_le() as usize;
1710        let column_count = length / 2;
1711
1712        if src.remaining() < length {
1713            return Err(ProtocolError::IncompletePacket {
1714                expected: length,
1715                actual: src.remaining(),
1716            });
1717        }
1718
1719        let mut columns = Vec::with_capacity(column_count);
1720        for _ in 0..column_count {
1721            columns.push(src.get_u16_le());
1722        }
1723
1724        Ok(Self { columns })
1725    }
1726}
1727
1728impl FeatureExtAck {
1729    /// Feature terminator byte.
1730    pub const TERMINATOR: u8 = 0xFF;
1731
1732    /// Decode a FEATUREEXTACK token from bytes.
1733    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1734        let mut features = Vec::new();
1735
1736        loop {
1737            if !src.has_remaining() {
1738                return Err(ProtocolError::UnexpectedEof);
1739            }
1740
1741            let feature_id = src.get_u8();
1742            if feature_id == Self::TERMINATOR {
1743                break;
1744            }
1745
1746            if src.remaining() < 4 {
1747                return Err(ProtocolError::UnexpectedEof);
1748            }
1749
1750            let data_len = src.get_u32_le() as usize;
1751
1752            if src.remaining() < data_len {
1753                return Err(ProtocolError::IncompletePacket {
1754                    expected: data_len,
1755                    actual: src.remaining(),
1756                });
1757            }
1758
1759            let data = src.copy_to_bytes(data_len);
1760            features.push(FeatureAck { feature_id, data });
1761        }
1762
1763        Ok(Self { features })
1764    }
1765}
1766
1767impl SspiToken {
1768    /// Decode an SSPI token from bytes.
1769    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1770        if src.remaining() < 2 {
1771            return Err(ProtocolError::UnexpectedEof);
1772        }
1773
1774        let length = src.get_u16_le() as usize;
1775
1776        if src.remaining() < length {
1777            return Err(ProtocolError::IncompletePacket {
1778                expected: length,
1779                actual: src.remaining(),
1780            });
1781        }
1782
1783        let data = src.copy_to_bytes(length);
1784        Ok(Self { data })
1785    }
1786}
1787
1788impl FedAuthInfo {
1789    /// Decode a FEDAUTHINFO token from bytes.
1790    pub fn decode(src: &mut impl Buf) -> Result<Self, ProtocolError> {
1791        if src.remaining() < 4 {
1792            return Err(ProtocolError::UnexpectedEof);
1793        }
1794
1795        let _length = src.get_u32_le();
1796
1797        if src.remaining() < 5 {
1798            return Err(ProtocolError::UnexpectedEof);
1799        }
1800
1801        let _count = src.get_u8();
1802
1803        // Read option data
1804        let mut sts_url = String::new();
1805        let mut spn = String::new();
1806
1807        // Parse info options until we have both
1808        while src.has_remaining() {
1809            if src.remaining() < 9 {
1810                break;
1811            }
1812
1813            let info_id = src.get_u8();
1814            let info_len = src.get_u32_le() as usize;
1815            let _info_offset = src.get_u32_le();
1816
1817            if src.remaining() < info_len {
1818                break;
1819            }
1820
1821            // Read UTF-16LE string
1822            let char_count = info_len / 2;
1823            let mut chars = Vec::with_capacity(char_count);
1824            for _ in 0..char_count {
1825                chars.push(src.get_u16_le());
1826            }
1827
1828            if let Ok(value) = String::from_utf16(&chars) {
1829                match info_id {
1830                    0x01 => spn = value,
1831                    0x02 => sts_url = value,
1832                    _ => {}
1833                }
1834            }
1835        }
1836
1837        Ok(Self { sts_url, spn })
1838    }
1839}
1840
1841// =============================================================================
1842// Token Parser
1843// =============================================================================
1844
1845/// Token stream parser.
1846///
1847/// Parses a stream of TDS tokens from a byte buffer.
1848///
1849/// # Basic vs Context-Aware Parsing
1850///
1851/// Some tokens (like `Done`, `Error`, `LoginAck`) can be parsed without context.
1852/// Use [`next_token()`](TokenParser::next_token) for these.
1853///
1854/// Other tokens (like `ColMetaData`, `Row`, `NbcRow`) require column metadata
1855/// to parse correctly. Use [`next_token_with_metadata()`](TokenParser::next_token_with_metadata)
1856/// for these.
1857///
1858/// # Example
1859///
1860/// ```rust,ignore
1861/// let mut parser = TokenParser::new(data);
1862/// let mut metadata = None;
1863///
1864/// while let Some(token) = parser.next_token_with_metadata(metadata.as_ref())? {
1865///     match token {
1866///         Token::ColMetaData(meta) => {
1867///             metadata = Some(meta);
1868///         }
1869///         Token::Row(row) => {
1870///             // Process row using metadata
1871///         }
1872///         Token::Done(done) => {
1873///             if !done.has_more() {
1874///                 break;
1875///             }
1876///         }
1877///         _ => {}
1878///     }
1879/// }
1880/// ```
1881pub struct TokenParser {
1882    data: Bytes,
1883    position: usize,
1884}
1885
1886impl TokenParser {
1887    /// Create a new token parser from bytes.
1888    #[must_use]
1889    pub fn new(data: Bytes) -> Self {
1890        Self { data, position: 0 }
1891    }
1892
1893    /// Get remaining bytes in the buffer.
1894    #[must_use]
1895    pub fn remaining(&self) -> usize {
1896        self.data.len().saturating_sub(self.position)
1897    }
1898
1899    /// Check if there are more bytes to parse.
1900    #[must_use]
1901    pub fn has_remaining(&self) -> bool {
1902        self.position < self.data.len()
1903    }
1904
1905    /// Peek at the next token type without consuming it.
1906    #[must_use]
1907    pub fn peek_token_type(&self) -> Option<TokenType> {
1908        if self.position < self.data.len() {
1909            TokenType::from_u8(self.data[self.position])
1910        } else {
1911            None
1912        }
1913    }
1914
1915    /// Parse the next token from the stream.
1916    ///
1917    /// This method can only parse context-independent tokens. For tokens that
1918    /// require column metadata (ColMetaData, Row, NbcRow), use
1919    /// [`next_token_with_metadata()`](TokenParser::next_token_with_metadata).
1920    ///
1921    /// Returns `None` if no more tokens are available.
1922    pub fn next_token(&mut self) -> Result<Option<Token>, ProtocolError> {
1923        self.next_token_with_metadata(None)
1924    }
1925
1926    /// Parse the next token with optional column metadata context.
1927    ///
1928    /// When `metadata` is provided, this method can parse Row and NbcRow tokens.
1929    /// Without metadata, those tokens will return an error.
1930    ///
1931    /// Returns `None` if no more tokens are available.
1932    pub fn next_token_with_metadata(
1933        &mut self,
1934        metadata: Option<&ColMetaData>,
1935    ) -> Result<Option<Token>, ProtocolError> {
1936        if !self.has_remaining() {
1937            return Ok(None);
1938        }
1939
1940        let mut buf = &self.data[self.position..];
1941        let start_pos = self.position;
1942
1943        let token_type_byte = buf.get_u8();
1944        let token_type = TokenType::from_u8(token_type_byte);
1945
1946        let token = match token_type {
1947            Some(TokenType::Done) => {
1948                let done = Done::decode(&mut buf)?;
1949                Token::Done(done)
1950            }
1951            Some(TokenType::DoneProc) => {
1952                let done = DoneProc::decode(&mut buf)?;
1953                Token::DoneProc(done)
1954            }
1955            Some(TokenType::DoneInProc) => {
1956                let done = DoneInProc::decode(&mut buf)?;
1957                Token::DoneInProc(done)
1958            }
1959            Some(TokenType::Error) => {
1960                let error = ServerError::decode(&mut buf)?;
1961                Token::Error(error)
1962            }
1963            Some(TokenType::Info) => {
1964                let info = ServerInfo::decode(&mut buf)?;
1965                Token::Info(info)
1966            }
1967            Some(TokenType::LoginAck) => {
1968                let login_ack = LoginAck::decode(&mut buf)?;
1969                Token::LoginAck(login_ack)
1970            }
1971            Some(TokenType::EnvChange) => {
1972                let env_change = EnvChange::decode(&mut buf)?;
1973                Token::EnvChange(env_change)
1974            }
1975            Some(TokenType::Order) => {
1976                let order = Order::decode(&mut buf)?;
1977                Token::Order(order)
1978            }
1979            Some(TokenType::FeatureExtAck) => {
1980                let ack = FeatureExtAck::decode(&mut buf)?;
1981                Token::FeatureExtAck(ack)
1982            }
1983            Some(TokenType::Sspi) => {
1984                let sspi = SspiToken::decode(&mut buf)?;
1985                Token::Sspi(sspi)
1986            }
1987            Some(TokenType::FedAuthInfo) => {
1988                let info = FedAuthInfo::decode(&mut buf)?;
1989                Token::FedAuthInfo(info)
1990            }
1991            Some(TokenType::ReturnStatus) => {
1992                if buf.remaining() < 4 {
1993                    return Err(ProtocolError::UnexpectedEof);
1994                }
1995                let status = buf.get_i32_le();
1996                Token::ReturnStatus(status)
1997            }
1998            Some(TokenType::ColMetaData) => {
1999                let col_meta = ColMetaData::decode(&mut buf)?;
2000                Token::ColMetaData(col_meta)
2001            }
2002            Some(TokenType::Row) => {
2003                let meta = metadata.ok_or_else(|| {
2004                    ProtocolError::StringEncoding(
2005                        #[cfg(feature = "std")]
2006                        "Row token requires column metadata".to_string(),
2007                        #[cfg(not(feature = "std"))]
2008                        "Row token requires column metadata",
2009                    )
2010                })?;
2011                let row = RawRow::decode(&mut buf, meta)?;
2012                Token::Row(row)
2013            }
2014            Some(TokenType::NbcRow) => {
2015                let meta = metadata.ok_or_else(|| {
2016                    ProtocolError::StringEncoding(
2017                        #[cfg(feature = "std")]
2018                        "NbcRow token requires column metadata".to_string(),
2019                        #[cfg(not(feature = "std"))]
2020                        "NbcRow token requires column metadata",
2021                    )
2022                })?;
2023                let row = NbcRow::decode(&mut buf, meta)?;
2024                Token::NbcRow(row)
2025            }
2026            Some(TokenType::ReturnValue) => {
2027                let ret_val = ReturnValue::decode(&mut buf)?;
2028                Token::ReturnValue(ret_val)
2029            }
2030            Some(TokenType::SessionState) => {
2031                let session = SessionState::decode(&mut buf)?;
2032                Token::SessionState(session)
2033            }
2034            Some(TokenType::ColInfo) | Some(TokenType::TabName) | Some(TokenType::Offset) => {
2035                // These tokens are rarely used and have complex formats.
2036                // Skip them by reading the length and advancing.
2037                if buf.remaining() < 2 {
2038                    return Err(ProtocolError::UnexpectedEof);
2039                }
2040                let length = buf.get_u16_le() as usize;
2041                if buf.remaining() < length {
2042                    return Err(ProtocolError::IncompletePacket {
2043                        expected: length,
2044                        actual: buf.remaining(),
2045                    });
2046                }
2047                // Skip the data
2048                buf.advance(length);
2049                // Recursively get the next token
2050                self.position = start_pos + (self.data.len() - start_pos - buf.remaining());
2051                return self.next_token_with_metadata(metadata);
2052            }
2053            None => {
2054                return Err(ProtocolError::InvalidTokenType(token_type_byte));
2055            }
2056        };
2057
2058        // Update position based on how much was consumed
2059        let consumed = self.data.len() - start_pos - buf.remaining();
2060        self.position = start_pos + consumed;
2061
2062        Ok(Some(token))
2063    }
2064
2065    /// Skip the current token without fully parsing it.
2066    ///
2067    /// This is useful for skipping unknown or uninteresting tokens.
2068    pub fn skip_token(&mut self) -> Result<(), ProtocolError> {
2069        if !self.has_remaining() {
2070            return Ok(());
2071        }
2072
2073        let token_type_byte = self.data[self.position];
2074        let token_type = TokenType::from_u8(token_type_byte);
2075
2076        // Calculate how many bytes to skip based on token type
2077        let skip_amount = match token_type {
2078            // Fixed-size tokens
2079            Some(TokenType::Done) | Some(TokenType::DoneProc) | Some(TokenType::DoneInProc) => {
2080                1 + Done::SIZE // token type + 12 bytes
2081            }
2082            Some(TokenType::ReturnStatus) => {
2083                1 + 4 // token type + 4 bytes
2084            }
2085            // Variable-length tokens with 2-byte length prefix
2086            Some(TokenType::Error)
2087            | Some(TokenType::Info)
2088            | Some(TokenType::LoginAck)
2089            | Some(TokenType::EnvChange)
2090            | Some(TokenType::Order)
2091            | Some(TokenType::Sspi)
2092            | Some(TokenType::ColInfo)
2093            | Some(TokenType::TabName)
2094            | Some(TokenType::Offset)
2095            | Some(TokenType::ReturnValue) => {
2096                if self.remaining() < 3 {
2097                    return Err(ProtocolError::UnexpectedEof);
2098                }
2099                let length = u16::from_le_bytes([
2100                    self.data[self.position + 1],
2101                    self.data[self.position + 2],
2102                ]) as usize;
2103                1 + 2 + length // token type + length prefix + data
2104            }
2105            // Tokens with 4-byte length prefix
2106            Some(TokenType::SessionState) | Some(TokenType::FedAuthInfo) => {
2107                if self.remaining() < 5 {
2108                    return Err(ProtocolError::UnexpectedEof);
2109                }
2110                let length = u32::from_le_bytes([
2111                    self.data[self.position + 1],
2112                    self.data[self.position + 2],
2113                    self.data[self.position + 3],
2114                    self.data[self.position + 4],
2115                ]) as usize;
2116                1 + 4 + length
2117            }
2118            // FeatureExtAck has no length prefix - must parse
2119            Some(TokenType::FeatureExtAck) => {
2120                // Parse to find end
2121                let mut buf = &self.data[self.position + 1..];
2122                let _ = FeatureExtAck::decode(&mut buf)?;
2123                self.data.len() - self.position - buf.remaining()
2124            }
2125            // ColMetaData, Row, NbcRow require context and can't be easily skipped
2126            Some(TokenType::ColMetaData) | Some(TokenType::Row) | Some(TokenType::NbcRow) => {
2127                return Err(ProtocolError::InvalidTokenType(token_type_byte));
2128            }
2129            None => {
2130                return Err(ProtocolError::InvalidTokenType(token_type_byte));
2131            }
2132        };
2133
2134        if self.remaining() < skip_amount {
2135            return Err(ProtocolError::UnexpectedEof);
2136        }
2137
2138        self.position += skip_amount;
2139        Ok(())
2140    }
2141
2142    /// Get the current position in the buffer.
2143    #[must_use]
2144    pub fn position(&self) -> usize {
2145        self.position
2146    }
2147
2148    /// Reset the parser to the beginning.
2149    pub fn reset(&mut self) {
2150        self.position = 0;
2151    }
2152}
2153
2154// =============================================================================
2155// no_std support
2156// =============================================================================
2157
2158#[cfg(not(feature = "std"))]
2159use alloc::string::String;
2160#[cfg(not(feature = "std"))]
2161use alloc::vec::Vec;
2162
2163// =============================================================================
2164// Tests
2165// =============================================================================
2166
2167#[cfg(test)]
2168#[allow(clippy::unwrap_used, clippy::panic)]
2169mod tests {
2170    use super::*;
2171    use bytes::BytesMut;
2172
2173    #[test]
2174    fn test_done_roundtrip() {
2175        let done = Done {
2176            status: DoneStatus {
2177                more: false,
2178                error: false,
2179                in_xact: false,
2180                count: true,
2181                attn: false,
2182                srverror: false,
2183            },
2184            cur_cmd: 193, // SELECT
2185            row_count: 42,
2186        };
2187
2188        let mut buf = BytesMut::new();
2189        done.encode(&mut buf);
2190
2191        // Skip the token type byte
2192        let mut cursor = &buf[1..];
2193        let decoded = Done::decode(&mut cursor).unwrap();
2194
2195        assert_eq!(decoded.status.count, done.status.count);
2196        assert_eq!(decoded.cur_cmd, done.cur_cmd);
2197        assert_eq!(decoded.row_count, done.row_count);
2198    }
2199
2200    #[test]
2201    fn test_done_status_bits() {
2202        let status = DoneStatus {
2203            more: true,
2204            error: true,
2205            in_xact: true,
2206            count: true,
2207            attn: false,
2208            srverror: false,
2209        };
2210
2211        let bits = status.to_bits();
2212        let restored = DoneStatus::from_bits(bits);
2213
2214        assert_eq!(status.more, restored.more);
2215        assert_eq!(status.error, restored.error);
2216        assert_eq!(status.in_xact, restored.in_xact);
2217        assert_eq!(status.count, restored.count);
2218    }
2219
2220    #[test]
2221    fn test_token_parser_done() {
2222        // DONE token: type (1) + status (2) + curcmd (2) + rowcount (8)
2223        let data = Bytes::from_static(&[
2224            0xFD, // DONE token type
2225            0x10, 0x00, // status: DONE_COUNT
2226            0xC1, 0x00, // cur_cmd: 193 (SELECT)
2227            0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row_count: 5
2228        ]);
2229
2230        let mut parser = TokenParser::new(data);
2231        let token = parser.next_token().unwrap().unwrap();
2232
2233        match token {
2234            Token::Done(done) => {
2235                assert!(done.status.count);
2236                assert!(!done.status.more);
2237                assert_eq!(done.cur_cmd, 193);
2238                assert_eq!(done.row_count, 5);
2239            }
2240            _ => panic!("Expected Done token"),
2241        }
2242
2243        // No more tokens
2244        assert!(parser.next_token().unwrap().is_none());
2245    }
2246
2247    #[test]
2248    fn test_env_change_type_from_u8() {
2249        assert_eq!(EnvChangeType::from_u8(1), Some(EnvChangeType::Database));
2250        assert_eq!(EnvChangeType::from_u8(20), Some(EnvChangeType::Routing));
2251        assert_eq!(EnvChangeType::from_u8(100), None);
2252    }
2253
2254    #[test]
2255    fn test_colmetadata_no_columns() {
2256        // No metadata marker (0xFFFF)
2257        let data = Bytes::from_static(&[0xFF, 0xFF]);
2258        let mut cursor: &[u8] = &data;
2259        let meta = ColMetaData::decode(&mut cursor).unwrap();
2260        assert!(meta.is_empty());
2261        assert_eq!(meta.column_count(), 0);
2262    }
2263
2264    #[test]
2265    fn test_colmetadata_single_int_column() {
2266        // COLMETADATA with 1 INT column
2267        // Format: column_count (2) + [user_type (4) + flags (2) + type_id (1) + name (b_varchar)]
2268        let mut data = BytesMut::new();
2269        data.extend_from_slice(&[0x01, 0x00]); // 1 column
2270        data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // user_type = 0
2271        data.extend_from_slice(&[0x01, 0x00]); // flags (nullable)
2272        data.extend_from_slice(&[0x38]); // TypeId::Int4
2273        // Column name "id" as B_VARCHAR (1 byte length + UTF-16LE)
2274        data.extend_from_slice(&[0x02]); // 2 characters
2275        data.extend_from_slice(&[b'i', 0x00, b'd', 0x00]); // "id" in UTF-16LE
2276
2277        let mut cursor: &[u8] = &data;
2278        let meta = ColMetaData::decode(&mut cursor).unwrap();
2279
2280        assert_eq!(meta.column_count(), 1);
2281        assert_eq!(meta.columns[0].name, "id");
2282        assert_eq!(meta.columns[0].type_id, TypeId::Int4);
2283        assert!(meta.columns[0].is_nullable());
2284    }
2285
2286    #[test]
2287    fn test_colmetadata_nvarchar_column() {
2288        // COLMETADATA with 1 NVARCHAR(50) column
2289        let mut data = BytesMut::new();
2290        data.extend_from_slice(&[0x01, 0x00]); // 1 column
2291        data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // user_type = 0
2292        data.extend_from_slice(&[0x01, 0x00]); // flags (nullable)
2293        data.extend_from_slice(&[0xE7]); // TypeId::NVarChar
2294        // Type info: max_length (2 bytes) + collation (5 bytes)
2295        data.extend_from_slice(&[0x64, 0x00]); // max_length = 100 (50 chars * 2)
2296        data.extend_from_slice(&[0x09, 0x04, 0xD0, 0x00, 0x34]); // collation
2297        // Column name "name"
2298        data.extend_from_slice(&[0x04]); // 4 characters
2299        data.extend_from_slice(&[b'n', 0x00, b'a', 0x00, b'm', 0x00, b'e', 0x00]);
2300
2301        let mut cursor: &[u8] = &data;
2302        let meta = ColMetaData::decode(&mut cursor).unwrap();
2303
2304        assert_eq!(meta.column_count(), 1);
2305        assert_eq!(meta.columns[0].name, "name");
2306        assert_eq!(meta.columns[0].type_id, TypeId::NVarChar);
2307        assert_eq!(meta.columns[0].type_info.max_length, Some(100));
2308        assert!(meta.columns[0].type_info.collation.is_some());
2309    }
2310
2311    #[test]
2312    fn test_raw_row_decode_int() {
2313        // Create metadata for a single INT column
2314        let metadata = ColMetaData {
2315            columns: vec![ColumnData {
2316                name: "id".to_string(),
2317                type_id: TypeId::Int4,
2318                col_type: 0x38,
2319                flags: 0,
2320                user_type: 0,
2321                type_info: TypeInfo::default(),
2322            }],
2323        };
2324
2325        // Row data: just 4 bytes for the int value 42
2326        let data = Bytes::from_static(&[0x2A, 0x00, 0x00, 0x00]); // 42 in little-endian
2327        let mut cursor: &[u8] = &data;
2328        let row = RawRow::decode(&mut cursor, &metadata).unwrap();
2329
2330        // The raw data should contain the 4 bytes
2331        assert_eq!(row.data.len(), 4);
2332        assert_eq!(&row.data[..], &[0x2A, 0x00, 0x00, 0x00]);
2333    }
2334
2335    #[test]
2336    fn test_raw_row_decode_nullable_int() {
2337        // Create metadata for a nullable INT column (IntN)
2338        let metadata = ColMetaData {
2339            columns: vec![ColumnData {
2340                name: "id".to_string(),
2341                type_id: TypeId::IntN,
2342                col_type: 0x26,
2343                flags: 0x01, // nullable
2344                user_type: 0,
2345                type_info: TypeInfo {
2346                    max_length: Some(4),
2347                    ..Default::default()
2348                },
2349            }],
2350        };
2351
2352        // Row data with value: 1 byte length + 4 bytes value
2353        let data = Bytes::from_static(&[0x04, 0x2A, 0x00, 0x00, 0x00]); // length=4, value=42
2354        let mut cursor: &[u8] = &data;
2355        let row = RawRow::decode(&mut cursor, &metadata).unwrap();
2356
2357        assert_eq!(row.data.len(), 5);
2358        assert_eq!(row.data[0], 4); // length
2359        assert_eq!(&row.data[1..], &[0x2A, 0x00, 0x00, 0x00]);
2360    }
2361
2362    #[test]
2363    fn test_raw_row_decode_null_value() {
2364        // Create metadata for a nullable INT column (IntN)
2365        let metadata = ColMetaData {
2366            columns: vec![ColumnData {
2367                name: "id".to_string(),
2368                type_id: TypeId::IntN,
2369                col_type: 0x26,
2370                flags: 0x01, // nullable
2371                user_type: 0,
2372                type_info: TypeInfo {
2373                    max_length: Some(4),
2374                    ..Default::default()
2375                },
2376            }],
2377        };
2378
2379        // NULL value: length = 0xFF (for bytelen types)
2380        let data = Bytes::from_static(&[0xFF]);
2381        let mut cursor: &[u8] = &data;
2382        let row = RawRow::decode(&mut cursor, &metadata).unwrap();
2383
2384        assert_eq!(row.data.len(), 1);
2385        assert_eq!(row.data[0], 0xFF); // NULL marker
2386    }
2387
2388    #[test]
2389    fn test_nbcrow_null_bitmap() {
2390        let row = NbcRow {
2391            null_bitmap: vec![0b00000101], // columns 0 and 2 are NULL
2392            data: Bytes::new(),
2393        };
2394
2395        assert!(row.is_null(0));
2396        assert!(!row.is_null(1));
2397        assert!(row.is_null(2));
2398        assert!(!row.is_null(3));
2399    }
2400
2401    #[test]
2402    fn test_token_parser_colmetadata() {
2403        // Build a COLMETADATA token with 1 INT column
2404        let mut data = BytesMut::new();
2405        data.extend_from_slice(&[0x81]); // COLMETADATA token type
2406        data.extend_from_slice(&[0x01, 0x00]); // 1 column
2407        data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // user_type = 0
2408        data.extend_from_slice(&[0x01, 0x00]); // flags (nullable)
2409        data.extend_from_slice(&[0x38]); // TypeId::Int4
2410        data.extend_from_slice(&[0x02]); // column name length
2411        data.extend_from_slice(&[b'i', 0x00, b'd', 0x00]); // "id"
2412
2413        let mut parser = TokenParser::new(data.freeze());
2414        let token = parser.next_token().unwrap().unwrap();
2415
2416        match token {
2417            Token::ColMetaData(meta) => {
2418                assert_eq!(meta.column_count(), 1);
2419                assert_eq!(meta.columns[0].name, "id");
2420                assert_eq!(meta.columns[0].type_id, TypeId::Int4);
2421            }
2422            _ => panic!("Expected ColMetaData token"),
2423        }
2424    }
2425
2426    #[test]
2427    fn test_token_parser_row_with_metadata() {
2428        // Build metadata
2429        let metadata = ColMetaData {
2430            columns: vec![ColumnData {
2431                name: "id".to_string(),
2432                type_id: TypeId::Int4,
2433                col_type: 0x38,
2434                flags: 0,
2435                user_type: 0,
2436                type_info: TypeInfo::default(),
2437            }],
2438        };
2439
2440        // Build ROW token
2441        let mut data = BytesMut::new();
2442        data.extend_from_slice(&[0xD1]); // ROW token type
2443        data.extend_from_slice(&[0x2A, 0x00, 0x00, 0x00]); // value = 42
2444
2445        let mut parser = TokenParser::new(data.freeze());
2446        let token = parser
2447            .next_token_with_metadata(Some(&metadata))
2448            .unwrap()
2449            .unwrap();
2450
2451        match token {
2452            Token::Row(row) => {
2453                assert_eq!(row.data.len(), 4);
2454            }
2455            _ => panic!("Expected Row token"),
2456        }
2457    }
2458
2459    #[test]
2460    fn test_token_parser_row_without_metadata_fails() {
2461        // Build ROW token
2462        let mut data = BytesMut::new();
2463        data.extend_from_slice(&[0xD1]); // ROW token type
2464        data.extend_from_slice(&[0x2A, 0x00, 0x00, 0x00]); // value = 42
2465
2466        let mut parser = TokenParser::new(data.freeze());
2467        let result = parser.next_token(); // No metadata provided
2468
2469        assert!(result.is_err());
2470    }
2471
2472    #[test]
2473    fn test_token_parser_peek() {
2474        let data = Bytes::from_static(&[
2475            0xFD, // DONE token type
2476            0x10, 0x00, // status
2477            0xC1, 0x00, // cur_cmd
2478            0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row_count
2479        ]);
2480
2481        let parser = TokenParser::new(data);
2482        assert_eq!(parser.peek_token_type(), Some(TokenType::Done));
2483    }
2484
2485    #[test]
2486    fn test_column_data_fixed_size() {
2487        let col = ColumnData {
2488            name: String::new(),
2489            type_id: TypeId::Int4,
2490            col_type: 0x38,
2491            flags: 0,
2492            user_type: 0,
2493            type_info: TypeInfo::default(),
2494        };
2495        assert_eq!(col.fixed_size(), Some(4));
2496
2497        let col2 = ColumnData {
2498            name: String::new(),
2499            type_id: TypeId::NVarChar,
2500            col_type: 0xE7,
2501            flags: 0,
2502            user_type: 0,
2503            type_info: TypeInfo::default(),
2504        };
2505        assert_eq!(col2.fixed_size(), None);
2506    }
2507}