diff --git a/Sources/MySQLNIO/Protocol/MySQLProtocol+COM_STMT_EXECUTE.swift b/Sources/MySQLNIO/Protocol/MySQLProtocol+COM_STMT_EXECUTE.swift index 5907137..cb601bf 100644 --- a/Sources/MySQLNIO/Protocol/MySQLProtocol+COM_STMT_EXECUTE.swift +++ b/Sources/MySQLNIO/Protocol/MySQLProtocol+COM_STMT_EXECUTE.swift @@ -76,8 +76,7 @@ extension MySQLProtocol { case .none: break case .some(var buffer): if value.type.encodingLength == nil { - // TODO: make length encoded - packet.payload.writeInteger(numericCast(buffer.readableBytes), endianness: .little, as: UInt8.self) + packet.payload.writeLengthEncoded(buffer.readableBytes) } packet.payload.writeBuffer(&buffer) } @@ -86,3 +85,24 @@ extension MySQLProtocol { } } } + +extension ByteBuffer { + mutating func writeLengthEncoded(_ integer: Int) { + assert(integer >= 0, "Length must be positive") + switch integer { + case 0..<251: + self.writeInteger(numericCast(integer), as: UInt8.self) + case 251..<1<<16: + self.writeInteger(0xFC, as: UInt8.self) + self.writeInteger(numericCast(integer), endianness: .little, as: UInt16.self) + case 1<<16..<1<<24: + self.writeInteger(0xFD, as: UInt8.self) + self.writeInteger(numericCast(integer & 0xFF), as: UInt8.self) + self.writeInteger(numericCast(integer >> 8 & 0xFF), as: UInt8.self) + self.writeInteger(numericCast(integer >> 16 & 0xFF), as: UInt8.self) + default: + self.writeInteger(0xFE, as: UInt8.self) + self.writeInteger(numericCast(integer), endianness: .little, as: UInt64.self) + } + } +} diff --git a/Tests/MySQLNIOTests/NIOMySQLTests.swift b/Tests/MySQLNIOTests/NIOMySQLTests.swift index a2373f2..a1e030e 100644 --- a/Tests/MySQLNIOTests/NIOMySQLTests.swift +++ b/Tests/MySQLNIOTests/NIOMySQLTests.swift @@ -245,6 +245,30 @@ final class NIOMySQLTests: XCTestCase { XCTAssert(time.microsecond == UInt32(100000)) XCTAssert(time2.microsecond == UInt32(100000)) } + + func testString_lengthEncoded_uint8() throws { + let conn = try MySQLConnection.test(on: self.eventLoop).wait() + defer { try! conn.close().wait() } + let string = String(repeating: "a", count: 128) + let rows = try! conn.query("SELECT ? as s", [MySQLData(string: string)]).wait() + XCTAssertEqual(rows[0].column("s")?.string, string) + } + + func testString_lengthEncoded_fc() throws { + let conn = try MySQLConnection.test(on: self.eventLoop).wait() + defer { try! conn.close().wait() } + let string = String(repeating: "a", count: 512) + let rows = try! conn.query("SELECT ? as s", [MySQLData(string: string)]).wait() + XCTAssertEqual(rows[0].column("s")?.string, string) + } + + func testString_lengthEncoded_fd() throws { + let conn = try MySQLConnection.test(on: self.eventLoop).wait() + defer { try! conn.close().wait() } + let string = String(repeating: "a", count: 1<<17) + let rows = try! conn.query("SELECT ? as s", [MySQLData(string: string)]).wait() + XCTAssertEqual(rows[0].column("s")?.string, string) + } func testTypes() throws { /// support