foreign_key_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package pgserver
  2. import (
  3. "testing"
  4. )
  5. // A dangling foreign key reports SQLSTATE 23503 on both the simple and the
  6. // extended protocol, and inside a transaction block it leaves the transaction
  7. // failed like the other integrity errors.
  8. func TestForeignKeySQLStateAcrossProtocolPaths(t *testing.T) {
  9. for _, extended := range []bool{false, true} {
  10. for _, transaction := range []bool{false, true} {
  11. c, client := newDataConnection(t)
  12. runQuery(t, c, client, simpleQueryMessage("CREATE TABLE parent (id INTEGER PRIMARY KEY)"))
  13. runQuery(t, c, client, simpleQueryMessage("CREATE TABLE child (id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES parent(id))"))
  14. if transaction {
  15. runQuery(t, c, client, simpleQueryMessage("BEGIN"))
  16. }
  17. sql := "INSERT INTO child (id, parent_id) VALUES (1, 99)"
  18. var messages []*Message
  19. if extended {
  20. messages = runExtendedExecution(t, c, client, sql)
  21. } else {
  22. messages = runQuery(t, c, client, simpleQueryMessage(sql))
  23. }
  24. if transaction {
  25. // A staged write is validated at COMMIT, not by the INSERT.
  26. if code := errorCode(messages[0]); code != "" {
  27. t.Fatalf("extended=%v staged INSERT SQLSTATE = %q, want none", extended, code)
  28. }
  29. messages = runQuery(t, c, client, simpleQueryMessage("COMMIT"))
  30. }
  31. if code := errorCode(messages[0]); code != ErrCodeForeignKeyViolation {
  32. t.Fatalf("extended=%v transaction=%v SQLSTATE = %q, want %q", extended, transaction, code, ErrCodeForeignKeyViolation)
  33. }
  34. if transaction {
  35. if c.txStatus != TxStatusIdle {
  36. t.Fatalf("tx status = %v, want idle after a failed COMMIT", c.txStatus)
  37. }
  38. runQuery(t, c, client, simpleQueryMessage("ROLLBACK"))
  39. }
  40. count := runQuery(t, c, client, simpleQueryMessage("SELECT COUNT(*) FROM child"))
  41. if values := dataRowValues(t, count[1]); len(values) != 1 || values[0] != "0" {
  42. t.Fatalf("rejected insert left rows behind: %v", values)
  43. }
  44. }
  45. }
  46. }
  47. // Deleting a referenced parent reports 23503 over the wire and leaves the
  48. // parent row in place.
  49. func TestForeignKeyParentDeleteSQLState(t *testing.T) {
  50. c, client := newDataConnection(t)
  51. runQuery(t, c, client, simpleQueryMessage("CREATE TABLE parent (id INTEGER PRIMARY KEY)"))
  52. runQuery(t, c, client, simpleQueryMessage("CREATE TABLE child (id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES parent(id))"))
  53. runQuery(t, c, client, simpleQueryMessage("INSERT INTO parent (id) VALUES (1)"))
  54. runQuery(t, c, client, simpleQueryMessage("INSERT INTO child (id, parent_id) VALUES (10, 1)"))
  55. messages := runQuery(t, c, client, simpleQueryMessage("DELETE FROM parent WHERE id = 1"))
  56. if code := errorCode(messages[0]); code != ErrCodeForeignKeyViolation {
  57. t.Fatalf("DELETE SQLSTATE = %q, want %q", code, ErrCodeForeignKeyViolation)
  58. }
  59. count := runQuery(t, c, client, simpleQueryMessage("SELECT COUNT(*) FROM parent"))
  60. if values := dataRowValues(t, count[1]); len(values) != 1 || values[0] != "1" {
  61. t.Fatalf("rejected delete removed the parent: %v", values)
  62. }
  63. }