github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/values_test.go (about) 1 // Copyright 2015 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sql 12 13 import ( 14 "context" 15 "fmt" 16 "go/constant" 17 "reflect" 18 "testing" 19 "time" 20 21 "github.com/cockroachdb/apd" 22 "github.com/cockroachdb/cockroach/pkg/base" 23 "github.com/cockroachdb/cockroach/pkg/roachpb" 24 "github.com/cockroachdb/cockroach/pkg/security" 25 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 26 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 27 "github.com/cockroachdb/cockroach/pkg/sql/types" 28 "github.com/cockroachdb/cockroach/pkg/util/bitarray" 29 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 30 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 31 "github.com/cockroachdb/cockroach/pkg/util/uuid" 32 "github.com/cockroachdb/errors" 33 "github.com/stretchr/testify/require" 34 ) 35 36 func makeTestPlanner() *planner { 37 // Initialize an Executorconfig sufficiently for the purposes of creating a 38 // planner. 39 execCfg := ExecutorConfig{ 40 NodeInfo: NodeInfo{ 41 NodeID: base.TestingIDContainer, 42 ClusterID: func() uuid.UUID { 43 return uuid.MakeV4() 44 }, 45 }, 46 } 47 48 // TODO(andrei): pass the cleanup along to the caller. 49 p, _ /* cleanup */ := newInternalPlanner( 50 "test", nil /* txn */, security.RootUser, &MemoryMetrics{}, &execCfg, 51 ) 52 return p 53 } 54 55 func TestValues(t *testing.T) { 56 defer leaktest.AfterTest(t)() 57 58 p := makeTestPlanner() 59 60 vInt := int64(5) 61 vNum := 3.14159 62 vStr := "two furs one cub" 63 vBool := true 64 65 unsupp := &tree.RangeCond{} 66 67 intVal := func(v int64) *tree.NumVal { 68 return tree.NewNumVal( 69 constant.MakeInt64(v), 70 "", /* origString */ 71 false /* negative */) 72 } 73 floatVal := func(f float64) *tree.CastExpr { 74 return &tree.CastExpr{ 75 Expr: tree.NewNumVal( 76 constant.MakeFloat64(f), 77 "", /* origString */ 78 false /* negative */), 79 Type: types.Float, 80 } 81 } 82 asRow := func(datums ...tree.Datum) []tree.Datums { 83 return []tree.Datums{datums} 84 } 85 86 makeValues := func(tuples ...tree.Exprs) *tree.ValuesClause { 87 return &tree.ValuesClause{Rows: tuples} 88 } 89 makeTuple := func(exprs ...tree.Expr) tree.Exprs { 90 return tree.Exprs(exprs) 91 } 92 93 testCases := []struct { 94 stmt *tree.ValuesClause 95 rows []tree.Datums 96 ok bool 97 }{ 98 { 99 makeValues(makeTuple(intVal(vInt))), 100 asRow(tree.NewDInt(tree.DInt(vInt))), 101 true, 102 }, 103 { 104 makeValues(makeTuple(intVal(vInt), intVal(vInt))), 105 asRow(tree.NewDInt(tree.DInt(vInt)), tree.NewDInt(tree.DInt(vInt))), 106 true, 107 }, 108 { 109 makeValues(makeTuple(floatVal(vNum))), 110 asRow(tree.NewDFloat(tree.DFloat(vNum))), 111 true, 112 }, 113 { 114 makeValues(makeTuple(tree.NewDString(vStr))), 115 asRow(tree.NewDString(vStr)), 116 true, 117 }, 118 { 119 makeValues(makeTuple(tree.NewDBytes(tree.DBytes(vStr)))), 120 asRow(tree.NewDBytes(tree.DBytes(vStr))), 121 true, 122 }, 123 { 124 makeValues(makeTuple(tree.MakeDBool(tree.DBool(vBool)))), 125 asRow(tree.MakeDBool(tree.DBool(vBool))), 126 true, 127 }, 128 { 129 makeValues(makeTuple(unsupp)), 130 nil, 131 false, 132 }, 133 } 134 135 ctx := context.Background() 136 for i, tc := range testCases { 137 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 138 plan, err := func() (_ planNode, err error) { 139 defer func() { 140 if r := recover(); r != nil { 141 err = errors.Errorf("%v", r) 142 } 143 }() 144 return p.Values(context.Background(), tc.stmt, nil) 145 }() 146 if plan != nil { 147 defer plan.Close(ctx) 148 } 149 if err == nil != tc.ok { 150 t.Errorf("%d: error_expected=%t, but got error %v", i, tc.ok, err) 151 } 152 if plan == nil { 153 return 154 } 155 params := runParams{ctx: ctx, p: p, extendedEvalCtx: &p.extendedEvalCtx} 156 if err := startExec(params, plan); err != nil { 157 t.Fatalf("%d: unexpected error in Start: %v", i, err) 158 } 159 var rows []tree.Datums 160 next, err := plan.Next(params) 161 for ; next; next, err = plan.Next(params) { 162 rows = append(rows, plan.Values()) 163 } 164 if err != nil { 165 t.Fatal(err) 166 } 167 if !reflect.DeepEqual(rows, tc.rows) { 168 t.Errorf("%d: expected rows:\n%+v\nactual rows:\n%+v", i, tc.rows, rows) 169 } 170 }) 171 } 172 } 173 174 type floatAlias float32 175 type boolAlias bool 176 type stringAlias string 177 178 func TestGolangQueryArgs(t *testing.T) { 179 defer leaktest.AfterTest(t)() 180 181 // Each test case pairs an arbitrary value and tree.Datum which has the same 182 // type 183 testCases := []struct { 184 value interface{} 185 expectedType *types.T 186 }{ 187 // Null type. 188 {nil, types.Unknown}, 189 {[]byte(nil), types.Unknown}, 190 191 // Bool type. 192 {true, types.Bool}, 193 194 // Primitive Integer types. 195 {int(1), types.Int}, 196 {int8(1), types.Int}, 197 {int16(1), types.Int}, 198 {int32(1), types.Int}, 199 {int64(1), types.Int}, 200 {uint(1), types.Int}, 201 {uint8(1), types.Int}, 202 {uint16(1), types.Int}, 203 {uint32(1), types.Int}, 204 {uint64(1), types.Int}, 205 206 // Primitive Float types. 207 {float32(1.0), types.Float}, 208 {float64(1.0), types.Float}, 209 210 // Decimal type. 211 {apd.New(55, 1), types.Decimal}, 212 213 // String type. 214 {"test", types.String}, 215 216 // Bytes type. 217 {[]byte("abc"), types.Bytes}, 218 219 // Interval and timestamp. 220 {time.Duration(1), types.Interval}, 221 {timeutil.Now(), types.Timestamp}, 222 223 // Primitive type aliases. 224 {roachpb.NodeID(1), types.Int}, 225 {sqlbase.ID(1), types.Int}, 226 {floatAlias(1), types.Float}, 227 {boolAlias(true), types.Bool}, 228 {stringAlias("string"), types.String}, 229 230 // Byte slice aliases. 231 {roachpb.Key("key"), types.Bytes}, 232 {roachpb.RKey("key"), types.Bytes}, 233 234 // Bit array. 235 {bitarray.MakeBitArrayFromInt64(8, 58, 7), types.VarBit}, 236 } 237 238 for i, tcase := range testCases { 239 datums, err := golangFillQueryArguments(tcase.value) 240 require.NoError(t, err) 241 if len(datums) != 1 { 242 t.Fatalf("expected 1 datum, got: %d", len(datums)) 243 } 244 d := datums[0] 245 if a, e := d.ResolvedType(), tcase.expectedType; !a.Equal(e) { 246 t.Errorf("case %d failed: expected type %s, got %s", i, e.String(), a.String()) 247 } 248 } 249 }