go18_test.go 7.6 KB

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