Skip to content

Commit

Permalink
Correctly handle the length case for 253 bytes - fixes mauricio#100
Browse files Browse the repository at this point in the history
  • Loading branch information
mauricio committed Sep 6, 2014
1 parent fbcd302 commit 6148f68
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 32 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@

# Changelog

## 0.2.15 - still in progress

* Fixes issue where PostgreSQL decoders fail to produce a NULL value if the null is wrapped by a `Some` instance - #99;
* Fixes issue where the 253 case of length encoded fields on MySQL produce a wrong value;

## 0.2.14 - 2014-08-30

* Remove failed prepared statement from cache - @dboissin - #95
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,6 @@ class ChannelWrapper( val buffer : ByteBuf ) extends AnyVal {

def readUntilEOF( charset: Charset ) = ByteBufferUtils.readUntilEOF(buffer, charset)

def read3BytesInt : Int = {
val first = buffer.readByte()
val second = buffer.readByte()
val third = buffer.readByte()
var i = third << 16 | second << 8 | first

if ((third & 0x80) == 0x80) {
i |= 0xff000000
}

i
}

def readLengthEncodedString( charset : Charset ) : String = {
val length = readBinaryLength
readFixedString(length.asInstanceOf[Int], charset)
Expand All @@ -70,14 +57,22 @@ class ChannelWrapper( val buffer : ByteBuf ) extends AnyVal {
firstByte match {
case MySQL_NULL => -1
case 252 => buffer.readUnsignedShort()
case 253 => read3BytesInt
case 253 => readLongInt
case 254 => buffer.readLong()
case _ => throw new UnknownLengthException(firstByte)
}
}

}

def readLongInt : Int = {
val first = buffer.readByte()
val second = buffer.readByte()
val third = buffer.readByte()

( first & 0xff ) | (( second & 0xff ) << 8) | ((third & 0xff) << 16)
}

def writeLength( length : Long ) {
if (length < 251) {
buffer.writeByte( length.asInstanceOf[Byte])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,32 @@

package com.github.mauricio.async.db.mysql.decoder

import io.netty.buffer.ByteBuf
import java.nio.charset.Charset

import com.github.mauricio.async.db.mysql.message.server.{ResultSetRowMessage, ServerMessage}
import com.github.mauricio.async.db.util.ChannelWrapper.bufferToWrapper
import java.nio.charset.Charset
import java.nio.ByteOrder
import io.netty.buffer.ByteBuf

object ResultSetRowDecoder {

final val NULL = 0xfb

}

class ResultSetRowDecoder( charset : Charset ) extends MessageDecoder {
class ResultSetRowDecoder(charset: Charset) extends MessageDecoder {

import ResultSetRowDecoder.NULL
import com.github.mauricio.async.db.mysql.decoder.ResultSetRowDecoder.NULL

def decode(buffer: ByteBuf): ServerMessage = {
val row = new ResultSetRowMessage()

while (buffer.isReadable() ) {
if ( buffer.getUnsignedByte(buffer.readerIndex()) == NULL ) {
while (buffer.isReadable()) {
if (buffer.getUnsignedByte(buffer.readerIndex()) == NULL) {
buffer.readByte()
row += null
} else {
val length = buffer.readBinaryLength.asInstanceOf[Int]
row += buffer.readBytes(length)

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class QuerySpec extends Specification with ConnectionHelper {
timestamp.getSecondOfMinute === 7


result("created_at_time") === Duration( 3, TimeUnit.HOURS ) + Duration( 14, TimeUnit.MINUTES ) + Duration( 7, TimeUnit.SECONDS )
result("created_at_time") === Duration(3, TimeUnit.HOURS) + Duration(14, TimeUnit.MINUTES) + Duration(7, TimeUnit.SECONDS)

val year = result("created_at_year").asInstanceOf[Short]

Expand Down Expand Up @@ -150,21 +150,21 @@ class QuerySpec extends Specification with ConnectionHelper {
| primary key (id) )""".stripMargin

val createIdeas = """CREATE TEMPORARY TABLE ideas (
| id INT NOT NULL AUTO_INCREMENT,
| some_idea VARCHAR(255) NOT NULL,
| primary key (id) )""".stripMargin
| id INT NOT NULL AUTO_INCREMENT,
| some_idea VARCHAR(255) NOT NULL,
| primary key (id) )""".stripMargin

val select = "SELECT * FROM posts"
val selectIdeas = "SELECT * FROM ideas"

val matcher : QueryResult => List[MatchResult[IndexedSeq[String]]] = { result =>
val matcher: QueryResult => List[MatchResult[IndexedSeq[String]]] = { result =>
val columns = result.rows.get.columnNames
List(columns must contain(allOf("id", "some_bytes")).inOrder, columns must have size(2))
List(columns must contain(allOf("id", "some_bytes")).inOrder, columns must have size (2))
}

val ideasMatcher : QueryResult => List[MatchResult[IndexedSeq[String]]] = { result =>
val ideasMatcher: QueryResult => List[MatchResult[IndexedSeq[String]]] = { result =>
val columns = result.rows.get.columnNames
List(columns must contain(allOf("id", "some_idea")).inOrder, columns must have size(2))
List(columns must contain(allOf("id", "some_idea")).inOrder, columns must have size (2))
}

withConnection {
Expand Down Expand Up @@ -204,10 +204,10 @@ class QuerySpec extends Specification with ConnectionHelper {
executeQuery(connection, insert)

val rows = executeQuery(connection, select).rows.get
rows(0)("bit_column") === Array(0,0,-128)
rows(0)("bit_column") === Array(0, 0, -128)

val preparedRows = executePreparedStatement(connection, select).rows.get
preparedRows(0)("bit_column") === Array(0,0,-128)
preparedRows(0)("bit_column") === Array(0, 0, -128)
}

}
Expand Down Expand Up @@ -264,6 +264,30 @@ class QuerySpec extends Specification with ConnectionHelper {

}

"select from a large text column" in {

val create = "create temporary table bombs (id char(4), bomb mediumtext character set ascii)"

val insert = """ insert bombs values
| ('bomb', repeat(' ',65536+16384+8192+4096+2048+1024+512+256+128)),
| ('good', repeat(' ',65536+16384+8192+4096+2048+1024+512+256+128-1))""".stripMargin


withConnection {
connection =>
executeQuery(connection, create)
executeQuery(connection, insert)
val result = executeQuery(connection, "select bomb from bombs").rows.get

result.size === 2

result(0)("bomb").asInstanceOf[String].length === 98176
result(1)("bomb").asInstanceOf[String].length === 98175
}

}


}

}

0 comments on commit 6148f68

Please sign in to comment.