| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311 |
- package pq
- import (
- "bytes"
- "database/sql"
- "database/sql/driver"
- "math/rand"
- "reflect"
- "strings"
- "testing"
- )
- func TestParseArray(t *testing.T) {
- for _, tt := range []struct {
- input string
- delim string
- dims []int
- elems [][]byte
- }{
- {`{}`, `,`, nil, [][]byte{}},
- {`{NULL}`, `,`, []int{1}, [][]byte{nil}},
- {`{a}`, `,`, []int{1}, [][]byte{{'a'}}},
- {`{a,b}`, `,`, []int{2}, [][]byte{{'a'}, {'b'}}},
- {`{{a,b}}`, `,`, []int{1, 2}, [][]byte{{'a'}, {'b'}}},
- {`{{a},{b}}`, `,`, []int{2, 1}, [][]byte{{'a'}, {'b'}}},
- {`{{{a,b},{c,d},{e,f}}}`, `,`, []int{1, 3, 2}, [][]byte{
- {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
- }},
- {`{""}`, `,`, []int{1}, [][]byte{{}}},
- {`{","}`, `,`, []int{1}, [][]byte{{','}}},
- {`{",",","}`, `,`, []int{2}, [][]byte{{','}, {','}}},
- {`{{",",","}}`, `,`, []int{1, 2}, [][]byte{{','}, {','}}},
- {`{{","},{","}}`, `,`, []int{2, 1}, [][]byte{{','}, {','}}},
- {`{{{",",","},{",",","},{",",","}}}`, `,`, []int{1, 3, 2}, [][]byte{
- {','}, {','}, {','}, {','}, {','}, {','},
- }},
- {`{"\"}"}`, `,`, []int{1}, [][]byte{{'"', '}'}}},
- {`{"\"","\""}`, `,`, []int{2}, [][]byte{{'"'}, {'"'}}},
- {`{{"\"","\""}}`, `,`, []int{1, 2}, [][]byte{{'"'}, {'"'}}},
- {`{{"\""},{"\""}}`, `,`, []int{2, 1}, [][]byte{{'"'}, {'"'}}},
- {`{{{"\"","\""},{"\"","\""},{"\"","\""}}}`, `,`, []int{1, 3, 2}, [][]byte{
- {'"'}, {'"'}, {'"'}, {'"'}, {'"'}, {'"'},
- }},
- {`{axyzb}`, `xyz`, []int{2}, [][]byte{{'a'}, {'b'}}},
- } {
- dims, elems, err := parseArray([]byte(tt.input), []byte(tt.delim))
- if err != nil {
- t.Fatalf("Expected no error for %q, got %q", tt.input, err)
- }
- if !reflect.DeepEqual(dims, tt.dims) {
- t.Errorf("Expected %v dimensions for %q, got %v", tt.dims, tt.input, dims)
- }
- if !reflect.DeepEqual(elems, tt.elems) {
- t.Errorf("Expected %v elements for %q, got %v", tt.elems, tt.input, elems)
- }
- }
- }
- func TestParseArrayError(t *testing.T) {
- for _, tt := range []struct {
- input, err string
- }{
- {``, "expected '{' at offset 0"},
- {`x`, "expected '{' at offset 0"},
- {`}`, "expected '{' at offset 0"},
- {`{`, "expected '}' at offset 1"},
- {`{{}`, "expected '}' at offset 3"},
- {`{}}`, "unexpected '}' at offset 2"},
- {`{,}`, "unexpected ',' at offset 1"},
- {`{,x}`, "unexpected ',' at offset 1"},
- {`{x,}`, "unexpected '}' at offset 3"},
- {`{x,{`, "unexpected '{' at offset 3"},
- {`{x},`, "unexpected ',' at offset 3"},
- {`{x}}`, "unexpected '}' at offset 3"},
- {`{{x}`, "expected '}' at offset 4"},
- {`{""x}`, "unexpected 'x' at offset 3"},
- {`{{a},{b,c}}`, "multidimensional arrays must have elements with matching dimensions"},
- } {
- _, _, err := parseArray([]byte(tt.input), []byte{','})
- if err == nil {
- t.Fatalf("Expected error for %q, got none", tt.input)
- }
- if !strings.Contains(err.Error(), tt.err) {
- t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err)
- }
- }
- }
- func TestArrayScanner(t *testing.T) {
- var s sql.Scanner = Array(&[]bool{})
- if _, ok := s.(*BoolArray); !ok {
- t.Errorf("Expected *BoolArray, got %T", s)
- }
- s = Array(&[]float64{})
- if _, ok := s.(*Float64Array); !ok {
- t.Errorf("Expected *Float64Array, got %T", s)
- }
- s = Array(&[]int64{})
- if _, ok := s.(*Int64Array); !ok {
- t.Errorf("Expected *Int64Array, got %T", s)
- }
- s = Array(&[]string{})
- if _, ok := s.(*StringArray); !ok {
- t.Errorf("Expected *StringArray, got %T", s)
- }
- for _, tt := range []interface{}{
- &[]sql.Scanner{},
- &[][]bool{},
- &[][]float64{},
- &[][]int64{},
- &[][]string{},
- } {
- s = Array(tt)
- if _, ok := s.(GenericArray); !ok {
- t.Errorf("Expected GenericArray for %T, got %T", tt, s)
- }
- }
- }
- func TestArrayValuer(t *testing.T) {
- var v driver.Valuer = Array([]bool{})
- if _, ok := v.(*BoolArray); !ok {
- t.Errorf("Expected *BoolArray, got %T", v)
- }
- v = Array([]float64{})
- if _, ok := v.(*Float64Array); !ok {
- t.Errorf("Expected *Float64Array, got %T", v)
- }
- v = Array([]int64{})
- if _, ok := v.(*Int64Array); !ok {
- t.Errorf("Expected *Int64Array, got %T", v)
- }
- v = Array([]string{})
- if _, ok := v.(*StringArray); !ok {
- t.Errorf("Expected *StringArray, got %T", v)
- }
- for _, tt := range []interface{}{
- nil,
- []driver.Value{},
- [][]bool{},
- [][]float64{},
- [][]int64{},
- [][]string{},
- } {
- v = Array(tt)
- if _, ok := v.(GenericArray); !ok {
- t.Errorf("Expected GenericArray for %T, got %T", tt, v)
- }
- }
- }
- func TestBoolArrayScanUnsupported(t *testing.T) {
- var arr BoolArray
- err := arr.Scan(1)
- if err == nil {
- t.Fatal("Expected error when scanning from int")
- }
- if !strings.Contains(err.Error(), "int to BoolArray") {
- t.Errorf("Expected type to be mentioned when scanning, got %q", err)
- }
- }
- func TestBoolArrayScanEmpty(t *testing.T) {
- var arr BoolArray
- err := arr.Scan(`{}`)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr == nil || len(arr) != 0 {
- t.Errorf("Expected empty, got %#v", arr)
- }
- }
- func TestBoolArrayScanNil(t *testing.T) {
- arr := BoolArray{true, true, true}
- err := arr.Scan(nil)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr != nil {
- t.Errorf("Expected nil, got %+v", arr)
- }
- }
- var BoolArrayStringTests = []struct {
- str string
- arr BoolArray
- }{
- {`{}`, BoolArray{}},
- {`{t}`, BoolArray{true}},
- {`{f,t}`, BoolArray{false, true}},
- }
- func TestBoolArrayScanBytes(t *testing.T) {
- for _, tt := range BoolArrayStringTests {
- bytes := []byte(tt.str)
- arr := BoolArray{true, true, true}
- err := arr.Scan(bytes)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", bytes, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr)
- }
- }
- }
- func BenchmarkBoolArrayScanBytes(b *testing.B) {
- var a BoolArray
- var x interface{} = []byte(`{t,f,t,f,t,f,t,f,t,f}`)
- for i := 0; i < b.N; i++ {
- a = BoolArray{}
- a.Scan(x)
- }
- }
- func TestBoolArrayScanString(t *testing.T) {
- for _, tt := range BoolArrayStringTests {
- arr := BoolArray{true, true, true}
- err := arr.Scan(tt.str)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", tt.str, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr)
- }
- }
- }
- func TestBoolArrayScanError(t *testing.T) {
- for _, tt := range []struct {
- input, err string
- }{
- {``, "unable to parse array"},
- {`{`, "unable to parse array"},
- {`{{t},{f}}`, "cannot convert ARRAY[2][1] to BoolArray"},
- {`{NULL}`, `could not parse boolean array index 0: invalid boolean ""`},
- {`{a}`, `could not parse boolean array index 0: invalid boolean "a"`},
- {`{t,b}`, `could not parse boolean array index 1: invalid boolean "b"`},
- {`{t,f,cd}`, `could not parse boolean array index 2: invalid boolean "cd"`},
- } {
- arr := BoolArray{true, true, true}
- err := arr.Scan(tt.input)
- if err == nil {
- t.Fatalf("Expected error for %q, got none", tt.input)
- }
- if !strings.Contains(err.Error(), tt.err) {
- t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err)
- }
- if !reflect.DeepEqual(arr, BoolArray{true, true, true}) {
- t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr)
- }
- }
- }
- func TestBoolArrayValue(t *testing.T) {
- result, err := BoolArray(nil).Value()
- if err != nil {
- t.Fatalf("Expected no error for nil, got %v", err)
- }
- if result != nil {
- t.Errorf("Expected nil, got %q", result)
- }
- result, err = BoolArray([]bool{}).Value()
- if err != nil {
- t.Fatalf("Expected no error for empty, got %v", err)
- }
- if expected := `{}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected empty, got %q", result)
- }
- result, err = BoolArray([]bool{false, true, false}).Value()
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if expected := `{f,t,f}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected %q, got %q", expected, result)
- }
- }
- func BenchmarkBoolArrayValue(b *testing.B) {
- rand.Seed(1)
- x := make([]bool, 10)
- for i := 0; i < len(x); i++ {
- x[i] = rand.Intn(2) == 0
- }
- a := BoolArray(x)
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func TestByteaArrayScanUnsupported(t *testing.T) {
- var arr ByteaArray
- err := arr.Scan(1)
- if err == nil {
- t.Fatal("Expected error when scanning from int")
- }
- if !strings.Contains(err.Error(), "int to ByteaArray") {
- t.Errorf("Expected type to be mentioned when scanning, got %q", err)
- }
- }
- func TestByteaArrayScanEmpty(t *testing.T) {
- var arr ByteaArray
- err := arr.Scan(`{}`)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr == nil || len(arr) != 0 {
- t.Errorf("Expected empty, got %#v", arr)
- }
- }
- func TestByteaArrayScanNil(t *testing.T) {
- arr := ByteaArray{{2}, {6}, {0, 0}}
- err := arr.Scan(nil)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr != nil {
- t.Errorf("Expected nil, got %+v", arr)
- }
- }
- var ByteaArrayStringTests = []struct {
- str string
- arr ByteaArray
- }{
- {`{}`, ByteaArray{}},
- {`{NULL}`, ByteaArray{nil}},
- {`{"\\xfeff"}`, ByteaArray{{'\xFE', '\xFF'}}},
- {`{"\\xdead","\\xbeef"}`, ByteaArray{{'\xDE', '\xAD'}, {'\xBE', '\xEF'}}},
- }
- func TestByteaArrayScanBytes(t *testing.T) {
- for _, tt := range ByteaArrayStringTests {
- bytes := []byte(tt.str)
- arr := ByteaArray{{2}, {6}, {0, 0}}
- err := arr.Scan(bytes)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", bytes, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr)
- }
- }
- }
- func BenchmarkByteaArrayScanBytes(b *testing.B) {
- var a ByteaArray
- var x interface{} = []byte(`{"\\xfe","\\xff","\\xdead","\\xbeef","\\xfe","\\xff","\\xdead","\\xbeef","\\xfe","\\xff"}`)
- for i := 0; i < b.N; i++ {
- a = ByteaArray{}
- a.Scan(x)
- }
- }
- func TestByteaArrayScanString(t *testing.T) {
- for _, tt := range ByteaArrayStringTests {
- arr := ByteaArray{{2}, {6}, {0, 0}}
- err := arr.Scan(tt.str)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", tt.str, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr)
- }
- }
- }
- func TestByteaArrayScanError(t *testing.T) {
- for _, tt := range []struct {
- input, err string
- }{
- {``, "unable to parse array"},
- {`{`, "unable to parse array"},
- {`{{"\\xfeff"},{"\\xbeef"}}`, "cannot convert ARRAY[2][1] to ByteaArray"},
- {`{"\\abc"}`, "could not parse bytea array index 0: could not parse bytea value"},
- } {
- arr := ByteaArray{{2}, {6}, {0, 0}}
- err := arr.Scan(tt.input)
- if err == nil {
- t.Fatalf("Expected error for %q, got none", tt.input)
- }
- if !strings.Contains(err.Error(), tt.err) {
- t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err)
- }
- if !reflect.DeepEqual(arr, ByteaArray{{2}, {6}, {0, 0}}) {
- t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr)
- }
- }
- }
- func TestByteaArrayValue(t *testing.T) {
- result, err := ByteaArray(nil).Value()
- if err != nil {
- t.Fatalf("Expected no error for nil, got %v", err)
- }
- if result != nil {
- t.Errorf("Expected nil, got %q", result)
- }
- result, err = ByteaArray([][]byte{}).Value()
- if err != nil {
- t.Fatalf("Expected no error for empty, got %v", err)
- }
- if expected := `{}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected empty, got %q", result)
- }
- result, err = ByteaArray([][]byte{{'\xDE', '\xAD', '\xBE', '\xEF'}, {'\xFE', '\xFF'}, {}}).Value()
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if expected := `{"\\xdeadbeef","\\xfeff","\\x"}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected %q, got %q", expected, result)
- }
- }
- func BenchmarkByteaArrayValue(b *testing.B) {
- rand.Seed(1)
- x := make([][]byte, 10)
- for i := 0; i < len(x); i++ {
- x[i] = make([]byte, len(x))
- for j := 0; j < len(x); j++ {
- x[i][j] = byte(rand.Int())
- }
- }
- a := ByteaArray(x)
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func TestFloat64ArrayScanUnsupported(t *testing.T) {
- var arr Float64Array
- err := arr.Scan(true)
- if err == nil {
- t.Fatal("Expected error when scanning from bool")
- }
- if !strings.Contains(err.Error(), "bool to Float64Array") {
- t.Errorf("Expected type to be mentioned when scanning, got %q", err)
- }
- }
- func TestFloat64ArrayScanEmpty(t *testing.T) {
- var arr Float64Array
- err := arr.Scan(`{}`)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr == nil || len(arr) != 0 {
- t.Errorf("Expected empty, got %#v", arr)
- }
- }
- func TestFloat64ArrayScanNil(t *testing.T) {
- arr := Float64Array{5, 5, 5}
- err := arr.Scan(nil)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr != nil {
- t.Errorf("Expected nil, got %+v", arr)
- }
- }
- var Float64ArrayStringTests = []struct {
- str string
- arr Float64Array
- }{
- {`{}`, Float64Array{}},
- {`{1.2}`, Float64Array{1.2}},
- {`{3.456,7.89}`, Float64Array{3.456, 7.89}},
- {`{3,1,2}`, Float64Array{3, 1, 2}},
- }
- func TestFloat64ArrayScanBytes(t *testing.T) {
- for _, tt := range Float64ArrayStringTests {
- bytes := []byte(tt.str)
- arr := Float64Array{5, 5, 5}
- err := arr.Scan(bytes)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", bytes, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr)
- }
- }
- }
- func BenchmarkFloat64ArrayScanBytes(b *testing.B) {
- var a Float64Array
- var x interface{} = []byte(`{1.2,3.4,5.6,7.8,9.01,2.34,5.67,8.90,1.234,5.678}`)
- for i := 0; i < b.N; i++ {
- a = Float64Array{}
- a.Scan(x)
- }
- }
- func TestFloat64ArrayScanString(t *testing.T) {
- for _, tt := range Float64ArrayStringTests {
- arr := Float64Array{5, 5, 5}
- err := arr.Scan(tt.str)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", tt.str, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr)
- }
- }
- }
- func TestFloat64ArrayScanError(t *testing.T) {
- for _, tt := range []struct {
- input, err string
- }{
- {``, "unable to parse array"},
- {`{`, "unable to parse array"},
- {`{{5.6},{7.8}}`, "cannot convert ARRAY[2][1] to Float64Array"},
- {`{NULL}`, "parsing array element index 0:"},
- {`{a}`, "parsing array element index 0:"},
- {`{5.6,a}`, "parsing array element index 1:"},
- {`{5.6,7.8,a}`, "parsing array element index 2:"},
- } {
- arr := Float64Array{5, 5, 5}
- err := arr.Scan(tt.input)
- if err == nil {
- t.Fatalf("Expected error for %q, got none", tt.input)
- }
- if !strings.Contains(err.Error(), tt.err) {
- t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err)
- }
- if !reflect.DeepEqual(arr, Float64Array{5, 5, 5}) {
- t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr)
- }
- }
- }
- func TestFloat64ArrayValue(t *testing.T) {
- result, err := Float64Array(nil).Value()
- if err != nil {
- t.Fatalf("Expected no error for nil, got %v", err)
- }
- if result != nil {
- t.Errorf("Expected nil, got %q", result)
- }
- result, err = Float64Array([]float64{}).Value()
- if err != nil {
- t.Fatalf("Expected no error for empty, got %v", err)
- }
- if expected := `{}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected empty, got %q", result)
- }
- result, err = Float64Array([]float64{1.2, 3.4, 5.6}).Value()
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if expected := `{1.2,3.4,5.6}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected %q, got %q", expected, result)
- }
- }
- func BenchmarkFloat64ArrayValue(b *testing.B) {
- rand.Seed(1)
- x := make([]float64, 10)
- for i := 0; i < len(x); i++ {
- x[i] = rand.NormFloat64()
- }
- a := Float64Array(x)
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func TestInt64ArrayScanUnsupported(t *testing.T) {
- var arr Int64Array
- err := arr.Scan(true)
- if err == nil {
- t.Fatal("Expected error when scanning from bool")
- }
- if !strings.Contains(err.Error(), "bool to Int64Array") {
- t.Errorf("Expected type to be mentioned when scanning, got %q", err)
- }
- }
- func TestInt64ArrayScanEmpty(t *testing.T) {
- var arr Int64Array
- err := arr.Scan(`{}`)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr == nil || len(arr) != 0 {
- t.Errorf("Expected empty, got %#v", arr)
- }
- }
- func TestInt64ArrayScanNil(t *testing.T) {
- arr := Int64Array{5, 5, 5}
- err := arr.Scan(nil)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr != nil {
- t.Errorf("Expected nil, got %+v", arr)
- }
- }
- var Int64ArrayStringTests = []struct {
- str string
- arr Int64Array
- }{
- {`{}`, Int64Array{}},
- {`{12}`, Int64Array{12}},
- {`{345,678}`, Int64Array{345, 678}},
- }
- func TestInt64ArrayScanBytes(t *testing.T) {
- for _, tt := range Int64ArrayStringTests {
- bytes := []byte(tt.str)
- arr := Int64Array{5, 5, 5}
- err := arr.Scan(bytes)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", bytes, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr)
- }
- }
- }
- func BenchmarkInt64ArrayScanBytes(b *testing.B) {
- var a Int64Array
- var x interface{} = []byte(`{1,2,3,4,5,6,7,8,9,0}`)
- for i := 0; i < b.N; i++ {
- a = Int64Array{}
- a.Scan(x)
- }
- }
- func TestInt64ArrayScanString(t *testing.T) {
- for _, tt := range Int64ArrayStringTests {
- arr := Int64Array{5, 5, 5}
- err := arr.Scan(tt.str)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", tt.str, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr)
- }
- }
- }
- func TestInt64ArrayScanError(t *testing.T) {
- for _, tt := range []struct {
- input, err string
- }{
- {``, "unable to parse array"},
- {`{`, "unable to parse array"},
- {`{{5},{6}}`, "cannot convert ARRAY[2][1] to Int64Array"},
- {`{NULL}`, "parsing array element index 0:"},
- {`{a}`, "parsing array element index 0:"},
- {`{5,a}`, "parsing array element index 1:"},
- {`{5,6,a}`, "parsing array element index 2:"},
- } {
- arr := Int64Array{5, 5, 5}
- err := arr.Scan(tt.input)
- if err == nil {
- t.Fatalf("Expected error for %q, got none", tt.input)
- }
- if !strings.Contains(err.Error(), tt.err) {
- t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err)
- }
- if !reflect.DeepEqual(arr, Int64Array{5, 5, 5}) {
- t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr)
- }
- }
- }
- func TestInt64ArrayValue(t *testing.T) {
- result, err := Int64Array(nil).Value()
- if err != nil {
- t.Fatalf("Expected no error for nil, got %v", err)
- }
- if result != nil {
- t.Errorf("Expected nil, got %q", result)
- }
- result, err = Int64Array([]int64{}).Value()
- if err != nil {
- t.Fatalf("Expected no error for empty, got %v", err)
- }
- if expected := `{}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected empty, got %q", result)
- }
- result, err = Int64Array([]int64{1, 2, 3}).Value()
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if expected := `{1,2,3}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected %q, got %q", expected, result)
- }
- }
- func BenchmarkInt64ArrayValue(b *testing.B) {
- rand.Seed(1)
- x := make([]int64, 10)
- for i := 0; i < len(x); i++ {
- x[i] = rand.Int63()
- }
- a := Int64Array(x)
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func TestStringArrayScanUnsupported(t *testing.T) {
- var arr StringArray
- err := arr.Scan(true)
- if err == nil {
- t.Fatal("Expected error when scanning from bool")
- }
- if !strings.Contains(err.Error(), "bool to StringArray") {
- t.Errorf("Expected type to be mentioned when scanning, got %q", err)
- }
- }
- func TestStringArrayScanEmpty(t *testing.T) {
- var arr StringArray
- err := arr.Scan(`{}`)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr == nil || len(arr) != 0 {
- t.Errorf("Expected empty, got %#v", arr)
- }
- }
- func TestStringArrayScanNil(t *testing.T) {
- arr := StringArray{"x", "x", "x"}
- err := arr.Scan(nil)
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if arr != nil {
- t.Errorf("Expected nil, got %+v", arr)
- }
- }
- var StringArrayStringTests = []struct {
- str string
- arr StringArray
- }{
- {`{}`, StringArray{}},
- {`{t}`, StringArray{"t"}},
- {`{f,1}`, StringArray{"f", "1"}},
- {`{"a\\b","c d",","}`, StringArray{"a\\b", "c d", ","}},
- }
- func TestStringArrayScanBytes(t *testing.T) {
- for _, tt := range StringArrayStringTests {
- bytes := []byte(tt.str)
- arr := StringArray{"x", "x", "x"}
- err := arr.Scan(bytes)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", bytes, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr)
- }
- }
- }
- func BenchmarkStringArrayScanBytes(b *testing.B) {
- var a StringArray
- var x interface{} = []byte(`{a,b,c,d,e,f,g,h,i,j}`)
- var y interface{} = []byte(`{"\a","\b","\c","\d","\e","\f","\g","\h","\i","\j"}`)
- for i := 0; i < b.N; i++ {
- a = StringArray{}
- a.Scan(x)
- a = StringArray{}
- a.Scan(y)
- }
- }
- func TestStringArrayScanString(t *testing.T) {
- for _, tt := range StringArrayStringTests {
- arr := StringArray{"x", "x", "x"}
- err := arr.Scan(tt.str)
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", tt.str, err)
- }
- if !reflect.DeepEqual(arr, tt.arr) {
- t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr)
- }
- }
- }
- func TestStringArrayScanError(t *testing.T) {
- for _, tt := range []struct {
- input, err string
- }{
- {``, "unable to parse array"},
- {`{`, "unable to parse array"},
- {`{{a},{b}}`, "cannot convert ARRAY[2][1] to StringArray"},
- {`{NULL}`, "parsing array element index 0: cannot convert nil to string"},
- {`{a,NULL}`, "parsing array element index 1: cannot convert nil to string"},
- {`{a,b,NULL}`, "parsing array element index 2: cannot convert nil to string"},
- } {
- arr := StringArray{"x", "x", "x"}
- err := arr.Scan(tt.input)
- if err == nil {
- t.Fatalf("Expected error for %q, got none", tt.input)
- }
- if !strings.Contains(err.Error(), tt.err) {
- t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err)
- }
- if !reflect.DeepEqual(arr, StringArray{"x", "x", "x"}) {
- t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr)
- }
- }
- }
- func TestStringArrayValue(t *testing.T) {
- result, err := StringArray(nil).Value()
- if err != nil {
- t.Fatalf("Expected no error for nil, got %v", err)
- }
- if result != nil {
- t.Errorf("Expected nil, got %q", result)
- }
- result, err = StringArray([]string{}).Value()
- if err != nil {
- t.Fatalf("Expected no error for empty, got %v", err)
- }
- if expected := `{}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected empty, got %q", result)
- }
- result, err = StringArray([]string{`a`, `\b`, `c"`, `d,e`}).Value()
- if err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if expected := `{"a","\\b","c\"","d,e"}`; !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected %q, got %q", expected, result)
- }
- }
- func BenchmarkStringArrayValue(b *testing.B) {
- x := make([]string, 10)
- for i := 0; i < len(x); i++ {
- x[i] = strings.Repeat(`abc"def\ghi`, 5)
- }
- a := StringArray(x)
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func TestGenericArrayScanUnsupported(t *testing.T) {
- var s string
- var ss []string
- var nsa [1]sql.NullString
- for _, tt := range []struct {
- src, dest interface{}
- err string
- }{
- {nil, nil, "destination <nil> is not a pointer to array or slice"},
- {nil, true, "destination bool is not a pointer to array or slice"},
- {nil, &s, "destination *string is not a pointer to array or slice"},
- {nil, ss, "destination []string is not a pointer to array or slice"},
- {nil, &nsa, "<nil> to [1]sql.NullString"},
- {true, &ss, "bool to []string"},
- {`{{x}}`, &ss, "multidimensional ARRAY[1][1] is not implemented"},
- {`{{x},{x}}`, &ss, "multidimensional ARRAY[2][1] is not implemented"},
- {`{x}`, &ss, "scanning to string is not implemented"},
- } {
- err := GenericArray{tt.dest}.Scan(tt.src)
- if err == nil {
- t.Fatalf("Expected error for [%#v %#v]", tt.src, tt.dest)
- }
- if !strings.Contains(err.Error(), tt.err) {
- t.Errorf("Expected error to contain %q for [%#v %#v], got %q", tt.err, tt.src, tt.dest, err)
- }
- }
- }
- func TestGenericArrayScanScannerArrayBytes(t *testing.T) {
- src, expected, nsa := []byte(`{NULL,abc,"\""}`),
- [3]sql.NullString{{}, {String: `abc`, Valid: true}, {String: `"`, Valid: true}},
- [3]sql.NullString{{String: ``, Valid: true}, {}, {}}
- if err := (GenericArray{&nsa}).Scan(src); err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if !reflect.DeepEqual(nsa, expected) {
- t.Errorf("Expected %v, got %v", expected, nsa)
- }
- }
- func TestGenericArrayScanScannerArrayString(t *testing.T) {
- src, expected, nsa := `{NULL,"\"",xyz}`,
- [3]sql.NullString{{}, {String: `"`, Valid: true}, {String: `xyz`, Valid: true}},
- [3]sql.NullString{{String: ``, Valid: true}, {}, {}}
- if err := (GenericArray{&nsa}).Scan(src); err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if !reflect.DeepEqual(nsa, expected) {
- t.Errorf("Expected %v, got %v", expected, nsa)
- }
- }
- func TestGenericArrayScanScannerSliceEmpty(t *testing.T) {
- var nss []sql.NullString
- if err := (GenericArray{&nss}).Scan(`{}`); err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if nss == nil || len(nss) != 0 {
- t.Errorf("Expected empty, got %#v", nss)
- }
- }
- func TestGenericArrayScanScannerSliceNil(t *testing.T) {
- nss := []sql.NullString{{String: ``, Valid: true}, {}}
- if err := (GenericArray{&nss}).Scan(nil); err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if nss != nil {
- t.Errorf("Expected nil, got %+v", nss)
- }
- }
- func TestGenericArrayScanScannerSliceBytes(t *testing.T) {
- src, expected, nss := []byte(`{NULL,abc,"\""}`),
- []sql.NullString{{}, {String: `abc`, Valid: true}, {String: `"`, Valid: true}},
- []sql.NullString{{String: ``, Valid: true}, {}, {}, {}, {}}
- if err := (GenericArray{&nss}).Scan(src); err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if !reflect.DeepEqual(nss, expected) {
- t.Errorf("Expected %v, got %v", expected, nss)
- }
- }
- func BenchmarkGenericArrayScanScannerSliceBytes(b *testing.B) {
- var a GenericArray
- var x interface{} = []byte(`{a,b,c,d,e,f,g,h,i,j}`)
- var y interface{} = []byte(`{"\a","\b","\c","\d","\e","\f","\g","\h","\i","\j"}`)
- for i := 0; i < b.N; i++ {
- a = GenericArray{new([]sql.NullString)}
- a.Scan(x)
- a = GenericArray{new([]sql.NullString)}
- a.Scan(y)
- }
- }
- func TestGenericArrayScanScannerSliceString(t *testing.T) {
- src, expected, nss := `{NULL,"\"",xyz}`,
- []sql.NullString{{}, {String: `"`, Valid: true}, {String: `xyz`, Valid: true}},
- []sql.NullString{{String: ``, Valid: true}, {}, {}}
- if err := (GenericArray{&nss}).Scan(src); err != nil {
- t.Fatalf("Expected no error, got %v", err)
- }
- if !reflect.DeepEqual(nss, expected) {
- t.Errorf("Expected %v, got %v", expected, nss)
- }
- }
- type TildeNullInt64 struct{ sql.NullInt64 }
- func (TildeNullInt64) ArrayDelimiter() string { return "~" }
- func TestGenericArrayScanDelimiter(t *testing.T) {
- src, expected, tnis := `{12~NULL~76}`,
- []TildeNullInt64{{sql.NullInt64{Int64: 12, Valid: true}}, {}, {sql.NullInt64{Int64: 76, Valid: true}}},
- []TildeNullInt64{{sql.NullInt64{Int64: 0, Valid: true}}, {}}
- if err := (GenericArray{&tnis}).Scan(src); err != nil {
- t.Fatalf("Expected no error for %#v, got %v", src, err)
- }
- if !reflect.DeepEqual(tnis, expected) {
- t.Errorf("Expected %v for %#v, got %v", expected, src, tnis)
- }
- }
- func TestGenericArrayScanErrors(t *testing.T) {
- var sa [1]string
- var nis []sql.NullInt64
- var pss *[]string
- for _, tt := range []struct {
- src, dest interface{}
- err string
- }{
- {nil, pss, "destination *[]string is nil"},
- {`{`, &sa, "unable to parse"},
- {`{}`, &sa, "cannot convert ARRAY[0] to [1]string"},
- {`{x,x}`, &sa, "cannot convert ARRAY[2] to [1]string"},
- {`{x}`, &nis, `parsing array element index 0: converting`},
- } {
- err := GenericArray{tt.dest}.Scan(tt.src)
- if err == nil {
- t.Fatalf("Expected error for [%#v %#v]", tt.src, tt.dest)
- }
- if !strings.Contains(err.Error(), tt.err) {
- t.Errorf("Expected error to contain %q for [%#v %#v], got %q", tt.err, tt.src, tt.dest, err)
- }
- }
- }
- func TestGenericArrayValueUnsupported(t *testing.T) {
- _, err := GenericArray{true}.Value()
- if err == nil {
- t.Fatal("Expected error for bool")
- }
- if !strings.Contains(err.Error(), "bool to array") {
- t.Errorf("Expected type to be mentioned, got %q", err)
- }
- }
- type ByteArrayValuer [1]byte
- type ByteSliceValuer []byte
- type FuncArrayValuer struct {
- delimiter func() string
- value func() (driver.Value, error)
- }
- func (a ByteArrayValuer) Value() (driver.Value, error) { return a[:], nil }
- func (b ByteSliceValuer) Value() (driver.Value, error) { return []byte(b), nil }
- func (f FuncArrayValuer) ArrayDelimiter() string { return f.delimiter() }
- func (f FuncArrayValuer) Value() (driver.Value, error) { return f.value() }
- func TestGenericArrayValue(t *testing.T) {
- result, err := GenericArray{nil}.Value()
- if err != nil {
- t.Fatalf("Expected no error for nil, got %v", err)
- }
- if result != nil {
- t.Errorf("Expected nil, got %q", result)
- }
- for _, tt := range []interface{}{
- []bool(nil),
- [][]int(nil),
- []*int(nil),
- []sql.NullString(nil),
- } {
- result, err := GenericArray{tt}.Value()
- if err != nil {
- t.Fatalf("Expected no error for %#v, got %v", tt, err)
- }
- if result != nil {
- t.Errorf("Expected nil for %#v, got %q", tt, result)
- }
- }
- Tilde := func(v driver.Value) FuncArrayValuer {
- return FuncArrayValuer{
- func() string { return "~" },
- func() (driver.Value, error) { return v, nil }}
- }
- for _, tt := range []struct {
- result string
- input interface{}
- }{
- {`{}`, []bool{}},
- {`{true}`, []bool{true}},
- {`{true,false}`, []bool{true, false}},
- {`{true,false}`, [2]bool{true, false}},
- {`{}`, [][]int{{}}},
- {`{}`, [][]int{{}, {}}},
- {`{{1}}`, [][]int{{1}}},
- {`{{1},{2}}`, [][]int{{1}, {2}}},
- {`{{1,2},{3,4}}`, [][]int{{1, 2}, {3, 4}}},
- {`{{1,2},{3,4}}`, [2][2]int{{1, 2}, {3, 4}}},
- {`{"a","\\b","c\"","d,e"}`, []string{`a`, `\b`, `c"`, `d,e`}},
- {`{"a","\\b","c\"","d,e"}`, [][]byte{{'a'}, {'\\', 'b'}, {'c', '"'}, {'d', ',', 'e'}}},
- {`{NULL}`, []*int{nil}},
- {`{0,NULL}`, []*int{new(int), nil}},
- {`{NULL}`, []sql.NullString{{}}},
- {`{"\"",NULL}`, []sql.NullString{{String: `"`, Valid: true}, {}}},
- {`{"a","b"}`, []ByteArrayValuer{{'a'}, {'b'}}},
- {`{{"a","b"},{"c","d"}}`, [][]ByteArrayValuer{{{'a'}, {'b'}}, {{'c'}, {'d'}}}},
- {`{"e","f"}`, []ByteSliceValuer{{'e'}, {'f'}}},
- {`{{"e","f"},{"g","h"}}`, [][]ByteSliceValuer{{{'e'}, {'f'}}, {{'g'}, {'h'}}}},
- {`{1~2}`, []FuncArrayValuer{Tilde(int64(1)), Tilde(int64(2))}},
- {`{{1~2}~{3~4}}`, [][]FuncArrayValuer{{Tilde(int64(1)), Tilde(int64(2))}, {Tilde(int64(3)), Tilde(int64(4))}}},
- } {
- result, err := GenericArray{tt.input}.Value()
- if err != nil {
- t.Fatalf("Expected no error for %q, got %v", tt.input, err)
- }
- if !reflect.DeepEqual(result, tt.result) {
- t.Errorf("Expected %q for %q, got %q", tt.result, tt.input, result)
- }
- }
- }
- func TestGenericArrayValueErrors(t *testing.T) {
- v := []interface{}{func() {}}
- if _, err := (GenericArray{v}).Value(); err == nil {
- t.Errorf("Expected error for %q, got nil", v)
- }
- v = []interface{}{nil, func() {}}
- if _, err := (GenericArray{v}).Value(); err == nil {
- t.Errorf("Expected error for %q, got nil", v)
- }
- }
- func BenchmarkGenericArrayValueBools(b *testing.B) {
- rand.Seed(1)
- x := make([]bool, 10)
- for i := 0; i < len(x); i++ {
- x[i] = rand.Intn(2) == 0
- }
- a := GenericArray{x}
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func BenchmarkGenericArrayValueFloat64s(b *testing.B) {
- rand.Seed(1)
- x := make([]float64, 10)
- for i := 0; i < len(x); i++ {
- x[i] = rand.NormFloat64()
- }
- a := GenericArray{x}
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func BenchmarkGenericArrayValueInt64s(b *testing.B) {
- rand.Seed(1)
- x := make([]int64, 10)
- for i := 0; i < len(x); i++ {
- x[i] = rand.Int63()
- }
- a := GenericArray{x}
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func BenchmarkGenericArrayValueByteSlices(b *testing.B) {
- x := make([][]byte, 10)
- for i := 0; i < len(x); i++ {
- x[i] = bytes.Repeat([]byte(`abc"def\ghi`), 5)
- }
- a := GenericArray{x}
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func BenchmarkGenericArrayValueStrings(b *testing.B) {
- x := make([]string, 10)
- for i := 0; i < len(x); i++ {
- x[i] = strings.Repeat(`abc"def\ghi`, 5)
- }
- a := GenericArray{x}
- for i := 0; i < b.N; i++ {
- a.Value()
- }
- }
- func TestArrayScanBackend(t *testing.T) {
- db := openTestConn(t)
- defer db.Close()
- for _, tt := range []struct {
- s string
- d sql.Scanner
- e interface{}
- }{
- {`ARRAY[true, false]`, new(BoolArray), &BoolArray{true, false}},
- {`ARRAY[E'\\xdead', E'\\xbeef']`, new(ByteaArray), &ByteaArray{{'\xDE', '\xAD'}, {'\xBE', '\xEF'}}},
- {`ARRAY[1.2, 3.4]`, new(Float64Array), &Float64Array{1.2, 3.4}},
- {`ARRAY[1, 2, 3]`, new(Int64Array), &Int64Array{1, 2, 3}},
- {`ARRAY['a', E'\\b', 'c"', 'd,e']`, new(StringArray), &StringArray{`a`, `\b`, `c"`, `d,e`}},
- } {
- err := db.QueryRow(`SELECT ` + tt.s).Scan(tt.d)
- if err != nil {
- t.Errorf("Expected no error when scanning %s into %T, got %v", tt.s, tt.d, err)
- }
- if !reflect.DeepEqual(tt.d, tt.e) {
- t.Errorf("Expected %v when scanning %s into %T, got %v", tt.e, tt.s, tt.d, tt.d)
- }
- }
- }
- func TestArrayValueBackend(t *testing.T) {
- db := openTestConn(t)
- defer db.Close()
- for _, tt := range []struct {
- s string
- v driver.Valuer
- }{
- {`ARRAY[true, false]`, BoolArray{true, false}},
- {`ARRAY[E'\\xdead', E'\\xbeef']`, ByteaArray{{'\xDE', '\xAD'}, {'\xBE', '\xEF'}}},
- {`ARRAY[1.2, 3.4]`, Float64Array{1.2, 3.4}},
- {`ARRAY[1, 2, 3]`, Int64Array{1, 2, 3}},
- {`ARRAY['a', E'\\b', 'c"', 'd,e']`, StringArray{`a`, `\b`, `c"`, `d,e`}},
- } {
- var x int
- err := db.QueryRow(`SELECT 1 WHERE `+tt.s+` <> $1`, tt.v).Scan(&x)
- if err != sql.ErrNoRows {
- t.Errorf("Expected %v to equal %s, got %v", tt.v, tt.s, err)
- }
- }
- }
|