rowid_test.go 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package pgserver
  2. import (
  3. "testing"
  4. )
  5. // RowDescription for the hidden rowid alias must report an integer OID, not
  6. // TEXT, because the value is a signed 64-bit integer.
  7. func TestRowIDWireTypeIsBigint(t *testing.T) {
  8. c, client := newDataConnection(t)
  9. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("CREATE TABLE t (id TEXT PRIMARY KEY)"), 0)})
  10. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("INSERT INTO t (id) VALUES ('a')"), 0)})
  11. msgs := runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("SELECT _rowid_ FROM t"), 0)})
  12. if msgs[0].Type != MsgRowDescription {
  13. t.Fatalf("first message = %c, want RowDescription", msgs[0].Type)
  14. }
  15. oids := rowDescriptionOIDs(t, msgs[0].Data)
  16. if len(oids) != 1 || oids[0] != 20 { // INT8OID
  17. t.Fatalf("rowid OIDs = %v, want [20]", oids)
  18. }
  19. if got := dataRowValues(t, msgs[1]); len(got) != 1 || got[0] != "1" {
  20. t.Fatalf("rowid value = %v, want [1]", got)
  21. }
  22. }
  23. // A keyset cursor built from _rowid_ must paginate without repeating or
  24. // skipping rows, including rows inserted after the first page is read.
  25. func TestRowIDKeysetPaginationOverSimpleQuery(t *testing.T) {
  26. c, client := newDataConnection(t)
  27. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("CREATE TABLE events (id TEXT PRIMARY KEY, payload TEXT)"), 0)})
  28. for _, id := range []string{"a", "b", "c", "d", "e"} {
  29. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("INSERT INTO events (id, payload) VALUES ('"+id+"', 'x')"), 0)})
  30. }
  31. page := func(cursor string) []string {
  32. msgs := runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("SELECT _rowid_ FROM events WHERE _rowid_ > "+cursor+" ORDER BY _rowid_ LIMIT 2"), 0)})
  33. if len(msgs) < 2 || msgs[0].Type != MsgRowDescription {
  34. t.Fatalf("unexpected page response: %v", msgs)
  35. }
  36. var ids []string
  37. for _, msg := range msgs[1:] {
  38. if msg.Type != MsgDataRow {
  39. break
  40. }
  41. ids = append(ids, dataRowValues(t, msg)[0])
  42. }
  43. return ids
  44. }
  45. first := page("0")
  46. if len(first) != 2 || first[0] != "1" || first[1] != "2" {
  47. t.Fatalf("first page = %v, want [1 2]", first)
  48. }
  49. // A late insert must not move the cursor backwards or duplicate page 1.
  50. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("INSERT INTO events (id, payload) VALUES ('late', 'x')"), 0)})
  51. second := page(first[1])
  52. if len(second) != 2 || second[0] != "3" || second[1] != "4" {
  53. t.Fatalf("second page = %v, want [3 4]", second)
  54. }
  55. third := page(second[1])
  56. if len(third) != 2 || third[0] != "5" || third[1] != "6" {
  57. t.Fatalf("third page = %v, want [5 6] (late row appended)", third)
  58. }
  59. if fourth := page(third[1]); len(fourth) != 0 {
  60. t.Fatalf("final page = %v, want empty", fourth)
  61. }
  62. }
  63. // INSERT ... RETURNING _rowid_ must expose the assigned cursor value.
  64. func TestRowIDReturningOverSimpleQuery(t *testing.T) {
  65. c, client := newDataConnection(t)
  66. runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("CREATE TABLE t (id TEXT PRIMARY KEY)"), 0)})
  67. msgs := runQuery(t, c, client, &Message{Type: MsgQuery, Data: append([]byte("INSERT INTO t (id) VALUES ('a') RETURNING _rowid_"), 0)})
  68. if len(msgs) < 3 {
  69. t.Fatalf("expected RowDescription+DataRow+CommandComplete, got %v", msgs)
  70. }
  71. if got := dataRowValues(t, msgs[1]); len(got) != 1 || got[0] != "1" {
  72. t.Fatalf("returned rowid = %v, want [1]", got)
  73. }
  74. }