1package pq
2
3import (
4	"database/sql"
5	"database/sql/driver"
6	"fmt"
7	"io"
8	"net"
9	"os"
10	"reflect"
11	"strings"
12	"testing"
13	"time"
14)
15
16type Fatalistic interface {
17	Fatal(args ...interface{})
18}
19
20func forceBinaryParameters() bool {
21	bp := os.Getenv("PQTEST_BINARY_PARAMETERS")
22	if bp == "yes" {
23		return true
24	} else if bp == "" || bp == "no" {
25		return false
26	} else {
27		panic("unexpected value for PQTEST_BINARY_PARAMETERS")
28	}
29}
30
31func openTestConnConninfo(conninfo string) (*sql.DB, error) {
32	defaultTo := func(envvar string, value string) {
33		if os.Getenv(envvar) == "" {
34			os.Setenv(envvar, value)
35		}
36	}
37	defaultTo("PGDATABASE", "pqgotest")
38	defaultTo("PGSSLMODE", "disable")
39	defaultTo("PGCONNECT_TIMEOUT", "20")
40
41	if forceBinaryParameters() &&
42		!strings.HasPrefix(conninfo, "postgres://") &&
43		!strings.HasPrefix(conninfo, "postgresql://") {
44		conninfo = conninfo + " binary_parameters=yes"
45	}
46
47	return sql.Open("postgres", conninfo)
48}
49
50func openTestConn(t Fatalistic) *sql.DB {
51	conn, err := openTestConnConninfo("")
52	if err != nil {
53		t.Fatal(err)
54	}
55
56	return conn
57}
58
59func getServerVersion(t *testing.T, db *sql.DB) int {
60	var version int
61	err := db.QueryRow("SHOW server_version_num").Scan(&version)
62	if err != nil {
63		t.Fatal(err)
64	}
65	return version
66}
67
68func TestReconnect(t *testing.T) {
69	db1 := openTestConn(t)
70	defer db1.Close()
71	tx, err := db1.Begin()
72	if err != nil {
73		t.Fatal(err)
74	}
75	var pid1 int
76	err = tx.QueryRow("SELECT pg_backend_pid()").Scan(&pid1)
77	if err != nil {
78		t.Fatal(err)
79	}
80	db2 := openTestConn(t)
81	defer db2.Close()
82	_, err = db2.Exec("SELECT pg_terminate_backend($1)", pid1)
83	if err != nil {
84		t.Fatal(err)
85	}
86	// The rollback will probably "fail" because we just killed
87	// its connection above
88	_ = tx.Rollback()
89
90	const expected int = 42
91	var result int
92	err = db1.QueryRow(fmt.Sprintf("SELECT %d", expected)).Scan(&result)
93	if err != nil {
94		t.Fatal(err)
95	}
96	if result != expected {
97		t.Errorf("got %v; expected %v", result, expected)
98	}
99}
100
101func TestCommitInFailedTransaction(t *testing.T) {
102	db := openTestConn(t)
103	defer db.Close()
104
105	txn, err := db.Begin()
106	if err != nil {
107		t.Fatal(err)
108	}
109	rows, err := txn.Query("SELECT error")
110	if err == nil {
111		rows.Close()
112		t.Fatal("expected failure")
113	}
114	err = txn.Commit()
115	if err != ErrInFailedTransaction {
116		t.Fatalf("expected ErrInFailedTransaction; got %#v", err)
117	}
118}
119
120func TestOpenURL(t *testing.T) {
121	testURL := func(url string) {
122		db, err := openTestConnConninfo(url)
123		if err != nil {
124			t.Fatal(err)
125		}
126		defer db.Close()
127		// database/sql might not call our Open at all unless we do something with
128		// the connection
129		txn, err := db.Begin()
130		if err != nil {
131			t.Fatal(err)
132		}
133		txn.Rollback()
134	}
135	testURL("postgres://")
136	testURL("postgresql://")
137}
138
139const pgpass_file = "/tmp/pqgotest_pgpass"
140
141func TestPgpass(t *testing.T) {
142	if os.Getenv("TRAVIS") != "true" {
143		t.Skip("not running under Travis, skipping pgpass tests")
144	}
145
146	testAssert := func(conninfo string, expected string, reason string) {
147		conn, err := openTestConnConninfo(conninfo)
148		if err != nil {
149			t.Fatal(err)
150		}
151		defer conn.Close()
152
153		txn, err := conn.Begin()
154		if err != nil {
155			if expected != "fail" {
156				t.Fatalf(reason, err)
157			}
158			return
159		}
160		rows, err := txn.Query("SELECT USER")
161		if err != nil {
162			txn.Rollback()
163			rows.Close()
164			if expected != "fail" {
165				t.Fatalf(reason, err)
166			}
167		} else {
168			if expected != "ok" {
169				t.Fatalf(reason, err)
170			}
171		}
172		txn.Rollback()
173	}
174	testAssert("", "ok", "missing .pgpass, unexpected error %#v")
175	os.Setenv("PGPASSFILE", pgpass_file)
176	testAssert("host=/tmp", "fail", ", unexpected error %#v")
177	os.Remove(pgpass_file)
178	pgpass, err := os.OpenFile(pgpass_file, os.O_RDWR|os.O_CREATE, 0644)
179	if err != nil {
180		t.Fatalf("Unexpected error writing pgpass file %#v", err)
181	}
182	_, err = pgpass.WriteString(`# comment
183server:5432:some_db:some_user:pass_A
184*:5432:some_db:some_user:pass_B
185localhost:*:*:*:pass_C
186*:*:*:*:pass_fallback
187`)
188	if err != nil {
189		t.Fatalf("Unexpected error writing pgpass file %#v", err)
190	}
191	pgpass.Close()
192
193	assertPassword := func(extra values, expected string) {
194		o := values{
195			"host":               "localhost",
196			"sslmode":            "disable",
197			"connect_timeout":    "20",
198			"user":               "majid",
199			"port":               "5432",
200			"extra_float_digits": "2",
201			"dbname":             "pqgotest",
202			"client_encoding":    "UTF8",
203			"datestyle":          "ISO, MDY",
204		}
205		for k, v := range extra {
206			o[k] = v
207		}
208		(&conn{}).handlePgpass(o)
209		if pw := o["password"]; pw != expected {
210			t.Fatalf("For %v expected %s got %s", extra, expected, pw)
211		}
212	}
213	// wrong permissions for the pgpass file means it should be ignored
214	assertPassword(values{"host": "example.com", "user": "foo"}, "")
215	// fix the permissions and check if it has taken effect
216	os.Chmod(pgpass_file, 0600)
217	assertPassword(values{"host": "server", "dbname": "some_db", "user": "some_user"}, "pass_A")
218	assertPassword(values{"host": "example.com", "user": "foo"}, "pass_fallback")
219	assertPassword(values{"host": "example.com", "dbname": "some_db", "user": "some_user"}, "pass_B")
220	// localhost also matches the default "" and UNIX sockets
221	assertPassword(values{"host": "", "user": "some_user"}, "pass_C")
222	assertPassword(values{"host": "/tmp", "user": "some_user"}, "pass_C")
223	// cleanup
224	os.Remove(pgpass_file)
225	os.Setenv("PGPASSFILE", "")
226}
227
228func TestExec(t *testing.T) {
229	db := openTestConn(t)
230	defer db.Close()
231
232	_, err := db.Exec("CREATE TEMP TABLE temp (a int)")
233	if err != nil {
234		t.Fatal(err)
235	}
236
237	r, err := db.Exec("INSERT INTO temp VALUES (1)")
238	if err != nil {
239		t.Fatal(err)
240	}
241
242	if n, _ := r.RowsAffected(); n != 1 {
243		t.Fatalf("expected 1 row affected, not %d", n)
244	}
245
246	r, err = db.Exec("INSERT INTO temp VALUES ($1), ($2), ($3)", 1, 2, 3)
247	if err != nil {
248		t.Fatal(err)
249	}
250
251	if n, _ := r.RowsAffected(); n != 3 {
252		t.Fatalf("expected 3 rows affected, not %d", n)
253	}
254
255	// SELECT doesn't send the number of returned rows in the command tag
256	// before 9.0
257	if getServerVersion(t, db) >= 90000 {
258		r, err = db.Exec("SELECT g FROM generate_series(1, 2) g")
259		if err != nil {
260			t.Fatal(err)
261		}
262		if n, _ := r.RowsAffected(); n != 2 {
263			t.Fatalf("expected 2 rows affected, not %d", n)
264		}
265
266		r, err = db.Exec("SELECT g FROM generate_series(1, $1) g", 3)
267		if err != nil {
268			t.Fatal(err)
269		}
270		if n, _ := r.RowsAffected(); n != 3 {
271			t.Fatalf("expected 3 rows affected, not %d", n)
272		}
273	}
274}
275
276func TestStatment(t *testing.T) {
277	db := openTestConn(t)
278	defer db.Close()
279
280	st, err := db.Prepare("SELECT 1")
281	if err != nil {
282		t.Fatal(err)
283	}
284
285	st1, err := db.Prepare("SELECT 2")
286	if err != nil {
287		t.Fatal(err)
288	}
289
290	r, err := st.Query()
291	if err != nil {
292		t.Fatal(err)
293	}
294	defer r.Close()
295
296	if !r.Next() {
297		t.Fatal("expected row")
298	}
299
300	var i int
301	err = r.Scan(&i)
302	if err != nil {
303		t.Fatal(err)
304	}
305
306	if i != 1 {
307		t.Fatalf("expected 1, got %d", i)
308	}
309
310	// st1
311
312	r1, err := st1.Query()
313	if err != nil {
314		t.Fatal(err)
315	}
316	defer r1.Close()
317
318	if !r1.Next() {
319		if r.Err() != nil {
320			t.Fatal(r1.Err())
321		}
322		t.Fatal("expected row")
323	}
324
325	err = r1.Scan(&i)
326	if err != nil {
327		t.Fatal(err)
328	}
329
330	if i != 2 {
331		t.Fatalf("expected 2, got %d", i)
332	}
333}
334
335func TestRowsCloseBeforeDone(t *testing.T) {
336	db := openTestConn(t)
337	defer db.Close()
338
339	r, err := db.Query("SELECT 1")
340	if err != nil {
341		t.Fatal(err)
342	}
343
344	err = r.Close()
345	if err != nil {
346		t.Fatal(err)
347	}
348
349	if r.Next() {
350		t.Fatal("unexpected row")
351	}
352
353	if r.Err() != nil {
354		t.Fatal(r.Err())
355	}
356}
357
358func TestParameterCountMismatch(t *testing.T) {
359	db := openTestConn(t)
360	defer db.Close()
361
362	var notused int
363	err := db.QueryRow("SELECT false", 1).Scan(&notused)
364	if err == nil {
365		t.Fatal("expected err")
366	}
367	// make sure we clean up correctly
368	err = db.QueryRow("SELECT 1").Scan(&notused)
369	if err != nil {
370		t.Fatal(err)
371	}
372
373	err = db.QueryRow("SELECT $1").Scan(&notused)
374	if err == nil {
375		t.Fatal("expected err")
376	}
377	// make sure we clean up correctly
378	err = db.QueryRow("SELECT 1").Scan(&notused)
379	if err != nil {
380		t.Fatal(err)
381	}
382}
383
384// Test that EmptyQueryResponses are handled correctly.
385func TestEmptyQuery(t *testing.T) {
386	db := openTestConn(t)
387	defer db.Close()
388
389	res, err := db.Exec("")
390	if err != nil {
391		t.Fatal(err)
392	}
393	if _, err := res.RowsAffected(); err != errNoRowsAffected {
394		t.Fatalf("expected %s, got %v", errNoRowsAffected, err)
395	}
396	if _, err := res.LastInsertId(); err != errNoLastInsertId {
397		t.Fatalf("expected %s, got %v", errNoLastInsertId, err)
398	}
399	rows, err := db.Query("")
400	if err != nil {
401		t.Fatal(err)
402	}
403	cols, err := rows.Columns()
404	if err != nil {
405		t.Fatal(err)
406	}
407	if len(cols) != 0 {
408		t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
409	}
410	if rows.Next() {
411		t.Fatal("unexpected row")
412	}
413	if rows.Err() != nil {
414		t.Fatal(rows.Err())
415	}
416
417	stmt, err := db.Prepare("")
418	if err != nil {
419		t.Fatal(err)
420	}
421	res, err = stmt.Exec()
422	if err != nil {
423		t.Fatal(err)
424	}
425	if _, err := res.RowsAffected(); err != errNoRowsAffected {
426		t.Fatalf("expected %s, got %v", errNoRowsAffected, err)
427	}
428	if _, err := res.LastInsertId(); err != errNoLastInsertId {
429		t.Fatalf("expected %s, got %v", errNoLastInsertId, err)
430	}
431	rows, err = stmt.Query()
432	if err != nil {
433		t.Fatal(err)
434	}
435	cols, err = rows.Columns()
436	if err != nil {
437		t.Fatal(err)
438	}
439	if len(cols) != 0 {
440		t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
441	}
442	if rows.Next() {
443		t.Fatal("unexpected row")
444	}
445	if rows.Err() != nil {
446		t.Fatal(rows.Err())
447	}
448}
449
450// Test that rows.Columns() is correct even if there are no result rows.
451func TestEmptyResultSetColumns(t *testing.T) {
452	db := openTestConn(t)
453	defer db.Close()
454
455	rows, err := db.Query("SELECT 1 AS a, text 'bar' AS bar WHERE FALSE")
456	if err != nil {
457		t.Fatal(err)
458	}
459	cols, err := rows.Columns()
460	if err != nil {
461		t.Fatal(err)
462	}
463	if len(cols) != 2 {
464		t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
465	}
466	if rows.Next() {
467		t.Fatal("unexpected row")
468	}
469	if rows.Err() != nil {
470		t.Fatal(rows.Err())
471	}
472	if cols[0] != "a" || cols[1] != "bar" {
473		t.Fatalf("unexpected Columns result %v", cols)
474	}
475
476	stmt, err := db.Prepare("SELECT $1::int AS a, text 'bar' AS bar WHERE FALSE")
477	if err != nil {
478		t.Fatal(err)
479	}
480	rows, err = stmt.Query(1)
481	if err != nil {
482		t.Fatal(err)
483	}
484	cols, err = rows.Columns()
485	if err != nil {
486		t.Fatal(err)
487	}
488	if len(cols) != 2 {
489		t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
490	}
491	if rows.Next() {
492		t.Fatal("unexpected row")
493	}
494	if rows.Err() != nil {
495		t.Fatal(rows.Err())
496	}
497	if cols[0] != "a" || cols[1] != "bar" {
498		t.Fatalf("unexpected Columns result %v", cols)
499	}
500
501}
502
503func TestEncodeDecode(t *testing.T) {
504	db := openTestConn(t)
505	defer db.Close()
506
507	q := `
508		SELECT
509			E'\\000\\001\\002'::bytea,
510			'foobar'::text,
511			NULL::integer,
512			'2000-1-1 01:02:03.04-7'::timestamptz,
513			0::boolean,
514			123,
515			-321,
516			3.14::float8
517		WHERE
518			    E'\\000\\001\\002'::bytea = $1
519			AND 'foobar'::text = $2
520			AND $3::integer is NULL
521	`
522	// AND '2000-1-1 12:00:00.000000-7'::timestamp = $3
523
524	exp1 := []byte{0, 1, 2}
525	exp2 := "foobar"
526
527	r, err := db.Query(q, exp1, exp2, nil)
528	if err != nil {
529		t.Fatal(err)
530	}
531	defer r.Close()
532
533	if !r.Next() {
534		if r.Err() != nil {
535			t.Fatal(r.Err())
536		}
537		t.Fatal("expected row")
538	}
539
540	var got1 []byte
541	var got2 string
542	var got3 = sql.NullInt64{Valid: true}
543	var got4 time.Time
544	var got5, got6, got7, got8 interface{}
545
546	err = r.Scan(&got1, &got2, &got3, &got4, &got5, &got6, &got7, &got8)
547	if err != nil {
548		t.Fatal(err)
549	}
550
551	if !reflect.DeepEqual(exp1, got1) {
552		t.Errorf("expected %q byte: %q", exp1, got1)
553	}
554
555	if !reflect.DeepEqual(exp2, got2) {
556		t.Errorf("expected %q byte: %q", exp2, got2)
557	}
558
559	if got3.Valid {
560		t.Fatal("expected invalid")
561	}
562
563	if got4.Year() != 2000 {
564		t.Fatal("wrong year")
565	}
566
567	if got5 != false {
568		t.Fatalf("expected false, got %q", got5)
569	}
570
571	if got6 != int64(123) {
572		t.Fatalf("expected 123, got %d", got6)
573	}
574
575	if got7 != int64(-321) {
576		t.Fatalf("expected -321, got %d", got7)
577	}
578
579	if got8 != float64(3.14) {
580		t.Fatalf("expected 3.14, got %f", got8)
581	}
582}
583
584func TestNoData(t *testing.T) {
585	db := openTestConn(t)
586	defer db.Close()
587
588	st, err := db.Prepare("SELECT 1 WHERE true = false")
589	if err != nil {
590		t.Fatal(err)
591	}
592	defer st.Close()
593
594	r, err := st.Query()
595	if err != nil {
596		t.Fatal(err)
597	}
598	defer r.Close()
599
600	if r.Next() {
601		if r.Err() != nil {
602			t.Fatal(r.Err())
603		}
604		t.Fatal("unexpected row")
605	}
606
607	_, err = db.Query("SELECT * FROM nonexistenttable WHERE age=$1", 20)
608	if err == nil {
609		t.Fatal("Should have raised an error on non existent table")
610	}
611
612	_, err = db.Query("SELECT * FROM nonexistenttable")
613	if err == nil {
614		t.Fatal("Should have raised an error on non existent table")
615	}
616}
617
618func TestErrorDuringStartup(t *testing.T) {
619	// Don't use the normal connection setup, this is intended to
620	// blow up in the startup packet from a non-existent user.
621	db, err := openTestConnConninfo("user=thisuserreallydoesntexist")
622	if err != nil {
623		t.Fatal(err)
624	}
625	defer db.Close()
626
627	_, err = db.Begin()
628	if err == nil {
629		t.Fatal("expected error")
630	}
631
632	e, ok := err.(*Error)
633	if !ok {
634		t.Fatalf("expected Error, got %#v", err)
635	} else if e.Code.Name() != "invalid_authorization_specification" && e.Code.Name() != "invalid_password" {
636		t.Fatalf("expected invalid_authorization_specification or invalid_password, got %s (%+v)", e.Code.Name(), err)
637	}
638}
639
640func TestBadConn(t *testing.T) {
641	var err error
642
643	cn := conn{}
644	func() {
645		defer cn.errRecover(&err)
646		panic(io.EOF)
647	}()
648	if err != driver.ErrBadConn {
649		t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
650	}
651	if !cn.bad {
652		t.Fatalf("expected cn.bad")
653	}
654
655	cn = conn{}
656	func() {
657		defer cn.errRecover(&err)
658		e := &Error{Severity: Efatal}
659		panic(e)
660	}()
661	if err != driver.ErrBadConn {
662		t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
663	}
664	if !cn.bad {
665		t.Fatalf("expected cn.bad")
666	}
667}
668
669// TestCloseBadConn tests that the underlying connection can be closed with
670// Close after an error.
671func TestCloseBadConn(t *testing.T) {
672	nc, err := net.Dial("tcp", "localhost:5432")
673	if err != nil {
674		t.Fatal(err)
675	}
676	cn := conn{c: nc}
677	func() {
678		defer cn.errRecover(&err)
679		panic(io.EOF)
680	}()
681	// Verify we can write before closing.
682	if _, err := nc.Write(nil); err != nil {
683		t.Fatal(err)
684	}
685	// First close should close the connection.
686	if err := cn.Close(); err != nil {
687		t.Fatal(err)
688	}
689
690	// During the Go 1.9 cycle, https://github.com/golang/go/commit/3792db5
691	// changed this error from
692	//
693	// net.errClosing = errors.New("use of closed network connection")
694	//
695	// to
696	//
697	// internal/poll.ErrClosing = errors.New("use of closed file or network connection")
698	const errClosing = "use of closed"
699
700	// Verify write after closing fails.
701	if _, err := nc.Write(nil); err == nil {
702		t.Fatal("expected error")
703	} else if !strings.Contains(err.Error(), errClosing) {
704		t.Fatalf("expected %s error, got %s", errClosing, err)
705	}
706	// Verify second close fails.
707	if err := cn.Close(); err == nil {
708		t.Fatal("expected error")
709	} else if !strings.Contains(err.Error(), errClosing) {
710		t.Fatalf("expected %s error, got %s", errClosing, err)
711	}
712}
713
714func TestErrorOnExec(t *testing.T) {
715	db := openTestConn(t)
716	defer db.Close()
717
718	txn, err := db.Begin()
719	if err != nil {
720		t.Fatal(err)
721	}
722	defer txn.Rollback()
723
724	_, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
725	if err != nil {
726		t.Fatal(err)
727	}
728
729	_, err = txn.Exec("INSERT INTO foo VALUES (0), (0)")
730	if err == nil {
731		t.Fatal("Should have raised error")
732	}
733
734	e, ok := err.(*Error)
735	if !ok {
736		t.Fatalf("expected Error, got %#v", err)
737	} else if e.Code.Name() != "unique_violation" {
738		t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
739	}
740}
741
742func TestErrorOnQuery(t *testing.T) {
743	db := openTestConn(t)
744	defer db.Close()
745
746	txn, err := db.Begin()
747	if err != nil {
748		t.Fatal(err)
749	}
750	defer txn.Rollback()
751
752	_, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
753	if err != nil {
754		t.Fatal(err)
755	}
756
757	_, err = txn.Query("INSERT INTO foo VALUES (0), (0)")
758	if err == nil {
759		t.Fatal("Should have raised error")
760	}
761
762	e, ok := err.(*Error)
763	if !ok {
764		t.Fatalf("expected Error, got %#v", err)
765	} else if e.Code.Name() != "unique_violation" {
766		t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
767	}
768}
769
770func TestErrorOnQueryRowSimpleQuery(t *testing.T) {
771	db := openTestConn(t)
772	defer db.Close()
773
774	txn, err := db.Begin()
775	if err != nil {
776		t.Fatal(err)
777	}
778	defer txn.Rollback()
779
780	_, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
781	if err != nil {
782		t.Fatal(err)
783	}
784
785	var v int
786	err = txn.QueryRow("INSERT INTO foo VALUES (0), (0)").Scan(&v)
787	if err == nil {
788		t.Fatal("Should have raised error")
789	}
790
791	e, ok := err.(*Error)
792	if !ok {
793		t.Fatalf("expected Error, got %#v", err)
794	} else if e.Code.Name() != "unique_violation" {
795		t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
796	}
797}
798
799// Test the QueryRow bug workarounds in stmt.exec() and simpleQuery()
800func TestQueryRowBugWorkaround(t *testing.T) {
801	db := openTestConn(t)
802	defer db.Close()
803
804	// stmt.exec()
805	_, err := db.Exec("CREATE TEMP TABLE notnulltemp (a varchar(10) not null)")
806	if err != nil {
807		t.Fatal(err)
808	}
809
810	var a string
811	err = db.QueryRow("INSERT INTO notnulltemp(a) values($1) RETURNING a", nil).Scan(&a)
812	if err == sql.ErrNoRows {
813		t.Fatalf("expected constraint violation error; got: %v", err)
814	}
815	pge, ok := err.(*Error)
816	if !ok {
817		t.Fatalf("expected *Error; got: %#v", err)
818	}
819	if pge.Code.Name() != "not_null_violation" {
820		t.Fatalf("expected not_null_violation; got: %s (%+v)", pge.Code.Name(), err)
821	}
822
823	// Test workaround in simpleQuery()
824	tx, err := db.Begin()
825	if err != nil {
826		t.Fatalf("unexpected error %s in Begin", err)
827	}
828	defer tx.Rollback()
829
830	_, err = tx.Exec("SET LOCAL check_function_bodies TO FALSE")
831	if err != nil {
832		t.Fatalf("could not disable check_function_bodies: %s", err)
833	}
834	_, err = tx.Exec(`
835CREATE OR REPLACE FUNCTION bad_function()
836RETURNS integer
837-- hack to prevent the function from being inlined
838SET check_function_bodies TO TRUE
839AS $$
840	SELECT text 'bad'
841$$ LANGUAGE sql`)
842	if err != nil {
843		t.Fatalf("could not create function: %s", err)
844	}
845
846	err = tx.QueryRow("SELECT * FROM bad_function()").Scan(&a)
847	if err == nil {
848		t.Fatalf("expected error")
849	}
850	pge, ok = err.(*Error)
851	if !ok {
852		t.Fatalf("expected *Error; got: %#v", err)
853	}
854	if pge.Code.Name() != "invalid_function_definition" {
855		t.Fatalf("expected invalid_function_definition; got: %s (%+v)", pge.Code.Name(), err)
856	}
857
858	err = tx.Rollback()
859	if err != nil {
860		t.Fatalf("unexpected error %s in Rollback", err)
861	}
862
863	// Also test that simpleQuery()'s workaround works when the query fails
864	// after a row has been received.
865	rows, err := db.Query(`
866select
867	(select generate_series(1, ss.i))
868from (select gs.i
869      from generate_series(1, 2) gs(i)
870      order by gs.i limit 2) ss`)
871	if err != nil {
872		t.Fatalf("query failed: %s", err)
873	}
874	if !rows.Next() {
875		t.Fatalf("expected at least one result row; got %s", rows.Err())
876	}
877	var i int
878	err = rows.Scan(&i)
879	if err != nil {
880		t.Fatalf("rows.Scan() failed: %s", err)
881	}
882	if i != 1 {
883		t.Fatalf("unexpected value for i: %d", i)
884	}
885	if rows.Next() {
886		t.Fatalf("unexpected row")
887	}
888	pge, ok = rows.Err().(*Error)
889	if !ok {
890		t.Fatalf("expected *Error; got: %#v", err)
891	}
892	if pge.Code.Name() != "cardinality_violation" {
893		t.Fatalf("expected cardinality_violation; got: %s (%+v)", pge.Code.Name(), rows.Err())
894	}
895}
896
897func TestSimpleQuery(t *testing.T) {
898	db := openTestConn(t)
899	defer db.Close()
900
901	r, err := db.Query("select 1")
902	if err != nil {
903		t.Fatal(err)
904	}
905	defer r.Close()
906
907	if !r.Next() {
908		t.Fatal("expected row")
909	}
910}
911
912func TestBindError(t *testing.T) {
913	db := openTestConn(t)
914	defer db.Close()
915
916	_, err := db.Exec("create temp table test (i integer)")
917	if err != nil {
918		t.Fatal(err)
919	}
920
921	_, err = db.Query("select * from test where i=$1", "hhh")
922	if err == nil {
923		t.Fatal("expected an error")
924	}
925
926	// Should not get error here
927	r, err := db.Query("select * from test where i=$1", 1)
928	if err != nil {
929		t.Fatal(err)
930	}
931	defer r.Close()
932}
933
934func TestParseErrorInExtendedQuery(t *testing.T) {
935	db := openTestConn(t)
936	defer db.Close()
937
938	rows, err := db.Query("PARSE_ERROR $1", 1)
939	if err == nil {
940		t.Fatal("expected error")
941	}
942
943	rows, err = db.Query("SELECT 1")
944	if err != nil {
945		t.Fatal(err)
946	}
947	rows.Close()
948}
949
950// TestReturning tests that an INSERT query using the RETURNING clause returns a row.
951func TestReturning(t *testing.T) {
952	db := openTestConn(t)
953	defer db.Close()
954
955	_, err := db.Exec("CREATE TEMP TABLE distributors (did integer default 0, dname text)")
956	if err != nil {
957		t.Fatal(err)
958	}
959
960	rows, err := db.Query("INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets') " +
961		"RETURNING did;")
962	if err != nil {
963		t.Fatal(err)
964	}
965	if !rows.Next() {
966		t.Fatal("no rows")
967	}
968	var did int
969	err = rows.Scan(&did)
970	if err != nil {
971		t.Fatal(err)
972	}
973	if did != 0 {
974		t.Fatalf("bad value for did: got %d, want %d", did, 0)
975	}
976
977	if rows.Next() {
978		t.Fatal("unexpected next row")
979	}
980	err = rows.Err()
981	if err != nil {
982		t.Fatal(err)
983	}
984}
985
986func TestIssue186(t *testing.T) {
987	db := openTestConn(t)
988	defer db.Close()
989
990	// Exec() a query which returns results
991	_, err := db.Exec("VALUES (1), (2), (3)")
992	if err != nil {
993		t.Fatal(err)
994	}
995
996	_, err = db.Exec("VALUES ($1), ($2), ($3)", 1, 2, 3)
997	if err != nil {
998		t.Fatal(err)
999	}
1000
1001	// Query() a query which doesn't return any results
1002	txn, err := db.Begin()
1003	if err != nil {
1004		t.Fatal(err)
1005	}
1006	defer txn.Rollback()
1007
1008	rows, err := txn.Query("CREATE TEMP TABLE foo(f1 int)")
1009	if err != nil {
1010		t.Fatal(err)
1011	}
1012	if err = rows.Close(); err != nil {
1013		t.Fatal(err)
1014	}
1015
1016	// small trick to get NoData from a parameterized query
1017	_, err = txn.Exec("CREATE RULE nodata AS ON INSERT TO foo DO INSTEAD NOTHING")
1018	if err != nil {
1019		t.Fatal(err)
1020	}
1021	rows, err = txn.Query("INSERT INTO foo VALUES ($1)", 1)
1022	if err != nil {
1023		t.Fatal(err)
1024	}
1025	if err = rows.Close(); err != nil {
1026		t.Fatal(err)
1027	}
1028}
1029
1030func TestIssue196(t *testing.T) {
1031	db := openTestConn(t)
1032	defer db.Close()
1033
1034	row := db.QueryRow("SELECT float4 '0.10000122' = $1, float8 '35.03554004971999' = $2",
1035		float32(0.10000122), float64(35.03554004971999))
1036
1037	var float4match, float8match bool
1038	err := row.Scan(&float4match, &float8match)
1039	if err != nil {
1040		t.Fatal(err)
1041	}
1042	if !float4match {
1043		t.Errorf("Expected float4 fidelity to be maintained; got no match")
1044	}
1045	if !float8match {
1046		t.Errorf("Expected float8 fidelity to be maintained; got no match")
1047	}
1048}
1049
1050// Test that any CommandComplete messages sent before the query results are
1051// ignored.
1052func TestIssue282(t *testing.T) {
1053	db := openTestConn(t)
1054	defer db.Close()
1055
1056	var search_path string
1057	err := db.QueryRow(`
1058		SET LOCAL search_path TO pg_catalog;
1059		SET LOCAL search_path TO pg_catalog;
1060		SHOW search_path`).Scan(&search_path)
1061	if err != nil {
1062		t.Fatal(err)
1063	}
1064	if search_path != "pg_catalog" {
1065		t.Fatalf("unexpected search_path %s", search_path)
1066	}
1067}
1068
1069func TestReadFloatPrecision(t *testing.T) {
1070	db := openTestConn(t)
1071	defer db.Close()
1072
1073	row := db.QueryRow("SELECT float4 '0.10000122', float8 '35.03554004971999'")
1074	var float4val float32
1075	var float8val float64
1076	err := row.Scan(&float4val, &float8val)
1077	if err != nil {
1078		t.Fatal(err)
1079	}
1080	if float4val != float32(0.10000122) {
1081		t.Errorf("Expected float4 fidelity to be maintained; got no match")
1082	}
1083	if float8val != float64(35.03554004971999) {
1084		t.Errorf("Expected float8 fidelity to be maintained; got no match")
1085	}
1086}
1087
1088func TestXactMultiStmt(t *testing.T) {
1089	// minified test case based on bug reports from
1090	// pico303@gmail.com and rangelspam@gmail.com
1091	t.Skip("Skipping failing test")
1092	db := openTestConn(t)
1093	defer db.Close()
1094
1095	tx, err := db.Begin()
1096	if err != nil {
1097		t.Fatal(err)
1098	}
1099	defer tx.Commit()
1100
1101	rows, err := tx.Query("select 1")
1102	if err != nil {
1103		t.Fatal(err)
1104	}
1105
1106	if rows.Next() {
1107		var val int32
1108		if err = rows.Scan(&val); err != nil {
1109			t.Fatal(err)
1110		}
1111	} else {
1112		t.Fatal("Expected at least one row in first query in xact")
1113	}
1114
1115	rows2, err := tx.Query("select 2")
1116	if err != nil {
1117		t.Fatal(err)
1118	}
1119
1120	if rows2.Next() {
1121		var val2 int32
1122		if err := rows2.Scan(&val2); err != nil {
1123			t.Fatal(err)
1124		}
1125	} else {
1126		t.Fatal("Expected at least one row in second query in xact")
1127	}
1128
1129	if err = rows.Err(); err != nil {
1130		t.Fatal(err)
1131	}
1132
1133	if err = rows2.Err(); err != nil {
1134		t.Fatal(err)
1135	}
1136
1137	if err = tx.Commit(); err != nil {
1138		t.Fatal(err)
1139	}
1140}
1141
1142var envParseTests = []struct {
1143	Expected map[string]string
1144	Env      []string
1145}{
1146	{
1147		Env:      []string{"PGDATABASE=hello", "PGUSER=goodbye"},
1148		Expected: map[string]string{"dbname": "hello", "user": "goodbye"},
1149	},
1150	{
1151		Env:      []string{"PGDATESTYLE=ISO, MDY"},
1152		Expected: map[string]string{"datestyle": "ISO, MDY"},
1153	},
1154	{
1155		Env:      []string{"PGCONNECT_TIMEOUT=30"},
1156		Expected: map[string]string{"connect_timeout": "30"},
1157	},
1158}
1159
1160func TestParseEnviron(t *testing.T) {
1161	for i, tt := range envParseTests {
1162		results := parseEnviron(tt.Env)
1163		if !reflect.DeepEqual(tt.Expected, results) {
1164			t.Errorf("%d: Expected: %#v Got: %#v", i, tt.Expected, results)
1165		}
1166	}
1167}
1168
1169func TestParseComplete(t *testing.T) {
1170	tpc := func(commandTag string, command string, affectedRows int64, shouldFail bool) {
1171		defer func() {
1172			if p := recover(); p != nil {
1173				if !shouldFail {
1174					t.Error(p)
1175				}
1176			}
1177		}()
1178		cn := &conn{}
1179		res, c := cn.parseComplete(commandTag)
1180		if c != command {
1181			t.Errorf("Expected %v, got %v", command, c)
1182		}
1183		n, err := res.RowsAffected()
1184		if err != nil {
1185			t.Fatal(err)
1186		}
1187		if n != affectedRows {
1188			t.Errorf("Expected %d, got %d", affectedRows, n)
1189		}
1190	}
1191
1192	tpc("ALTER TABLE", "ALTER TABLE", 0, false)
1193	tpc("INSERT 0 1", "INSERT", 1, false)
1194	tpc("UPDATE 100", "UPDATE", 100, false)
1195	tpc("SELECT 100", "SELECT", 100, false)
1196	tpc("FETCH 100", "FETCH", 100, false)
1197	// allow COPY (and others) without row count
1198	tpc("COPY", "COPY", 0, false)
1199	// don't fail on command tags we don't recognize
1200	tpc("UNKNOWNCOMMANDTAG", "UNKNOWNCOMMANDTAG", 0, false)
1201
1202	// failure cases
1203	tpc("INSERT 1", "", 0, true)   // missing oid
1204	tpc("UPDATE 0 1", "", 0, true) // too many numbers
1205	tpc("SELECT foo", "", 0, true) // invalid row count
1206}
1207
1208func TestExecerInterface(t *testing.T) {
1209	// Gin up a straw man private struct just for the type check
1210	cn := &conn{c: nil}
1211	var cni interface{} = cn
1212
1213	_, ok := cni.(driver.Execer)
1214	if !ok {
1215		t.Fatal("Driver doesn't implement Execer")
1216	}
1217}
1218
1219func TestNullAfterNonNull(t *testing.T) {
1220	db := openTestConn(t)
1221	defer db.Close()
1222
1223	r, err := db.Query("SELECT 9::integer UNION SELECT NULL::integer")
1224	if err != nil {
1225		t.Fatal(err)
1226	}
1227
1228	var n sql.NullInt64
1229
1230	if !r.Next() {
1231		if r.Err() != nil {
1232			t.Fatal(err)
1233		}
1234		t.Fatal("expected row")
1235	}
1236
1237	if err := r.Scan(&n); err != nil {
1238		t.Fatal(err)
1239	}
1240
1241	if n.Int64 != 9 {
1242		t.Fatalf("expected 2, not %d", n.Int64)
1243	}
1244
1245	if !r.Next() {
1246		if r.Err() != nil {
1247			t.Fatal(err)
1248		}
1249		t.Fatal("expected row")
1250	}
1251
1252	if err := r.Scan(&n); err != nil {
1253		t.Fatal(err)
1254	}
1255
1256	if n.Valid {
1257		t.Fatal("expected n to be invalid")
1258	}
1259
1260	if n.Int64 != 0 {
1261		t.Fatalf("expected n to 2, not %d", n.Int64)
1262	}
1263}
1264
1265func Test64BitErrorChecking(t *testing.T) {
1266	defer func() {
1267		if err := recover(); err != nil {
1268			t.Fatal("panic due to 0xFFFFFFFF != -1 " +
1269				"when int is 64 bits")
1270		}
1271	}()
1272
1273	db := openTestConn(t)
1274	defer db.Close()
1275
1276	r, err := db.Query(`SELECT *
1277FROM (VALUES (0::integer, NULL::text), (1, 'test string')) AS t;`)
1278
1279	if err != nil {
1280		t.Fatal(err)
1281	}
1282
1283	defer r.Close()
1284
1285	for r.Next() {
1286	}
1287}
1288
1289func TestCommit(t *testing.T) {
1290	db := openTestConn(t)
1291	defer db.Close()
1292
1293	_, err := db.Exec("CREATE TEMP TABLE temp (a int)")
1294	if err != nil {
1295		t.Fatal(err)
1296	}
1297	sqlInsert := "INSERT INTO temp VALUES (1)"
1298	sqlSelect := "SELECT * FROM temp"
1299	tx, err := db.Begin()
1300	if err != nil {
1301		t.Fatal(err)
1302	}
1303	_, err = tx.Exec(sqlInsert)
1304	if err != nil {
1305		t.Fatal(err)
1306	}
1307	err = tx.Commit()
1308	if err != nil {
1309		t.Fatal(err)
1310	}
1311	var i int
1312	err = db.QueryRow(sqlSelect).Scan(&i)
1313	if err != nil {
1314		t.Fatal(err)
1315	}
1316	if i != 1 {
1317		t.Fatalf("expected 1, got %d", i)
1318	}
1319}
1320
1321func TestErrorClass(t *testing.T) {
1322	db := openTestConn(t)
1323	defer db.Close()
1324
1325	_, err := db.Query("SELECT int 'notint'")
1326	if err == nil {
1327		t.Fatal("expected error")
1328	}
1329	pge, ok := err.(*Error)
1330	if !ok {
1331		t.Fatalf("expected *pq.Error, got %#+v", err)
1332	}
1333	if pge.Code.Class() != "22" {
1334		t.Fatalf("expected class 28, got %v", pge.Code.Class())
1335	}
1336	if pge.Code.Class().Name() != "data_exception" {
1337		t.Fatalf("expected data_exception, got %v", pge.Code.Class().Name())
1338	}
1339}
1340
1341func TestParseOpts(t *testing.T) {
1342	tests := []struct {
1343		in       string
1344		expected values
1345		valid    bool
1346	}{
1347		{"dbname=hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
1348		{"dbname=hello user=goodbye  ", values{"dbname": "hello", "user": "goodbye"}, true},
1349		{"dbname = hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
1350		{"dbname=hello user =goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
1351		{"dbname=hello user= goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
1352		{"host=localhost password='correct horse battery staple'", values{"host": "localhost", "password": "correct horse battery staple"}, true},
1353		{"dbname=データベース password=パスワード", values{"dbname": "データベース", "password": "パスワード"}, true},
1354		{"dbname=hello user=''", values{"dbname": "hello", "user": ""}, true},
1355		{"user='' dbname=hello", values{"dbname": "hello", "user": ""}, true},
1356		// The last option value is an empty string if there's no non-whitespace after its =
1357		{"dbname=hello user=   ", values{"dbname": "hello", "user": ""}, true},
1358
1359		// The parser ignores spaces after = and interprets the next set of non-whitespace characters as the value.
1360		{"user= password=foo", values{"user": "password=foo"}, true},
1361
1362		// Backslash escapes next char
1363		{`user=a\ \'\\b`, values{"user": `a '\b`}, true},
1364		{`user='a \'b'`, values{"user": `a 'b`}, true},
1365
1366		// Incomplete escape
1367		{`user=x\`, values{}, false},
1368
1369		// No '=' after the key
1370		{"postgre://marko@internet", values{}, false},
1371		{"dbname user=goodbye", values{}, false},
1372		{"user=foo blah", values{}, false},
1373		{"user=foo blah   ", values{}, false},
1374
1375		// Unterminated quoted value
1376		{"dbname=hello user='unterminated", values{}, false},
1377	}
1378
1379	for _, test := range tests {
1380		o := make(values)
1381		err := parseOpts(test.in, o)
1382
1383		switch {
1384		case err != nil && test.valid:
1385			t.Errorf("%q got unexpected error: %s", test.in, err)
1386		case err == nil && test.valid && !reflect.DeepEqual(test.expected, o):
1387			t.Errorf("%q got: %#v want: %#v", test.in, o, test.expected)
1388		case err == nil && !test.valid:
1389			t.Errorf("%q expected an error", test.in)
1390		}
1391	}
1392}
1393
1394func TestRuntimeParameters(t *testing.T) {
1395	type RuntimeTestResult int
1396	const (
1397		ResultUnknown RuntimeTestResult = iota
1398		ResultSuccess
1399		ResultError // other error
1400	)
1401
1402	tests := []struct {
1403		conninfo        string
1404		param           string
1405		expected        string
1406		expectedOutcome RuntimeTestResult
1407	}{
1408		// invalid parameter
1409		{"DOESNOTEXIST=foo", "", "", ResultError},
1410		// we can only work with a specific value for these two
1411		{"client_encoding=SQL_ASCII", "", "", ResultError},
1412		{"datestyle='ISO, YDM'", "", "", ResultError},
1413		// "options" should work exactly as it does in libpq
1414		{"options='-c search_path=pqgotest'", "search_path", "pqgotest", ResultSuccess},
1415		// pq should override client_encoding in this case
1416		{"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", ResultSuccess},
1417		// allow client_encoding to be set explicitly
1418		{"client_encoding=UTF8", "client_encoding", "UTF8", ResultSuccess},
1419		// test a runtime parameter not supported by libpq
1420		{"work_mem='139kB'", "work_mem", "139kB", ResultSuccess},
1421		// test fallback_application_name
1422		{"application_name=foo fallback_application_name=bar", "application_name", "foo", ResultSuccess},
1423		{"application_name='' fallback_application_name=bar", "application_name", "", ResultSuccess},
1424		{"fallback_application_name=bar", "application_name", "bar", ResultSuccess},
1425	}
1426
1427	for _, test := range tests {
1428		db, err := openTestConnConninfo(test.conninfo)
1429		if err != nil {
1430			t.Fatal(err)
1431		}
1432
1433		// application_name didn't exist before 9.0
1434		if test.param == "application_name" && getServerVersion(t, db) < 90000 {
1435			db.Close()
1436			continue
1437		}
1438
1439		tryGetParameterValue := func() (value string, outcome RuntimeTestResult) {
1440			defer db.Close()
1441			row := db.QueryRow("SELECT current_setting($1)", test.param)
1442			err = row.Scan(&value)
1443			if err != nil {
1444				return "", ResultError
1445			}
1446			return value, ResultSuccess
1447		}
1448
1449		value, outcome := tryGetParameterValue()
1450		if outcome != test.expectedOutcome && outcome == ResultError {
1451			t.Fatalf("%v: unexpected error: %v", test.conninfo, err)
1452		}
1453		if outcome != test.expectedOutcome {
1454			t.Fatalf("unexpected outcome %v (was expecting %v) for conninfo \"%s\"",
1455				outcome, test.expectedOutcome, test.conninfo)
1456		}
1457		if value != test.expected {
1458			t.Fatalf("bad value for %s: got %s, want %s with conninfo \"%s\"",
1459				test.param, value, test.expected, test.conninfo)
1460		}
1461	}
1462}
1463
1464func TestIsUTF8(t *testing.T) {
1465	var cases = []struct {
1466		name string
1467		want bool
1468	}{
1469		{"unicode", true},
1470		{"utf-8", true},
1471		{"utf_8", true},
1472		{"UTF-8", true},
1473		{"UTF8", true},
1474		{"utf8", true},
1475		{"u n ic_ode", true},
1476		{"ut_f%8", true},
1477		{"ubf8", false},
1478		{"punycode", false},
1479	}
1480
1481	for _, test := range cases {
1482		if g := isUTF8(test.name); g != test.want {
1483			t.Errorf("isUTF8(%q) = %v want %v", test.name, g, test.want)
1484		}
1485	}
1486}
1487
1488func TestQuoteIdentifier(t *testing.T) {
1489	var cases = []struct {
1490		input string
1491		want  string
1492	}{
1493		{`foo`, `"foo"`},
1494		{`foo bar baz`, `"foo bar baz"`},
1495		{`foo"bar`, `"foo""bar"`},
1496		{"foo\x00bar", `"foo"`},
1497		{"\x00foo", `""`},
1498	}
1499
1500	for _, test := range cases {
1501		got := QuoteIdentifier(test.input)
1502		if got != test.want {
1503			t.Errorf("QuoteIdentifier(%q) = %v want %v", test.input, got, test.want)
1504		}
1505	}
1506}
1507
1508func TestRowsResultTag(t *testing.T) {
1509	type ResultTag interface {
1510		Result() driver.Result
1511		Tag() string
1512	}
1513
1514	tests := []struct {
1515		query string
1516		tag   string
1517		ra    int64
1518	}{
1519		{
1520			query: "CREATE TEMP TABLE temp (a int)",
1521			tag:   "CREATE TABLE",
1522		},
1523		{
1524			query: "INSERT INTO temp VALUES (1), (2)",
1525			tag:   "INSERT",
1526			ra:    2,
1527		},
1528		{
1529			query: "SELECT 1",
1530		},
1531		// A SELECT anywhere should take precedent.
1532		{
1533			query: "SELECT 1; INSERT INTO temp VALUES (1), (2)",
1534		},
1535		{
1536			query: "INSERT INTO temp VALUES (1), (2); SELECT 1",
1537		},
1538		// Multiple statements that don't return rows should return the last tag.
1539		{
1540			query: "CREATE TEMP TABLE t (a int); DROP TABLE t",
1541			tag:   "DROP TABLE",
1542		},
1543		// Ensure a rows-returning query in any position among various tags-returing
1544		// statements will prefer the rows.
1545		{
1546			query: "SELECT 1; CREATE TEMP TABLE t (a int); DROP TABLE t",
1547		},
1548		{
1549			query: "CREATE TEMP TABLE t (a int); SELECT 1; DROP TABLE t",
1550		},
1551		{
1552			query: "CREATE TEMP TABLE t (a int); DROP TABLE t; SELECT 1",
1553		},
1554		// Verify that an no-results query doesn't set the tag.
1555		{
1556			query: "CREATE TEMP TABLE t (a int); SELECT 1 WHERE FALSE; DROP TABLE t;",
1557		},
1558	}
1559
1560	// If this is the only test run, this will correct the connection string.
1561	openTestConn(t).Close()
1562
1563	conn, err := Open("")
1564	if err != nil {
1565		t.Fatal(err)
1566	}
1567	defer conn.Close()
1568	q := conn.(driver.Queryer)
1569
1570	for _, test := range tests {
1571		if rows, err := q.Query(test.query, nil); err != nil {
1572			t.Fatalf("%s: %s", test.query, err)
1573		} else {
1574			r := rows.(ResultTag)
1575			if tag := r.Tag(); tag != test.tag {
1576				t.Fatalf("%s: unexpected tag %q", test.query, tag)
1577			}
1578			res := r.Result()
1579			if ra, _ := res.RowsAffected(); ra != test.ra {
1580				t.Fatalf("%s: unexpected rows affected: %d", test.query, ra)
1581			}
1582			rows.Close()
1583		}
1584	}
1585}
1586