diff --git a/Sources/CosmoMSSQL/TDS/TDSPreLogin.swift b/Sources/CosmoMSSQL/TDS/TDSPreLogin.swift index 0d59ef5..400efd4 100644 --- a/Sources/CosmoMSSQL/TDS/TDSPreLogin.swift +++ b/Sources/CosmoMSSQL/TDS/TDSPreLogin.swift @@ -21,7 +21,8 @@ enum PreLoginEncryption: UInt8 { } struct TDSPreLoginRequest { - var clientVersion: (UInt8, UInt8, UInt8, UInt8) = (8, 0, 0, 0) + // Changed from TDS 8.0 to TDS 7.4 for better Azure SQL compatibility + var clientVersion: (UInt8, UInt8, UInt8, UInt8) = (7, 4, 0, 0) var encryption: PreLoginEncryption init(encryption: PreLoginEncryption = .on) { diff --git a/Sources/CosmoMSSQL/TDS/TDSTLSFramer.swift b/Sources/CosmoMSSQL/TDS/TDSTLSFramer.swift index 38494c0..5311dc4 100644 --- a/Sources/CosmoMSSQL/TDS/TDSTLSFramer.swift +++ b/Sources/CosmoMSSQL/TDS/TDSTLSFramer.swift @@ -29,6 +29,9 @@ final class TDSTLSFramer: ChannelDuplexHandler, @unchecked Sendable { /// the TLS handshake completes. var active: Bool = false + // Accumulator buffer for incomplete TDS packets + private var accumulatedBuffer: ByteBuffer? + // MARK: - Inbound func channelRead(context: ChannelHandlerContext, data: NIOAny) { @@ -36,7 +39,18 @@ final class TDSTLSFramer: ChannelDuplexHandler, @unchecked Sendable { context.fireChannelRead(data) return } - var buf = unwrapInboundIn(data) + var incoming = unwrapInboundIn(data) + + // Accumulate incoming data with any previously buffered data + if var accumulated = accumulatedBuffer { + accumulated.writeBuffer(&incoming) + accumulatedBuffer = accumulated + } else { + accumulatedBuffer = incoming + } + + guard var buf = accumulatedBuffer else { return } + // The buffer may contain one or more TDS Pre-Login packets. // Each packet: [type 1B][status 1B][length 2B big-endian][spid 2B][pid 1B][win 1B] + payload while buf.readableBytes >= 8 { @@ -44,12 +58,23 @@ final class TDSTLSFramer: ChannelDuplexHandler, @unchecked Sendable { let lengthBE: UInt16 = buf.getInteger(at: buf.readerIndex + 2, endianness: .big), Int(lengthBE) <= buf.readableBytes, Int(lengthBE) >= 8 - else { break } + else { + // Save remaining data for next read + accumulatedBuffer = buf + return + } let packetLen = Int(lengthBE) var packet = buf.readSlice(length: packetLen)! packet.moveReaderIndex(forwardBy: 8) // skip TDS header context.fireChannelRead(wrapInboundOut(packet)) } + + // If all data was processed, clear the accumulator + if buf.readableBytes == 0 { + accumulatedBuffer = nil + } else { + accumulatedBuffer = buf + } } // MARK: - Outbound