All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finagle.postgres.messages.BackendMessageParser.scala Maven / Gradle / Ivy

package com.twitter.finagle.postgres.messages

import com.twitter.finagle.postgres.values.Buffers
import com.twitter.logging.Logger

import org.jboss.netty.buffer.ChannelBuffer

/*
 * Class for converting packets into BackendMessages.
 */
class BackendMessageParser {
  private val logger = Logger(getClass.getName)

  def parse(packet: Packet): Option[BackendMessage] = {
    val result: Option[BackendMessage] = packet.code.get match {
      case 'R' =>
        parseR(packet)
      case 'E' =>
        parseE(packet)
      case 'K' =>
        parseK(packet)
      case 'd' =>
        parseSmallD(packet)
      case 'D' =>
        parseD(packet)
      case '3' =>
        logger.error("'3' Not implemented yet")
        throw new UnsupportedOperationException("'3' Not implemented yet")
      case 'C' =>
        parseC(packet)
      case 'G' =>
        logger.error("'G' Not implemented yet")
        throw new UnsupportedOperationException("'G' Not implemented yet")
      case 'H' =>
        logger.error("'H' Not implemented yet")
        throw new UnsupportedOperationException("'H' Not implemented yet")
      case 'W' =>
        logger.error("'W' Not implemented yet")

        throw new UnsupportedOperationException("'W' Not implemented yet")
      case 'I' =>
        parseI(packet)
      case 'V' =>
        logger.error("'V' Not implemented yet")
        throw new UnsupportedOperationException("'V' Not implemented yet")
      case 'n' =>
        parseSmallN(packet)
      case 'N' =>
        parseN(packet)
      case 'A' =>
        parseA(packet)
      case 't' =>
        parseSmallT(packet)
      case 'S' =>
        parseS(packet)
      case '1' =>
        parse1(packet)
      case '2' =>
        parse2(packet)
      case 's' =>
        parseSmallS(packet)
      case 'Z' =>
        parseZ(packet)
      case 'T' =>
        parseT(packet)

      case unknown =>
        None
    }

    result
  }

  def parseR(packet: Packet): Option[BackendMessage] = {
    val Packet(_, length, content, _) = packet

    length match {
      case 8 =>
        val code = content.readInt()

        code match {
          case 3 =>
            Some(new AuthenticationCleartextPassword())
          case 0 =>
            Some(new AuthenticationOk())
          case _ =>
            None
        }

      case 12 =>
        val code = packet.content.readInt
        if (code == 5) {
          val salt = new Array[Byte](4)
          packet.content.readBytes(salt)
          Some(new AuthenticationMD5Password(salt))
        } else {
          None
        }

      case _ =>
        None
    }
  }

  def parseE(packet: Packet): Option[BackendMessage] = {
    val Packet(_, _, content, _) = packet

    val builder = new StringBuilder()
    while (content.readable) {
      builder.append(Buffers.readCString(content))
    }

    Some(new ErrorResponse(Some(builder.toString)))
  }

  def parseN(packet: Packet): Option[BackendMessage] = {
    val Packet(_, _, content, inSslNegotation) = packet

    if (inSslNegotation) {
      Some(SslNotSupported)
    } else {
      val builder = new StringBuilder()
      while (content.readable) {
        builder.append(Buffers.readCString(content))
      }

      Some(new NoticeResponse(Some(builder.toString)))
    }
  }

  def parseZ(packet: Packet): Option[BackendMessage] = {
    val Packet(_, length, content, _) = packet

    if (length != 5) {
      throw new IllegalStateException("Unexpected message length ")
    }

    val status = content.readByte().asInstanceOf[Char]

    Some(new ReadyForQuery(status))
  }

  def parseK(packet: Packet): Option[BackendMessage] = {
    val Packet(_, length, content, _) = packet

    if (length != 12) {
      throw new IllegalStateException("Unexpected message length ")
    }

    val processId = content.readInt
    val secretKey = content.readInt

    Some(new BackendKeyData(processId, secretKey))
  }

