go18_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // +build go1.8
  2. package pq
  3. import (
  4. "context"
  5. "database/sql"
  6. "runtime"
  7. "strings"
  8. "testing"
  9. "time"
  10. )
  11. func TestMultipleSimpleQuery(t *testing.T) {
  12. db := openTestConn(t)
  13. defer db.Close()
  14. rows, err := db.Query("select 1; set time zone default; select 2; select 3")
  15. if err != nil {
  16. t.Fatal(err)
  17. }
  18. defer rows.Close()
  19. var i int
  20. for rows.Next() {
  21. if err := rows.Scan(&i); err != nil {
  22. t.Fatal(err)
  23. }
  24. if i != 1 {
  25. t.Fatalf("expected 1, got %d", i)
  26. }
  27. }
  28. if !rows.NextResultSet() {
  29. t.Fatal("expected more result sets", rows.Err())
  30. }
  31. for rows.Next() {
  32. if err := rows.Scan(&i); err != nil {
  33. t.Fatal(err)
  34. }
  35. if i != 2 {
  36. t.Fatalf("expected 2, got %d", i)
  37. }
  38. }
  39. // Make sure that if we ignore a result we can still query.
  40. rows, err = db.Query("select 4; select 5")
  41. if err != nil {
  42. t.Fatal(err)
  43. }
  44. defer rows.Close()
  45. for rows.Next() {
  46. if err := rows.Scan(&i); err != nil {
  47. t.Fatal(err)
  48. }
  49. if i != 4 {
  50. t.Fatalf("expected 4, got %d", i)
  51. }
  52. }
  53. if !rows.NextResultSet() {
  54. t.Fatal("expected more result sets", rows.Err())
  55. }
  56. for rows.Next() {
  57. if err := rows.Scan(&i); err != nil {
  58. t.Fatal(err)
  59. }
  60. if i != 5 {
  61. t.Fatalf("expected 5, got %d", i)
  62. }
  63. }
  64. if rows.NextResultSet() {
  65. t.Fatal("unexpected result set")
  66. }
  67. }
  68. const contextRaceIterations = 100
  69. func TestContextCancelExec(t *testing.T) {
  70. db := openTestConn(t)
  71. defer db.Close()
  72. ctx, cancel := context.WithCancel(context.Background())
  73. // Delay execution for just a bit until db.ExecContext has begun.
  74. defer time.AfterFunc(time.Millisecond*10, cancel).Stop()
  75. // Not canceled until after the exec has started.
  76. if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil {
  77. t.Fatal("expected error")
  78. } else if err.Error() != "pq: canceling statement due to user request" {
  79. t.Fatalf("unexpected error: %s", err)
  80. }
  81. // Context is already canceled, so error should come before execution.
  82. if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil {
  83. t.Fatal("expected error")
  84. } else if err.Error() != "context canceled" {
  85. t.Fatalf("unexpected error: %s", err)
  86. }
  87. for i := 0; i < contextRaceIterations; i++ {
  88. func() {
  89. ctx, cancel := context.WithCancel(context.Background())
  90. defer cancel()
  91. if _, err := db.ExecContext(ctx, "select 1"); err != nil {
  92. t.Fatal(err)
  93. }
  94. }()
  95. if _, err := db.Exec("select 1"); err != nil {
  96. t.Fatal(err)
  97. }
  98. }
  99. }
  100. func TestContextCancelQuery(t *testing.T) {
  101. db := openTestConn(t)
  102. defer db.Close()
  103. ctx, cancel := context.WithCancel(context.Background())
  104. // Delay execution for just a bit until db.QueryContext has begun.
  105. defer time.AfterFunc(time.Millisecond*10, cancel).Stop()
  106. // Not canceled until after the exec has started.
  107. if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil {
  108. t.Fatal("expected error")
  109. } else if err.Error() != "pq: canceling statement due to user request" {
  110. t.Fatalf("unexpected error: %s", err)
  111. }
  112. // Context is already canceled, so error should come before execution.
  113. if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil {
  114. t.Fatal("expected error")
  115. } else if err.Error() != "context canceled" {
  116. t.Fatalf("unexpected error: %s", err)
  117. }
  118. for i := 0; i < contextRaceIterations; i++ {
  119. func() {
  120. ctx, cancel := context.WithCancel(context.Background())
  121. rows, err := db.QueryContext(ctx, "select 1")
  122. cancel()
  123. if err != nil {
  124. t.Fatal(err)
  125. } else if err := rows.Close(); err != nil {
  126. t.Fatal(err)
  127. }
  128. }()
  129. if rows, err := db.Query("select 1"); err != nil {
  130. t.Fatal(err)
  131. } else if err := rows.Close(); err != nil {
  132. t.Fatal(err)
  133. }
  134. }
  135. }
  136. // TestIssue617 tests that a failed query in QueryContext doesn't lead to a
  137. // goroutine leak.
  138. func TestIssue617(t *testing.T) {
  139. db := openTestConn(t)
  140. defer db.Close()
  141. const N = 10
  142. numGoroutineStart := runtime.NumGoroutine()
  143. for i := 0; i < N; i++ {
  144. func() {
  145. ctx, cancel := context.WithCancel(context.Background())
  146. defer cancel()
  147. _, err := db.QueryContext(ctx, `SELECT * FROM DOESNOTEXIST`)
  148. pqErr, _ := err.(*Error)
  149. // Expecting "pq: relation \"doesnotexist\" does not exist" error.
  150. if err == nil || pqErr == nil || pqErr.Code != "42P01" {
  151. t.Fatalf("expected undefined table error, got %v", err)
  152. }
  153. }()
  154. }
  155. numGoroutineFinish := runtime.NumGoroutine()
  156. // We use N/2 and not N because the GC and other actors may increase or
  157. // decrease the number of goroutines.
  158. if numGoroutineFinish-numGoroutineStart >= N/2 {
  159. t.Errorf("goroutine leak detected, was %d, now %d", numGoroutineStart, numGoroutineFinish)
  160. }
  161. }
  162. func TestContextCancelBegin(t *testing.T) {
  163. db := openTestConn(t)
  164. defer db.Close()
  165. ctx, cancel := context.WithCancel(context.Background())
  166. tx, err := db.BeginTx(ctx, nil)
  167. if err != nil {
  168. t.Fatal(err)
  169. }
  170. // Delay execution for just a bit until tx.Exec has begun.
  171. defer time.AfterFunc(time.Millisecond*10, cancel).Stop()
  172. // Not canceled until after the exec has started.
  173. if _, err := tx.Exec("select pg_sleep(1)"); err == nil {
  174. t.Fatal("expected error")
  175. } else if err.Error() != "pq: canceling statement due to user request" {
  176. t.Fatalf("unexpected error: %s", err)
  177. }
  178. // Transaction is canceled, so expect an error.
  179. if _, err := tx.Query("select pg_sleep(1)"); err == nil {
  180. t.Fatal("expected error")
  181. } else if err != sql.ErrTxDone {
  182. t.Fatalf("unexpected error: %s", err)
  183. }
  184. // Context is canceled, so cannot begin a transaction.
  185. if _, err := db.BeginTx(ctx, nil); err == nil {
  186. t.Fatal("expected error")
  187. } else if err.Error() != "context canceled" {
  188. t.Fatalf("unexpected error: %s", err)
  189. }
  190. for i := 0; i < contextRaceIterations; i++ {
  191. func() {
  192. ctx, cancel := context.WithCancel(context.Background())
  193. tx, err := db.BeginTx(ctx, nil)
  194. cancel()
  195. if err != nil {
  196. t.Fatal(err)
  197. } else if err := tx.Rollback(); err != nil && err != sql.ErrTxDone {
  198. t.Fatal(err)
  199. }
  200. }()
  201. if tx, err := db.Begin(); err != nil {
  202. t.Fatal(err)
  203. } else if err := tx.Rollback(); err != nil {
  204. t.Fatal(err)
  205. }
  206. }
  207. }
  208. func TestTxOptions(t *testing.T) {
  209. db := openTestConn(t)
  210. defer db.Close()
  211. ctx := context.Background()
  212. tests := []struct {
  213. level sql.IsolationLevel
  214. isolation string
  215. }{
  216. {
  217. level: sql.LevelDefault,
  218. isolation: "",
  219. },
  220. {
  221. level: sql.LevelReadUncommitted,
  222. isolation: "read uncommitted",
  223. },
  224. {
  225. level: sql.LevelReadCommitted,
  226. isolation: "read committed",
  227. },
  228. {
  229. level: sql.LevelRepeatableRead,
  230. isolation: "repeatable read",
  231. },
  232. {
  233. level: sql.LevelSerializable,
  234. isolation: "serializable",
  235. },
  236. }
  237. for _, test := range tests {
  238. for _, ro := range []bool{true, false} {
  239. tx, err := db.BeginTx(ctx, &sql.TxOptions{
  240. Isolation: test.level,
  241. ReadOnly: ro,
  242. })
  243. if err != nil {
  244. t.Fatal(err)
  245. }
  246. var isolation string
  247. err = tx.QueryRow("select current_setting('transaction_isolation')").Scan(&isolation)
  248. if err != nil {
  249. t.Fatal(err)
  250. }
  251. if test.isolation != "" && isolation != test.isolation {
  252. t.Errorf("wrong isolation level: %s != %s", isolation, test.isolation)
  253. }
  254. var isRO string
  255. err = tx.QueryRow("select current_setting('transaction_read_only')").Scan(&isRO)
  256. if err != nil {
  257. t.Fatal(err)
  258. }
  259. if ro != (isRO == "on") {
  260. t.Errorf("read/[write,only] not set: %t != %s for level %s",
  261. ro, isRO, test.isolation)
  262. }
  263. tx.Rollback()
  264. }
  265. }
  266. _, err := db.BeginTx(ctx, &sql.TxOptions{
  267. Isolation: sql.LevelLinearizable,
  268. })
  269. if err == nil {
  270. t.Fatal("expected LevelLinearizable to fail")
  271. }
  272. if !strings.Contains(err.Error(), "isolation level not supported") {
  273. t.Errorf("Expected error to mention isolation level, got %q", err)
  274. }
  275. }