1 package pgconn_test
2
3 import (
4 "bytes"
5 "context"
6 "os"
7 "strings"
8 "testing"
9
10 "github.com/jackc/pgconn"
11 "github.com/stretchr/testify/require"
12 )
13
14 func BenchmarkConnect(b *testing.B) {
15 benchmarks := []struct {
16 name string
17 env string
18 }{
19 {"Unix socket", "PGX_TEST_UNIX_SOCKET_CONN_STRING"},
20 {"TCP", "PGX_TEST_TCP_CONN_STRING"},
21 }
22
23 for _, bm := range benchmarks {
24 bm := bm
25 b.Run(bm.name, func(b *testing.B) {
26 connString := os.Getenv(bm.env)
27 if connString == "" {
28 b.Skipf("Skipping due to missing environment variable %v", bm.env)
29 }
30
31 for i := 0; i < b.N; i++ {
32 conn, err := pgconn.Connect(context.Background(), connString)
33 require.Nil(b, err)
34
35 err = conn.Close(context.Background())
36 require.Nil(b, err)
37 }
38 })
39 }
40 }
41
42 func BenchmarkExec(b *testing.B) {
43 expectedValues := [][]byte{[]byte("hello"), []byte("42"), []byte("2019-01-01")}
44 benchmarks := []struct {
45 name string
46 ctx context.Context
47 }{
48
49
50 {"background context", context.Background()},
51 {"empty context", context.TODO()},
52 }
53
54 for _, bm := range benchmarks {
55 bm := bm
56 b.Run(bm.name, func(b *testing.B) {
57 conn, err := pgconn.Connect(bm.ctx, os.Getenv("PGX_TEST_CONN_STRING"))
58 require.Nil(b, err)
59 defer closeConn(b, conn)
60
61 b.ResetTimer()
62
63 for i := 0; i < b.N; i++ {
64 mrr := conn.Exec(bm.ctx, "select 'hello'::text as a, 42::int4 as b, '2019-01-01'::date")
65
66 for mrr.NextResult() {
67 rr := mrr.ResultReader()
68
69 rowCount := 0
70 for rr.NextRow() {
71 rowCount++
72 if len(rr.Values()) != len(expectedValues) {
73 b.Fatalf("unexpected number of values: %d", len(rr.Values()))
74 }
75 for i := range rr.Values() {
76 if !bytes.Equal(rr.Values()[i], expectedValues[i]) {
77 b.Fatalf("unexpected values: %s %s", rr.Values()[i], expectedValues[i])
78 }
79 }
80 }
81 _, err = rr.Close()
82
83 if err != nil {
84 b.Fatal(err)
85 }
86 if rowCount != 1 {
87 b.Fatalf("unexpected rowCount: %d", rowCount)
88 }
89 }
90
91 err := mrr.Close()
92 if err != nil {
93 b.Fatal(err)
94 }
95 }
96 })
97 }
98 }
99
100 func BenchmarkExecPossibleToCancel(b *testing.B) {
101 conn, err := pgconn.Connect(context.Background(), os.Getenv("PGX_TEST_CONN_STRING"))
102 require.Nil(b, err)
103 defer closeConn(b, conn)
104
105 expectedValues := [][]byte{[]byte("hello"), []byte("42"), []byte("2019-01-01")}
106
107 b.ResetTimer()
108
109 ctx, cancel := context.WithCancel(context.Background())
110 defer cancel()
111
112 for i := 0; i < b.N; i++ {
113 mrr := conn.Exec(ctx, "select 'hello'::text as a, 42::int4 as b, '2019-01-01'::date")
114
115 for mrr.NextResult() {
116 rr := mrr.ResultReader()
117
118 rowCount := 0
119 for rr.NextRow() {
120 rowCount++
121 if len(rr.Values()) != len(expectedValues) {
122 b.Fatalf("unexpected number of values: %d", len(rr.Values()))
123 }
124 for i := range rr.Values() {
125 if !bytes.Equal(rr.Values()[i], expectedValues[i]) {
126 b.Fatalf("unexpected values: %s %s", rr.Values()[i], expectedValues[i])
127 }
128 }
129 }
130 _, err = rr.Close()
131
132 if err != nil {
133 b.Fatal(err)
134 }
135 if rowCount != 1 {
136 b.Fatalf("unexpected rowCount: %d", rowCount)
137 }
138 }
139
140 err := mrr.Close()
141 if err != nil {
142 b.Fatal(err)
143 }
144 }
145 }
146
147 func BenchmarkExecPrepared(b *testing.B) {
148 expectedValues := [][]byte{[]byte("hello"), []byte("42"), []byte("2019-01-01")}
149
150 benchmarks := []struct {
151 name string
152 ctx context.Context
153 }{
154
155
156 {"background context", context.Background()},
157 {"empty context", context.TODO()},
158 }
159
160 for _, bm := range benchmarks {
161 bm := bm
162 b.Run(bm.name, func(b *testing.B) {
163 conn, err := pgconn.Connect(bm.ctx, os.Getenv("PGX_TEST_CONN_STRING"))
164 require.Nil(b, err)
165 defer closeConn(b, conn)
166
167 _, err = conn.Prepare(bm.ctx, "ps1", "select 'hello'::text as a, 42::int4 as b, '2019-01-01'::date", nil)
168 require.Nil(b, err)
169
170 b.ResetTimer()
171
172 for i := 0; i < b.N; i++ {
173 rr := conn.ExecPrepared(bm.ctx, "ps1", nil, nil, nil)
174
175 rowCount := 0
176 for rr.NextRow() {
177 rowCount++
178 if len(rr.Values()) != len(expectedValues) {
179 b.Fatalf("unexpected number of values: %d", len(rr.Values()))
180 }
181 for i := range rr.Values() {
182 if !bytes.Equal(rr.Values()[i], expectedValues[i]) {
183 b.Fatalf("unexpected values: %s %s", rr.Values()[i], expectedValues[i])
184 }
185 }
186 }
187 _, err = rr.Close()
188
189 if err != nil {
190 b.Fatal(err)
191 }
192 if rowCount != 1 {
193 b.Fatalf("unexpected rowCount: %d", rowCount)
194 }
195 }
196 })
197 }
198 }
199
200 func BenchmarkExecPreparedPossibleToCancel(b *testing.B) {
201 conn, err := pgconn.Connect(context.Background(), os.Getenv("PGX_TEST_CONN_STRING"))
202 require.Nil(b, err)
203 defer closeConn(b, conn)
204
205 ctx, cancel := context.WithCancel(context.Background())
206 defer cancel()
207
208 _, err = conn.Prepare(ctx, "ps1", "select 'hello'::text as a, 42::int4 as b, '2019-01-01'::date", nil)
209 require.Nil(b, err)
210
211 expectedValues := [][]byte{[]byte("hello"), []byte("42"), []byte("2019-01-01")}
212
213 b.ResetTimer()
214
215 for i := 0; i < b.N; i++ {
216 rr := conn.ExecPrepared(ctx, "ps1", nil, nil, nil)
217
218 rowCount := 0
219 for rr.NextRow() {
220 rowCount += 1
221 if len(rr.Values()) != len(expectedValues) {
222 b.Fatalf("unexpected number of values: %d", len(rr.Values()))
223 }
224 for i := range rr.Values() {
225 if !bytes.Equal(rr.Values()[i], expectedValues[i]) {
226 b.Fatalf("unexpected values: %s %s", rr.Values()[i], expectedValues[i])
227 }
228 }
229 }
230 _, err = rr.Close()
231
232 if err != nil {
233 b.Fatal(err)
234 }
235 if rowCount != 1 {
236 b.Fatalf("unexpected rowCount: %d", rowCount)
237 }
238 }
239 }
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257 func BenchmarkCommandTagRowsAffected(b *testing.B) {
258 benchmarks := []struct {
259 commandTag string
260 rowsAffected int64
261 }{
262 {"UPDATE 1", 1},
263 {"UPDATE 123456789", 123456789},
264 {"INSERT 0 1", 1},
265 {"INSERT 0 123456789", 123456789},
266 }
267
268 for _, bm := range benchmarks {
269 ct := pgconn.CommandTag(bm.commandTag)
270 b.Run(bm.commandTag, func(b *testing.B) {
271 var n int64
272 for i := 0; i < b.N; i++ {
273 n = ct.RowsAffected()
274 }
275 if n != bm.rowsAffected {
276 b.Errorf("expected %d got %d", bm.rowsAffected, n)
277 }
278 })
279 }
280 }
281
282 func BenchmarkCommandTagTypeFromString(b *testing.B) {
283 ct := pgconn.CommandTag("UPDATE 1")
284
285 var update bool
286 for i := 0; i < b.N; i++ {
287 update = strings.HasPrefix(ct.String(), "UPDATE")
288 }
289 if !update {
290 b.Error("expected update")
291 }
292 }
293
294 func BenchmarkCommandTagInsert(b *testing.B) {
295 benchmarks := []struct {
296 commandTag string
297 is bool
298 }{
299 {"INSERT 1", true},
300 {"INSERT 1234567890", true},
301 {"UPDATE 1", false},
302 {"UPDATE 1234567890", false},
303 {"DELETE 1", false},
304 {"DELETE 1234567890", false},
305 {"SELECT 1", false},
306 {"SELECT 1234567890", false},
307 {"UNKNOWN 1234567890", false},
308 }
309
310 for _, bm := range benchmarks {
311 ct := pgconn.CommandTag(bm.commandTag)
312 b.Run(bm.commandTag, func(b *testing.B) {
313 var is bool
314 for i := 0; i < b.N; i++ {
315 is = ct.Insert()
316 }
317 if is != bm.is {
318 b.Errorf("expected %v got %v", bm.is, is)
319 }
320 })
321 }
322 }
323
View as plain text