  def parseSmallD(packet: Packet): Option[BackendMessage] = {
    throw new UnsupportedOperationException("'d' Not implemented yet")
  }

  def parseD(packet: Packet): Option[BackendMessage] = {
    val Packet(_, _, content, _) = packet

    val fieldNumber = content.readShort
    val fields = new Array[ChannelBuffer](fieldNumber)

    for (i <- 0.until(fieldNumber)) {
      val length = content.readInt
      if (length == -1) {
        fields(i) = null
      } else {
        val index = content.readerIndex
        val slice = content.slice(index, length)
        content.readerIndex(index + length)

        fields(i) = slice

        content.readerIndex(index + length)
      }
    }

    Some(new DataRow(fields))
  }

  def parseT(packet: Packet): Option[BackendMessage] = {
    val Packet(_, _, content, _) = packet

    val fieldNumber = content.readShort

    val fields = new Array[FieldDescription](fieldNumber)
    0.until(fieldNumber).foreach {
      index =>

        val field = new FieldDescription(
          Buffers.readCString(content),
          content.readInt,
          content.readShort,
          content.readInt,
          content.readShort,
          content.readInt,
          content.readShort)

        fields(index) = field
    }

    Some(new RowDescription(fields))
  }

  def parseC(packet: Packet): Option[BackendMessage] = {
    val Packet(_, _, content, _) = packet

    val tag = Buffers.readCString(content)

    Some(new CommandComplete(parseTag(tag)))
  }

  def parseTag(tag: String) : CommandCompleteStatus = {
    if (tag == "CREATE TABLE") {
      CreateTable
    } else if (tag == "DROP TABLE") {
      DropTable
    } else if (tag == "DISCARD ALL") {
      DiscardAll
    } else {
      val parts = tag.split(" ")

      parts(0) match {
        case "SELECT" => Select(parts(1).toInt)
        case "INSERT" => Insert(parts(2).toInt)
        case "DELETE" => Delete(parts(1).toInt)
        case "UPDATE" => Update(parts(1).toInt)
	case "BEGIN"  => Begin
	case "SAVEPOINT" => Savepoint
	case "ROLLBACK"  => RollBack
	case "COMMIT" => Commit
        case _ => throw new IllegalStateException("Unknown command complete response tag " + tag)
      }
    }
  }

  def parseS(packet: Packet): Option[BackendMessage] = {
    val Packet(_, _, content, inSslNegotation) = packet

    if (inSslNegotation) {
      Some(SwitchToSsl)
    } else {
      val parameterStatus = new ParameterStatus(Buffers.readCString(content), Buffers.readCString(content))
      Some(parameterStatus)
    }
  }

  def parse1(packet: Packet): Option[BackendMessage] = {
    Some(ParseComplete)
  }

  def parse2(packet: Packet): Option[BackendMessage] = {
    Some(BindComplete)
  }

  def parseSmallT(packet: Packet): Option[BackendMessage] = {
    val Packet(_, _, content, _) = packet

    val paramNumber = content.readShort

    val params = new Array[Int](paramNumber)
    0.until(paramNumber).foreach {
      index =>
        val param = content.readInt
        params(index) = param
    }

    Some(new ParameterDescription(params))

  }

  def parseSmallN(packet: Packet): Option[BackendMessage] = {
    Some(NoData)
  }

  def parseSmallS(packet: Packet): Option[BackendMessage] = {
    Some(PortalSuspended)
  }

  def parseI(packet: Packet): Option[BackendMessage] = {
    Some(EmptyQueryResponse)
  }

  def parseA(packet: Packet): Option[BackendMessage] = {
    val Packet(_, _, content, _) = packet
    val processId = content.readInt
    val channel = Buffers.readCString(content)
    val payload = Buffers.readCString(content)

    Some(NotificationResponse(processId, channel, payload))
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy