proxy_error_test.go 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package pgserver
  2. import (
  3. "bufio"
  4. "net"
  5. "testing"
  6. )
  7. func runMessageCycle(t *testing.T, c *Connection, client net.Conn, messages ...*Message) []*Message {
  8. t.Helper()
  9. done := make(chan error, 1)
  10. go func() {
  11. for _, msg := range messages {
  12. if err := c.handleMessage(msg); err != nil {
  13. done <- err
  14. return
  15. }
  16. }
  17. done <- nil
  18. }()
  19. r := bufio.NewReader(client)
  20. var response []*Message
  21. for {
  22. msg, err := ReadMessage(r)
  23. if err != nil {
  24. t.Fatal(err)
  25. }
  26. response = append(response, msg)
  27. if msg.Type == MsgReadyForQuery {
  28. break
  29. }
  30. }
  31. if err := <-done; err != nil {
  32. t.Fatal(err)
  33. }
  34. return response
  35. }
  36. func TestSyntaxErrorAbortsSimpleAndExtendedTransaction(t *testing.T) {
  37. for _, extended := range []bool{false, true} {
  38. c, client := newDataConnection(t)
  39. runQuery(t, c, client, &Message{Type: MsgQuery, Data: []byte("BEGIN\x00")})
  40. var response []*Message
  41. if extended {
  42. response = runExtendedExecution(t, c, client, "SELEC invalid")
  43. } else {
  44. response = runQuery(t, c, client, &Message{Type: MsgQuery, Data: []byte("SELEC invalid\x00")})
  45. }
  46. if errorCode(response[0]) != "42601" || c.txStatus != TxStatusFailed {
  47. t.Fatalf("extended=%v did not abort on syntax error", extended)
  48. }
  49. response = runQuery(t, c, client, &Message{Type: MsgQuery, Data: []byte("SELECT 1\x00")})
  50. if errorCode(response[0]) != "25P02" {
  51. t.Fatal("failed transaction accepted SELECT")
  52. }
  53. runQuery(t, c, client, &Message{Type: MsgQuery, Data: []byte("ROLLBACK\x00")})
  54. }
  55. }
  56. func TestProxyErrorRelayTransactionAndSyncRecovery(t *testing.T) {
  57. for _, extended := range []bool{false, true} {
  58. c, client := newDataConnection(t)
  59. for _, sql := range []string{"CREATE TABLE t (id INTEGER PRIMARY KEY)", "BEGIN", "INSERT INTO t VALUES (1)", "SAVEPOINT s"} {
  60. runQuery(t, c, client, &Message{Type: MsgQuery, Data: []byte(sql + "\x00")})
  61. }
  62. kind := byte(MsgQuery)
  63. if extended {
  64. kind = MsgParse
  65. }
  66. messages := []*Message{{Type: MsgProxyError, Data: []byte{kind}}}
  67. if extended {
  68. c.portals[""] = &portal{query: "INSERT INTO t VALUES (2)"}
  69. messages = append(messages, &Message{Type: MsgExecute, Data: []byte{0, 0, 0, 0, 0}}, &Message{Type: MsgSync})
  70. }
  71. response := runMessageCycle(t, c, client, messages...)
  72. if errorCode(response[0]) != "42501" {
  73. t.Fatalf("extended=%v missing permission error", extended)
  74. }
  75. if last := response[len(response)-1]; last.Type != MsgReadyForQuery || string(last.Data) != "E" {
  76. t.Fatalf("extended=%v false ready state: %v", extended, last)
  77. }
  78. runQuery(t, c, client, &Message{Type: MsgQuery, Data: []byte("ROLLBACK TO SAVEPOINT s\x00")})
  79. response = runQuery(t, c, client, &Message{Type: MsgQuery, Data: []byte("SELECT COUNT(*) FROM t\x00")})
  80. if row := dataRowValues(t, response[1]); len(row) != 1 || row[0] != "1" {
  81. t.Fatalf("relay lost earlier writes or executed discarded messages: %v", row)
  82. }
  83. runQuery(t, c, client, &Message{Type: MsgQuery, Data: []byte("ROLLBACK\x00")})
  84. }
  85. }