commit_failure_test.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536
  1. package pgserver
  2. import (
  3. "testing"
  4. )
  5. // A constraint failure at COMMIT is a normal conflict: storage has already
  6. // rolled the transaction back, so the wire session must return to idle instead
  7. // of rejecting every later statement, including ROLLBACK.
  8. func TestFailedCommitClearsTransactionState(t *testing.T) {
  9. c, client := newDataConnection(t)
  10. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("CREATE TABLE t (id INTEGER PRIMARY KEY, email TEXT UNIQUE)"), 0)})
  11. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("INSERT INTO t VALUES (1, 'a@x')"), 0)})
  12. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("BEGIN"), 0)})
  13. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("INSERT INTO t VALUES (2, 'a@x')"), 0)})
  14. msgs := runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("COMMIT"), 0)})
  15. if len(msgs) == 0 || msgs[0].Type != MsgErrorResponse {
  16. t.Fatalf("COMMIT should fail with the buffered unique violation, got %v", msgs)
  17. }
  18. if c.txStatus != TxStatusIdle {
  19. t.Fatalf("tx status = %v, want idle after a failed COMMIT", c.txStatus)
  20. }
  21. msgs = runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("SELECT 1"), 0)})
  22. if len(msgs) < 2 || msgs[0].Type != MsgRowDescription {
  23. t.Fatalf("SELECT after failed COMMIT = %v, want a result", msgs)
  24. }
  25. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("BEGIN"), 0)})
  26. msgs = runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("ROLLBACK"), 0)})
  27. if len(msgs) == 0 || msgs[0].Type == MsgErrorResponse {
  28. t.Fatalf("BEGIN/ROLLBACK after failed COMMIT = %v", msgs)
  29. }
  30. }