postgres.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package l7
  2. import (
  3. "bytes"
  4. "fmt"
  5. )
  6. const (
  7. PostgresFrameQuery byte = 'Q'
  8. PostgresFrameBind byte = 'B'
  9. PostgresFrameParse byte = 'P'
  10. PostgresFrameClose byte = 'C'
  11. )
  12. type PostgresParser struct {
  13. preparedStatements map[string]string
  14. }
  15. func NewPostgresParser() *PostgresParser {
  16. return &PostgresParser{preparedStatements: map[string]string{}}
  17. }
  18. func (p *PostgresParser) Parse(payload []byte) string {
  19. l := len(payload)
  20. if l < 5 {
  21. return ""
  22. }
  23. cmd := payload[0]
  24. switch cmd {
  25. case PostgresFrameQuery:
  26. var query string
  27. if q, _, ok := bytes.Cut(payload[5:], []byte{0}); ok {
  28. query = string(q)
  29. } else {
  30. query = string(q) + "..."
  31. }
  32. return query
  33. case PostgresFrameBind:
  34. _, rest, ok := bytes.Cut(payload[5:], []byte{0})
  35. if !ok {
  36. return ""
  37. }
  38. preparedStatementName, _, ok := bytes.Cut(rest, []byte{0})
  39. if !ok {
  40. return ""
  41. }
  42. preparedStatementNameStr := string(preparedStatementName)
  43. statement, ok := p.preparedStatements[preparedStatementNameStr]
  44. if !ok {
  45. statement = fmt.Sprintf(`EXECUTE %s /* unknown */`, preparedStatementNameStr)
  46. }
  47. return statement
  48. case PostgresFrameParse:
  49. preparedStatementName, rest, ok := bytes.Cut(payload[5:], []byte{0})
  50. if !ok {
  51. return ""
  52. }
  53. var query string
  54. q, _, ok := bytes.Cut(rest, []byte{0})
  55. if ok {
  56. query = string(q)
  57. } else {
  58. query = string(q) + "..."
  59. }
  60. preparedStatementNameStr := string(preparedStatementName)
  61. p.preparedStatements[preparedStatementNameStr] = query
  62. return fmt.Sprintf("PREPARE %s AS %s", preparedStatementNameStr, query)
  63. case PostgresFrameClose:
  64. if l < 7 {
  65. return ""
  66. }
  67. if payload[5] != 'S' {
  68. return ""
  69. }
  70. preparedStatementName, _, ok := bytes.Cut(payload[6:], []byte{0})
  71. if !ok {
  72. return ""
  73. }
  74. delete(p.preparedStatements, string(preparedStatementName))
  75. }
  76. return ""
  77. }