示例#1
0
func (t *DBTest) TestLargeWriteRead(c *C) {
	src := bytes.Repeat([]byte{0x1}, 1e6)
	var dst []byte
	_, err := t.db.QueryOne(pg.Scan(&dst), "SELECT ?", src)
	c.Assert(err, IsNil)
	c.Assert(dst, DeepEquals, src)
}
示例#2
0
func (t *DBTest) TestTime(c *C) {
	for _, test := range timeTests {
		var tm time.Time
		_, err := t.db.QueryOne(pg.Scan(&tm), "SELECT ?", test.str)
		c.Assert(err, IsNil)
		c.Assert(tm.Unix(), Equals, test.wanted.Unix(), Commentf("str=%q", test.str))
	}
}
示例#3
0
func ExampleDB_WithTimeout() {
	var count int
	// Use bigger timeout since this query is known to be slow.
	_, err := db.WithTimeout(time.Minute).QueryOne(pg.Scan(&count), `
		SELECT count(*) FROM big_table
	`)
	if err != nil {
		panic(err)
	}
}
示例#4
0
func ExampleDB_Prepare() {
	stmt, err := db.Prepare(`SELECT $1::text, $2::text`)
	if err != nil {
		panic(err)
	}

	var s1, s2 string
	_, err = stmt.QueryOne(pg.Scan(&s1, &s2), "foo", "bar")
	fmt.Println(s1, s2, err)
	// Output: foo bar <nil>
}
示例#5
0
func (t *LoaderTest) TestLoaderError(c *C) {
	tx, err := t.db.Begin()
	c.Assert(err, IsNil)
	defer tx.Rollback()

	loader := errLoader("my error")
	_, err = tx.QueryOne(loader, "SELECT 1, 2")
	c.Assert(err.Error(), Equals, "my error")

	// Verify that client is still functional.
	var n1, n2 int
	_, err = tx.QueryOne(pg.Scan(&n1, &n2), "SELECT 1, 2")
	c.Assert(err, IsNil)
	c.Assert(n1, Equals, 1)
	c.Assert(n2, Equals, 2)
}
示例#6
0
func BenchmarkQueryRowScan(b *testing.B) {
	db := pg.Connect(pgOptions())
	defer db.Close()

	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			var n int64
			_, err := db.QueryOne(pg.Scan(&n), `SELECT ? AS num`, 1)
			if err != nil {
				b.Fatal(err)
			}
			if n != 1 {
				b.Fatalf("got %d, wanted 1", n)
			}
		}
	})
}
示例#7
0
func BenchmarkQueryRowStmtScan(b *testing.B) {
	db := pg.Connect(pgOptions())
	defer db.Close()

	stmt, err := db.Prepare(`SELECT $1::bigint AS num`)
	if err != nil {
		b.Fatal(err)
	}
	defer stmt.Close()

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		var n int64
		_, err := stmt.QueryOne(pg.Scan(&n), 1)
		if err != nil {
			b.Fatal(err)
		}
		if n != 1 {
			b.Fatalf("got %d, wanted 1", n)
		}
	}
}
示例#8
0
func (t *DBTest) TestScan(c *C) {
	var dst int
	_, err := t.db.QueryOne(pg.Scan(&dst), "SELECT 1")
	c.Assert(err, IsNil)
	c.Assert(dst, Equals, 1)
}
示例#9
0
func TestConversion(t *testing.T) {
	conversionTests := []conversionTest{
		{src: true, dst: nil, wanterr: "pg: Decode(nil)"},
		{src: true, dst: new(uintptr), wanterr: "pg: Decode(unsupported uintptr)"},
		{src: true, dst: true, wanterr: "pg: Decode(nonsettable bool)"},
		{src: true, dst: (*bool)(nil), wanterr: "pg: Decode(nonsettable *bool)"},

		{src: nil, dst: new(*bool), pgtype: "bool", wantnil: true},
		{src: nil, dst: new(bool), pgtype: "bool", wantzero: true},
		{src: true, dst: new(bool), pgtype: "bool"},
		{src: true, dst: new(*bool), pgtype: "bool"},

		{src: nil, dst: new(string), pgtype: "text", wantzero: true},
		{src: nil, dst: new(*string), pgtype: "text", wantnil: true},
		{src: "hello world", dst: new(string), pgtype: "text"},
		{src: "hello world", dst: new(*string), pgtype: "text"},
		{src: "'\"\000", dst: new(string), wanted: `'"`, pgtype: "text"},

		{src: []byte("hello world\000"), dst: new([]byte), pgtype: "bytea"},
		{src: []byte{}, dst: new([]byte), pgtype: "bytea", wantzero: true},
		{src: nil, dst: new([]byte), pgtype: "bytea", wantnil: true},

		{src: int(math.MaxInt32), dst: new(int), pgtype: "int"},
		{src: int(math.MinInt32), dst: new(int), pgtype: "int"},
		{src: nil, dst: new(int), pgtype: "int", wantzero: true},
		{src: int(math.MaxInt32), dst: new(*int), pgtype: "int"},
		{src: nil, dst: new(*int), pgtype: "int", wantnil: true},
		{src: int8(math.MaxInt8), dst: new(int8), pgtype: "smallint"},
		{src: int8(math.MinInt8), dst: new(int8), pgtype: "smallint"},
		{src: int16(math.MaxInt16), dst: new(int16), pgtype: "smallint"},
		{src: int16(math.MinInt16), dst: new(int16), pgtype: "smallint"},
		{src: int32(math.MaxInt32), dst: new(int32), pgtype: "int"},
		{src: int32(math.MinInt32), dst: new(int32), pgtype: "int"},
		{src: int64(math.MaxInt64), dst: new(int64), pgtype: "bigint"},
		{src: int64(math.MinInt64), dst: new(int64), pgtype: "bigint"},
		{src: uint(math.MaxUint32), dst: new(uint), pgtype: "bigint"},
		{src: uint8(math.MaxUint8), dst: new(uint8), pgtype: "smallint"},
		{src: uint16(math.MaxUint16), dst: new(uint16), pgtype: "int"},
		{src: uint32(math.MaxUint32), dst: new(uint32), pgtype: "bigint"},
		{src: uint64(math.MaxUint64), dst: new(uint64)},

		{src: float32(math.MaxFloat32), dst: new(float32), pgtype: "decimal"},
		{src: float32(math.SmallestNonzeroFloat32), dst: new(float32), pgtype: "decimal"},
		{src: float64(math.MaxFloat64), dst: new(float64), pgtype: "decimal"},
		{src: float64(math.SmallestNonzeroFloat64), dst: new(float64), pgtype: "decimal"},

		{src: nil, dst: new([]int), pgtype: "jsonb", wantnil: true},
		{src: []int(nil), dst: new([]int), pgtype: "jsonb", wantnil: true},
		{src: []int{}, dst: new([]int), pgtype: "jsonb", wantzero: true},
		{src: []int{1, 2, 3}, dst: new([]int), pgtype: "jsonb"},
		{src: IntSlice{1, 2, 3}, dst: new(IntSlice), pgtype: "jsonb"},

		{
			src:      nil,
			dst:      &types.Array{[]int(nil)},
			pgtype:   "int[]",
			wantzero: true,
		},
		{
			src:      types.Array{[]int(nil)},
			dst:      &types.Array{[]int(nil)},
			pgtype:   "int[]",
			wantzero: true,
		},
		{
			src:    types.Array{[]int{}},
			dst:    &types.Array{[]int(nil)},
			pgtype: "int[]",
		},
		{
			src:    types.Array{[]int{1, 2, 3}},
			dst:    &types.Array{[]int(nil)},
			pgtype: "int[]",
		},

		{src: nil, dst: new([]int64), pgtype: "jsonb", wantnil: true},
		{src: []int64(nil), dst: new([]int64), pgtype: "jsonb", wantnil: true},
		{src: []int64{}, dst: new([]int64), pgtype: "jsonb", wantzero: true},
		{src: []int64{1, 2, 3}, dst: new([]int64), pgtype: "jsonb"},
		{src: Int64Slice{1, 2, 3}, dst: new(Int64Slice), pgtype: "jsonb"},

		{
			src:      nil,
			dst:      &types.Array{[]int64(nil)},
			pgtype:   "bigint[]",
			wantzero: true,
		},
		{
			src:      types.Array{[]int64(nil)},
			dst:      &types.Array{[]int64(nil)},
			pgtype:   "bigint[]",
			wantzero: true,
		},
		{
			src:    types.Array{[]int64{}},
			dst:    &types.Array{[]int64(nil)},
			pgtype: "bigint[]",
		},
		{
			src:    types.Array{[]int64{1, 2, 3}},
			dst:    &types.Array{[]int64(nil)},
			pgtype: "bigint[]",
		},

		{src: nil, dst: new([]float64), pgtype: "jsonb", wantnil: true},
		{src: []float64(nil), dst: new([]float64), pgtype: "jsonb", wantnil: true},
		{src: []float64{1.1, 2.22, 3.333}, dst: new([]float64), pgtype: "jsonb"},
		{src: Float64Slice{1.1, 2.22, 3.333}, dst: new(Float64Slice), pgtype: "jsonb"},

		{
			src:      nil,
			dst:      &types.Array{[]float64(nil)},
			pgtype:   "decimal[]",
			wantzero: true,
		},
		{
			src:      types.Array{[]float64(nil)},
			dst:      &types.Array{[]float64(nil)},
			pgtype:   "decimal[]",
			wantzero: true,
		},
		{
			src:    types.Array{[]float64{}},
			dst:    &types.Array{[]float64(nil)},
			pgtype: "decimal[]",
		},
		{
			src:    types.Array{[]float64{1.1, 2.22, 3.333}},
			dst:    &types.Array{[]float64(nil)},
			pgtype: "decimal[]",
		},

		{src: nil, dst: new([]string), pgtype: "jsonb", wantnil: true},
		{src: []string(nil), dst: new([]string), pgtype: "jsonb", wantnil: true},
		{src: []string{}, dst: new([]string), pgtype: "jsonb", wantzero: true},
		{src: []string{"foo\n", "bar {}", "'\\\""}, dst: new([]string), pgtype: "jsonb"},
		{src: StringSlice{"foo", "bar"}, dst: new(StringSlice), pgtype: "jsonb"},

		{
			src:      nil,
			dst:      &types.Array{[]string(nil)},
			pgtype:   "text[]",
			wantzero: true,
		},
		{
			src:      types.Array{[]string(nil)},
			dst:      &types.Array{[]string(nil)},
			pgtype:   "text[]",
			wantzero: true,
		},
		{
			src:    types.Array{[]string{}},
			dst:    &types.Array{[]string(nil)},
			pgtype: "text[]",
		},
		{
			src:    types.Array{[]string{"one", "two", "three"}},
			dst:    &types.Array{[]string(nil)},
			pgtype: "text[]",
		},

		{
			src:     nil,
			dst:     new(map[string]string),
			pgtype:  "jsonb",
			wantnil: true,
		},
		{
			src:     map[string]string(nil),
			dst:     new(map[string]string),
			pgtype:  "jsonb",
			wantnil: true,
		},
		{
			src:    map[string]string{"foo\n =>": "bar\n =>", "'\\\"": "'\\\""},
			dst:    new(map[string]string),
			pgtype: "jsonb",
		},

		{src: &sql.NullBool{}, dst: &sql.NullBool{}, pgtype: "bool"},
		{src: &sql.NullBool{Valid: true}, dst: &sql.NullBool{}, pgtype: "bool"},
		{src: &sql.NullBool{Valid: true, Bool: true}, dst: &sql.NullBool{}, pgtype: "bool"},

		{src: &sql.NullString{}, dst: &sql.NullString{}, pgtype: "text"},
		{src: &sql.NullString{Valid: true}, dst: &sql.NullString{}, pgtype: "text"},
		{src: &sql.NullString{Valid: true, String: "foo"}, dst: &sql.NullString{}, pgtype: "text"},

		{src: &sql.NullInt64{}, dst: &sql.NullInt64{}, pgtype: "bigint"},
		{src: &sql.NullInt64{Valid: true}, dst: &sql.NullInt64{}, pgtype: "bigint"},
		{src: &sql.NullInt64{Valid: true, Int64: math.MaxInt64}, dst: &sql.NullInt64{}, pgtype: "bigint"},

		{src: &sql.NullFloat64{}, dst: &sql.NullFloat64{}, pgtype: "decimal"},
		{src: &sql.NullFloat64{Valid: true}, dst: &sql.NullFloat64{}, pgtype: "decimal"},
		{src: &sql.NullFloat64{Valid: true, Float64: math.MaxFloat64}, dst: &sql.NullFloat64{}, pgtype: "decimal"},

		{src: nil, dst: &customStrSlice{}, wantnil: true},
		{src: customStrSlice{}, dst: &customStrSlice{}, wantzero: true},
		{src: customStrSlice{"one", "two"}, dst: &customStrSlice{}},

		{src: time.Time{}, dst: &time.Time{}, pgtype: "timestamp"},
		{src: time.Now(), dst: &time.Time{}, pgtype: "timestamp"},
		{src: time.Now().UTC(), dst: &time.Time{}, pgtype: "timestamp"},
		{src: nil, dst: &time.Time{}, pgtype: "timestamp", wantzero: true},
		{src: time.Now(), dst: new(*time.Time), pgtype: "timestamp"},
		{src: nil, dst: new(*time.Time), pgtype: "timestamp", wantnil: true},

		{src: time.Time{}, dst: &time.Time{}, pgtype: "timestamptz"},
		{src: time.Now(), dst: &time.Time{}, pgtype: "timestamptz"},
		{src: time.Now().UTC(), dst: &time.Time{}, pgtype: "timestamptz"},
		{src: nil, dst: &time.Time{}, pgtype: "timestamptz", wantzero: true},
		{src: time.Now(), dst: new(*time.Time), pgtype: "timestamptz"},
		{src: nil, dst: new(*time.Time), pgtype: "timestamptz", wantnil: true},

		{src: 1, dst: new(pg.Ints), wanted: pg.Ints{1}},
		{src: "hello", dst: new(pg.Strings), wanted: pg.Strings{"hello"}},
		{src: 1, dst: new(pg.IntSet), wanted: pg.IntSet{1: struct{}{}}},

		{src: nil, dst: new(*JSONMap), wantnil: true, pgtype: "json"},
		{src: nil, dst: new(JSONMap), wantnil: true, pgtype: "json"},
		{src: JSONMap{}, dst: &JSONMap{}, pgtype: "json"},
		{src: JSONMap{"foo": "bar"}, dst: &JSONMap{}, pgtype: "json"},
		{src: JSONMap{"foo": "bar"}, dst: new(*JSONMap), pgtype: "json"},
		{src: `{"foo": "bar"}`, dst: &JSONField{}, wanted: JSONField{Foo: "bar"}},

		{src: nil, dst: new(*Struct), wantnil: true, pgtype: "json"},
		{src: nil, dst: new(Struct), wantzero: true, pgtype: "json"},
		{src: Struct{}, dst: &Struct{}, pgtype: "json"},
		{src: Struct{Foo: "bar"}, dst: &Struct{}, pgtype: "json"},
		{src: Struct{Foo: "bar"}, dst: new(*Struct), pgtype: "json"},
		{src: `{"foo": "bar"}`, dst: new(Struct), wanted: Struct{Foo: "bar"}},
	}

	db := pg.Connect(pgOptions())
	db.Exec("CREATE EXTENSION hstore")
	defer db.Exec("DROP EXTENSION hstore")

	for i, test := range conversionTests {
		test.i = i

		var err error
		if _, ok := test.dst.(orm.ColumnScanner); ok {
			_, err = db.QueryOne(test.dst, "SELECT (?) AS dst", test.src)
		} else {
			dst := struct{ Dst interface{} }{Dst: test.dst}
			_, err = db.QueryOne(&dst, "SELECT (?) AS dst", test.src)
		}
		test.Assert(t, err)
	}

	for i, test := range conversionTests {
		test.i = i

		if test.pgtype == "" {
			continue
		}

		stmt, err := db.Prepare(fmt.Sprintf("SELECT ($1::%s) AS dst", test.pgtype))
		if err != nil {
			t.Fatal(err)
		}

		if _, ok := test.dst.(orm.ColumnScanner); ok {
			_, err = stmt.QueryOne(test.dst, test.src)
		} else {
			dst := struct{ Dst interface{} }{Dst: test.dst}
			_, err = stmt.QueryOne(&dst, test.src)
		}
		test.Assert(t, err)

		if err := stmt.Close(); err != nil {
			t.Fatal(err)
		}
	}

	for i, test := range conversionTests {
		test.i = i

		if _, ok := test.dst.(orm.ColumnScanner); ok {
			continue
		}

		_, err := db.QueryOne(pg.Scan(test.dst), "SELECT (?) AS dst", test.src)
		test.Assert(t, err)
	}

	for i, test := range conversionTests {
		test.i = i

		if _, ok := test.dst.(orm.ColumnScanner); ok {
			continue
		}
		if test.pgtype == "" {
			continue
		}

		stmt, err := db.Prepare(fmt.Sprintf("SELECT ($1::%s) AS dst", test.pgtype))
		if err != nil {
			t.Fatal(err)
		}

		_, err = stmt.QueryOne(pg.Scan(test.dst), test.src)
		test.Assert(t, err)

		if err := stmt.Close(); err != nil {
			t.Fatal(err)
		}
	}
}
示例#10
0
func ExampleDB_QueryOne_Scan() {
	var s1, s2 string
	_, err := db.QueryOne(pg.Scan(&s1, &s2), `SELECT ?, ?`, "foo", "bar")
	fmt.Println(s1, s2, err)
	// Output: foo bar <nil>
}