github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sqlbase/encoded_datum_test.go (about) 1 // Copyright 2016 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 sqlbase 12 13 import ( 14 "context" 15 "testing" 16 "time" 17 "unsafe" 18 19 "github.com/cockroachdb/apd" 20 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 21 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 22 "github.com/cockroachdb/cockroach/pkg/sql/types" 23 "github.com/cockroachdb/cockroach/pkg/util/encoding" 24 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 25 "github.com/cockroachdb/cockroach/pkg/util/randutil" 26 ) 27 28 func TestEncDatum(t *testing.T) { 29 defer leaktest.AfterTest(t)() 30 31 a := &DatumAlloc{} 32 evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings()) 33 defer evalCtx.Stop(context.Background()) 34 v := EncDatum{} 35 if !v.IsUnset() { 36 t.Errorf("empty EncDatum should be unset") 37 } 38 39 if _, ok := v.Encoding(); ok { 40 t.Errorf("empty EncDatum has an encoding") 41 } 42 43 x := DatumToEncDatum(types.Int, tree.NewDInt(5)) 44 45 check := func(x EncDatum) { 46 if x.IsUnset() { 47 t.Errorf("unset after DatumToEncDatum()") 48 } 49 if x.IsNull() { 50 t.Errorf("null after DatumToEncDatum()") 51 } 52 if val, err := x.GetInt(); err != nil { 53 t.Fatal(err) 54 } else if val != 5 { 55 t.Errorf("GetInt returned %d", val) 56 } 57 } 58 check(x) 59 60 encoded, err := x.Encode(types.Int, a, DatumEncoding_ASCENDING_KEY, nil) 61 if err != nil { 62 t.Fatal(err) 63 } 64 65 y := EncDatumFromEncoded(DatumEncoding_ASCENDING_KEY, encoded) 66 check(y) 67 68 if enc, ok := y.Encoding(); !ok { 69 t.Error("no encoding after EncDatumFromEncoded") 70 } else if enc != DatumEncoding_ASCENDING_KEY { 71 t.Errorf("invalid encoding %d", enc) 72 } 73 err = y.EnsureDecoded(types.Int, a) 74 if err != nil { 75 t.Fatal(err) 76 } 77 if cmp := y.Datum.Compare(evalCtx, x.Datum); cmp != 0 { 78 t.Errorf("Datums should be equal, cmp = %d", cmp) 79 } 80 81 enc2, err := y.Encode(types.Int, a, DatumEncoding_DESCENDING_KEY, nil) 82 if err != nil { 83 t.Fatal(err) 84 } 85 // y's encoding should not change. 86 if enc, ok := y.Encoding(); !ok { 87 t.Error("no encoding") 88 } else if enc != DatumEncoding_ASCENDING_KEY { 89 t.Errorf("invalid encoding %d", enc) 90 } 91 z := EncDatumFromEncoded(DatumEncoding_DESCENDING_KEY, enc2) 92 if enc, ok := z.Encoding(); !ok { 93 t.Error("no encoding") 94 } else if enc != DatumEncoding_DESCENDING_KEY { 95 t.Errorf("invalid encoding %d", enc) 96 } 97 check(z) 98 99 err = z.EnsureDecoded(types.Int, a) 100 if err != nil { 101 t.Fatal(err) 102 } 103 if cmp := y.Datum.Compare(evalCtx, z.Datum); cmp != 0 { 104 t.Errorf("Datums should be equal, cmp = %d", cmp) 105 } 106 y.UnsetDatum() 107 if !y.IsUnset() { 108 t.Error("not unset after UnsetDatum()") 109 } 110 } 111 112 func columnTypeCompatibleWithEncoding(typ *types.T, enc DatumEncoding) bool { 113 return enc == DatumEncoding_VALUE || ColumnTypeIsIndexable(typ) 114 } 115 116 func TestEncDatumNull(t *testing.T) { 117 defer leaktest.AfterTest(t)() 118 119 // Verify DNull is null. 120 n := DatumToEncDatum(types.Int, tree.DNull) 121 if !n.IsNull() { 122 t.Error("DNull not null") 123 } 124 125 var alloc DatumAlloc 126 rng, _ := randutil.NewPseudoRand() 127 128 // Generate random EncDatums (some of which are null), and verify that a datum 129 // created from its encoding has the same IsNull() value. 130 for cases := 0; cases < 100; cases++ { 131 a, typ := RandEncDatum(rng) 132 for enc := range DatumEncoding_name { 133 if !columnTypeCompatibleWithEncoding(typ, DatumEncoding(enc)) { 134 continue 135 } 136 encoded, err := a.Encode(typ, &alloc, DatumEncoding(enc), nil) 137 if err != nil { 138 t.Fatal(err) 139 } 140 b := EncDatumFromEncoded(DatumEncoding(enc), encoded) 141 if a.IsNull() != b.IsNull() { 142 t.Errorf("before: %s (null=%t) after: %s (null=%t)", 143 a.String(types.Int), a.IsNull(), b.String(types.Int), b.IsNull()) 144 } 145 } 146 } 147 148 } 149 150 // checkEncDatumCmp encodes the given values using the given encodings, 151 // creates EncDatums from those encodings and verifies the Compare result on 152 // those encodings. It also checks if the Compare resulted in decoding or not. 153 func checkEncDatumCmp( 154 t *testing.T, 155 a *DatumAlloc, 156 typ *types.T, 157 v1, v2 *EncDatum, 158 enc1, enc2 DatumEncoding, 159 expectedCmp int, 160 requiresDecode bool, 161 ) { 162 buf1, err := v1.Encode(typ, a, enc1, nil) 163 if err != nil { 164 t.Fatal(err) 165 } 166 buf2, err := v2.Encode(typ, a, enc2, nil) 167 if err != nil { 168 t.Fatal(err) 169 } 170 dec1 := EncDatumFromEncoded(enc1, buf1) 171 172 dec2 := EncDatumFromEncoded(enc2, buf2) 173 174 evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings()) 175 defer evalCtx.Stop(context.Background()) 176 if val, err := dec1.Compare(typ, a, evalCtx, &dec2); err != nil { 177 t.Fatal(err) 178 } else if val != expectedCmp { 179 t.Errorf("comparing %s (%s), %s (%s) resulted in %d, expected %d", 180 v1.String(typ), enc1, v2.String(typ), enc2, val, expectedCmp, 181 ) 182 } 183 184 if requiresDecode { 185 if dec1.Datum == nil || dec2.Datum == nil { 186 t.Errorf( 187 "comparing %s (%s), %s (%s) did not require decoding", 188 v1.String(typ), enc1, v2.String(typ), enc2, 189 ) 190 } 191 } else { 192 if dec1.Datum != nil || dec2.Datum != nil { 193 t.Errorf( 194 "comparing %s (%s), %s (%s) required decoding", 195 v1.String(typ), enc1, v2.String(typ), enc2, 196 ) 197 } 198 } 199 } 200 201 func TestEncDatumCompare(t *testing.T) { 202 defer leaktest.AfterTest(t)() 203 204 a := &DatumAlloc{} 205 evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings()) 206 defer evalCtx.Stop(context.Background()) 207 rng, _ := randutil.NewPseudoRand() 208 209 for _, typ := range types.OidToType { 210 switch typ.Family() { 211 case types.AnyFamily, types.UnknownFamily, types.ArrayFamily, types.JsonFamily, types.TupleFamily, types.GeometryFamily, types.GeographyFamily: 212 continue 213 case types.CollatedStringFamily: 214 typ = types.MakeCollatedString(types.String, *RandCollationLocale(rng)) 215 } 216 217 // Generate two datums d1 < d2 218 var d1, d2 tree.Datum 219 for { 220 d1 = RandDatum(rng, typ, false) 221 d2 = RandDatum(rng, typ, false) 222 if cmp := d1.Compare(evalCtx, d2); cmp < 0 { 223 break 224 } 225 } 226 v1 := DatumToEncDatum(typ, d1) 227 v2 := DatumToEncDatum(typ, d2) 228 229 if val, err := v1.Compare(typ, a, evalCtx, &v2); err != nil { 230 t.Fatal(err) 231 } else if val != -1 { 232 t.Errorf("compare(1, 2) = %d", val) 233 } 234 235 asc := DatumEncoding_ASCENDING_KEY 236 desc := DatumEncoding_DESCENDING_KEY 237 noncmp := DatumEncoding_VALUE 238 239 checkEncDatumCmp(t, a, typ, &v1, &v2, asc, asc, -1, false) 240 checkEncDatumCmp(t, a, typ, &v2, &v1, asc, asc, +1, false) 241 checkEncDatumCmp(t, a, typ, &v1, &v1, asc, asc, 0, false) 242 checkEncDatumCmp(t, a, typ, &v2, &v2, asc, asc, 0, false) 243 244 checkEncDatumCmp(t, a, typ, &v1, &v2, desc, desc, -1, false) 245 checkEncDatumCmp(t, a, typ, &v2, &v1, desc, desc, +1, false) 246 checkEncDatumCmp(t, a, typ, &v1, &v1, desc, desc, 0, false) 247 checkEncDatumCmp(t, a, typ, &v2, &v2, desc, desc, 0, false) 248 249 // These cases require decoding. Data with a composite key encoding cannot 250 // be decoded from their key part alone. 251 if !HasCompositeKeyEncoding(typ) { 252 checkEncDatumCmp(t, a, typ, &v1, &v2, noncmp, noncmp, -1, true) 253 checkEncDatumCmp(t, a, typ, &v2, &v1, desc, noncmp, +1, true) 254 checkEncDatumCmp(t, a, typ, &v1, &v1, asc, desc, 0, true) 255 checkEncDatumCmp(t, a, typ, &v2, &v2, desc, asc, 0, true) 256 } 257 } 258 } 259 260 func TestEncDatumFromBuffer(t *testing.T) { 261 defer leaktest.AfterTest(t)() 262 263 var alloc DatumAlloc 264 evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings()) 265 defer evalCtx.Stop(context.Background()) 266 rng, _ := randutil.NewPseudoRand() 267 for test := 0; test < 20; test++ { 268 var err error 269 // Generate a set of random datums. 270 ed := make([]EncDatum, 1+rng.Intn(10)) 271 typs := make([]*types.T, len(ed)) 272 for i := range ed { 273 d, t := RandEncDatum(rng) 274 ed[i], typs[i] = d, t 275 } 276 // Encode them in a single buffer. 277 var buf []byte 278 enc := make([]DatumEncoding, len(ed)) 279 for i := range ed { 280 if HasCompositeKeyEncoding(typs[i]) { 281 // There's no way to reconstruct data from the key part of a composite 282 // encoding. 283 enc[i] = DatumEncoding_VALUE 284 } else { 285 enc[i] = RandDatumEncoding(rng) 286 for !columnTypeCompatibleWithEncoding(typs[i], enc[i]) { 287 enc[i] = RandDatumEncoding(rng) 288 } 289 } 290 buf, err = ed[i].Encode(typs[i], &alloc, enc[i], buf) 291 if err != nil { 292 t.Fatalf("Failed to encode type %v: %s", typs[i], err) 293 } 294 } 295 // Decode the buffer. 296 b := buf 297 for i := range ed { 298 if len(b) == 0 { 299 t.Fatal("buffer ended early") 300 } 301 var decoded EncDatum 302 decoded, b, err = EncDatumFromBuffer(typs[i], enc[i], b) 303 if err != nil { 304 t.Fatalf("%+v: encdatum from %+v: %+v (%+v)", ed[i].Datum, enc[i], err, typs[i]) 305 } 306 err = decoded.EnsureDecoded(typs[i], &alloc) 307 if err != nil { 308 t.Fatalf("%+v: ensuredecoded: %v (%+v)", ed[i], err, typs[i]) 309 } 310 if decoded.Datum.Compare(evalCtx, ed[i].Datum) != 0 { 311 t.Errorf("decoded datum %+v doesn't equal original %+v", decoded.Datum, ed[i].Datum) 312 } 313 } 314 if len(b) != 0 { 315 t.Errorf("%d leftover bytes", len(b)) 316 } 317 } 318 } 319 320 func TestEncDatumRowCompare(t *testing.T) { 321 defer leaktest.AfterTest(t)() 322 323 v := [5]EncDatum{} 324 for i := range v { 325 v[i] = DatumToEncDatum(types.Int, tree.NewDInt(tree.DInt(i))) 326 } 327 328 asc := encoding.Ascending 329 desc := encoding.Descending 330 331 testCases := []struct { 332 row1, row2 EncDatumRow 333 ord ColumnOrdering 334 cmp int 335 }{ 336 { 337 row1: EncDatumRow{v[0], v[1], v[2]}, 338 row2: EncDatumRow{v[0], v[1], v[3]}, 339 ord: ColumnOrdering{}, 340 cmp: 0, 341 }, 342 { 343 row1: EncDatumRow{v[0], v[1], v[2]}, 344 row2: EncDatumRow{v[0], v[1], v[3]}, 345 ord: ColumnOrdering{{1, desc}}, 346 cmp: 0, 347 }, 348 { 349 row1: EncDatumRow{v[0], v[1], v[2]}, 350 row2: EncDatumRow{v[0], v[1], v[3]}, 351 ord: ColumnOrdering{{0, asc}, {1, desc}}, 352 cmp: 0, 353 }, 354 { 355 row1: EncDatumRow{v[0], v[1], v[2]}, 356 row2: EncDatumRow{v[0], v[1], v[3]}, 357 ord: ColumnOrdering{{2, asc}}, 358 cmp: -1, 359 }, 360 { 361 row1: EncDatumRow{v[0], v[1], v[3]}, 362 row2: EncDatumRow{v[0], v[1], v[2]}, 363 ord: ColumnOrdering{{2, asc}}, 364 cmp: 1, 365 }, 366 { 367 row1: EncDatumRow{v[0], v[1], v[2]}, 368 row2: EncDatumRow{v[0], v[1], v[3]}, 369 ord: ColumnOrdering{{2, asc}, {0, asc}, {1, asc}}, 370 cmp: -1, 371 }, 372 { 373 row1: EncDatumRow{v[0], v[1], v[2]}, 374 row2: EncDatumRow{v[0], v[1], v[3]}, 375 ord: ColumnOrdering{{0, asc}, {2, desc}}, 376 cmp: 1, 377 }, 378 { 379 row1: EncDatumRow{v[0], v[1], v[2]}, 380 row2: EncDatumRow{v[0], v[1], v[3]}, 381 ord: ColumnOrdering{{1, desc}, {0, asc}, {2, desc}}, 382 cmp: 1, 383 }, 384 { 385 row1: EncDatumRow{v[2], v[3], v[4]}, 386 row2: EncDatumRow{v[1], v[3], v[0]}, 387 ord: ColumnOrdering{{0, asc}}, 388 cmp: 1, 389 }, 390 { 391 row1: EncDatumRow{v[2], v[3], v[4]}, 392 row2: EncDatumRow{v[1], v[3], v[0]}, 393 ord: ColumnOrdering{{1, desc}, {0, asc}}, 394 cmp: 1, 395 }, 396 { 397 row1: EncDatumRow{v[2], v[3], v[4]}, 398 row2: EncDatumRow{v[1], v[3], v[0]}, 399 ord: ColumnOrdering{{1, asc}, {0, asc}}, 400 cmp: 1, 401 }, 402 { 403 row1: EncDatumRow{v[2], v[3], v[4]}, 404 row2: EncDatumRow{v[1], v[3], v[0]}, 405 ord: ColumnOrdering{{1, asc}, {0, desc}}, 406 cmp: -1, 407 }, 408 { 409 row1: EncDatumRow{v[2], v[3], v[4]}, 410 row2: EncDatumRow{v[1], v[3], v[0]}, 411 ord: ColumnOrdering{{0, desc}, {1, asc}}, 412 cmp: -1, 413 }, 414 } 415 416 a := &DatumAlloc{} 417 evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings()) 418 defer evalCtx.Stop(context.Background()) 419 for _, c := range testCases { 420 typs := make([]*types.T, len(c.row1)) 421 for i := range typs { 422 typs[i] = types.Int 423 } 424 cmp, err := c.row1.Compare(typs, a, c.ord, evalCtx, c.row2) 425 if err != nil { 426 t.Error(err) 427 } else if cmp != c.cmp { 428 t.Errorf( 429 "%s cmp %s ordering %v got %d, expected %d", 430 c.row1.String(typs), c.row2.String(typs), c.ord, cmp, c.cmp, 431 ) 432 } 433 } 434 } 435 436 func TestEncDatumRowAlloc(t *testing.T) { 437 defer leaktest.AfterTest(t)() 438 439 evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings()) 440 defer evalCtx.Stop(context.Background()) 441 rng, _ := randutil.NewPseudoRand() 442 for _, cols := range []int{1, 2, 4, 10, 40, 100} { 443 for _, rows := range []int{1, 2, 3, 5, 10, 20} { 444 colTypes := RandColumnTypes(rng, cols) 445 in := make(EncDatumRows, rows) 446 for i := 0; i < rows; i++ { 447 in[i] = make(EncDatumRow, cols) 448 for j := 0; j < cols; j++ { 449 datum := RandDatum(rng, colTypes[j], true /* nullOk */) 450 in[i][j] = DatumToEncDatum(colTypes[j], datum) 451 } 452 } 453 var alloc EncDatumRowAlloc 454 out := make(EncDatumRows, rows) 455 for i := 0; i < rows; i++ { 456 out[i] = alloc.CopyRow(in[i]) 457 if len(out[i]) != cols { 458 t.Fatalf("allocated row has invalid length %d (expected %d)", len(out[i]), cols) 459 } 460 } 461 // Do some random appends to make sure the buffers never overlap. 462 for x := 0; x < 10; x++ { 463 i := rng.Intn(rows) 464 j := rng.Intn(rows) 465 out[i] = append(out[i], out[j]...) 466 out[i] = out[i][:cols] 467 } 468 for i := 0; i < rows; i++ { 469 for j := 0; j < cols; j++ { 470 if a, b := in[i][j].Datum, out[i][j].Datum; a.Compare(evalCtx, b) != 0 { 471 t.Errorf("copied datum %s doesn't equal original %s", b, a) 472 } 473 } 474 } 475 } 476 } 477 } 478 479 func TestValueEncodeDecodeTuple(t *testing.T) { 480 rng, seed := randutil.NewPseudoRand() 481 tests := make([]tree.Datum, 1000) 482 colTypes := make([]*types.T, 1000) 483 evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings()) 484 485 for i := range tests { 486 len := rng.Intn(5) 487 contents := make([]*types.T, len) 488 for j := range contents { 489 contents[j] = RandEncodableType(rng) 490 } 491 colTypes[i] = types.MakeTuple(contents) 492 tests[i] = RandDatum(rng, colTypes[i], true) 493 } 494 495 for i, test := range tests { 496 497 switch typedTest := test.(type) { 498 case *tree.DTuple: 499 500 buf, err := EncodeTableValue(nil, ColumnID(encoding.NoColumnID), typedTest, nil) 501 if err != nil { 502 t.Fatalf("seed %d: encoding tuple %v with types %v failed with error: %v", 503 seed, test, colTypes[i], err) 504 } 505 var decodedTuple tree.Datum 506 testTyp := test.ResolvedType() 507 508 decodedTuple, buf, err = DecodeTableValue(&DatumAlloc{}, testTyp, buf) 509 if err != nil { 510 t.Fatalf("seed %d: decoding tuple %v with type (%+v, %+v) failed with error: %v", 511 seed, test, colTypes[i], testTyp, err) 512 } 513 if len(buf) != 0 { 514 t.Fatalf("seed %d: decoding tuple %v with type (%+v, %+v) left %d remaining bytes", 515 seed, test, colTypes[i], testTyp, len(buf)) 516 } 517 518 if cmp := decodedTuple.Compare(evalCtx, test); cmp != 0 { 519 t.Fatalf("seed %d: encoded %+v, decoded %+v, expected equal, received comparison: %d", seed, test, decodedTuple, cmp) 520 } 521 default: 522 if test == tree.DNull { 523 continue 524 } 525 t.Fatalf("seed %d: non-null test case %v is not a tuple", seed, test) 526 } 527 } 528 529 } 530 531 func TestEncDatumSize(t *testing.T) { 532 defer leaktest.AfterTest(t)() 533 534 const ( 535 asc = DatumEncoding_ASCENDING_KEY 536 desc = DatumEncoding_DESCENDING_KEY 537 538 DIntSize = unsafe.Sizeof(tree.DInt(0)) 539 DFloatSize = unsafe.Sizeof(tree.DFloat(0)) 540 DStringSize = unsafe.Sizeof(*tree.NewDString("")) 541 ) 542 543 dec12300 := &tree.DDecimal{Decimal: *apd.New(123, 2)} 544 decimalSize := dec12300.Size() 545 546 testCases := []struct { 547 encDatum EncDatum 548 expectedSize uintptr 549 }{ 550 { 551 encDatum: EncDatumFromEncoded(asc, encoding.EncodeVarintAscending(nil, 0)), 552 expectedSize: EncDatumOverhead + 1, // 1 is encoded with length 1 byte array 553 }, 554 { 555 encDatum: EncDatumFromEncoded(desc, encoding.EncodeVarintDescending(nil, 123)), 556 expectedSize: EncDatumOverhead + 2, // 123 is encoded with length 2 byte array 557 }, 558 { 559 encDatum: EncDatumFromEncoded(asc, encoding.EncodeVarintAscending(nil, 12345)), 560 expectedSize: EncDatumOverhead + 3, // 12345 is encoded with length 3 byte array 561 }, 562 { 563 encDatum: DatumToEncDatum(types.Int, tree.NewDInt(123)), 564 expectedSize: EncDatumOverhead + DIntSize, 565 }, 566 { 567 encDatum: EncDatum{ 568 encoding: asc, 569 encoded: encoding.EncodeVarintAscending(nil, 123), 570 Datum: tree.NewDInt(123), 571 }, 572 expectedSize: EncDatumOverhead + 2 + DIntSize, // 123 is encoded with length 2 byte array 573 }, 574 { 575 encDatum: EncDatumFromEncoded(asc, encoding.EncodeFloatAscending(nil, 0)), 576 expectedSize: EncDatumOverhead + 1, // 0.0 is encoded with length 1 byte array 577 }, 578 { 579 encDatum: EncDatumFromEncoded(desc, encoding.EncodeFloatDescending(nil, 123)), 580 expectedSize: EncDatumOverhead + 9, // 123.0 is encoded with length 9 byte array 581 }, 582 { 583 encDatum: DatumToEncDatum(types.Float, tree.NewDFloat(123)), 584 expectedSize: EncDatumOverhead + DFloatSize, 585 }, 586 { 587 encDatum: EncDatum{ 588 encoding: asc, 589 encoded: encoding.EncodeFloatAscending(nil, 123), 590 Datum: tree.NewDFloat(123), 591 }, 592 expectedSize: EncDatumOverhead + 9 + DFloatSize, // 123.0 is encoded with length 9 byte array 593 }, 594 { 595 encDatum: EncDatumFromEncoded(asc, encoding.EncodeDecimalAscending(nil, apd.New(0, 0))), 596 expectedSize: EncDatumOverhead + 1, // 0.0 is encoded with length 1 byte array 597 }, 598 { 599 encDatum: EncDatumFromEncoded(desc, encoding.EncodeDecimalDescending(nil, apd.New(123, 2))), 600 expectedSize: EncDatumOverhead + 4, // 123.0 is encoded with length 4 byte array 601 }, 602 { 603 encDatum: DatumToEncDatum(types.Decimal, dec12300), 604 expectedSize: EncDatumOverhead + decimalSize, 605 }, 606 { 607 encDatum: EncDatum{ 608 encoding: asc, 609 encoded: encoding.EncodeDecimalAscending(nil, &dec12300.Decimal), 610 Datum: dec12300, 611 }, 612 expectedSize: EncDatumOverhead + 4 + decimalSize, 613 }, 614 { 615 encDatum: EncDatumFromEncoded(asc, encoding.EncodeStringAscending(nil, "")), 616 expectedSize: EncDatumOverhead + 3, // "" is encoded with length 3 byte array 617 }, 618 { 619 encDatum: EncDatumFromEncoded(desc, encoding.EncodeStringDescending(nil, "123⌘")), 620 expectedSize: EncDatumOverhead + 9, // "123⌘" is encoded with length 9 byte array 621 }, 622 { 623 encDatum: DatumToEncDatum(types.String, tree.NewDString("12")), 624 expectedSize: EncDatumOverhead + DStringSize + 2, 625 }, 626 { 627 encDatum: EncDatum{ 628 encoding: asc, 629 encoded: encoding.EncodeStringAscending(nil, "1234"), 630 Datum: tree.NewDString("12345"), 631 }, 632 expectedSize: EncDatumOverhead + 7 + DStringSize + 5, // "1234" is encoded with length 7 byte array 633 }, 634 { 635 encDatum: EncDatumFromEncoded(asc, encoding.EncodeTimeAscending(nil, time.Date(2018, time.June, 26, 11, 50, 0, 0, time.FixedZone("EDT", 0)))), 636 expectedSize: EncDatumOverhead + 7, // This time is encoded with length 7 byte array 637 }, 638 { 639 encDatum: EncDatumFromEncoded(asc, encoding.EncodeTimeAscending(nil, time.Date(2018, time.June, 26, 11, 50, 12, 3456789, time.FixedZone("EDT", 0)))), 640 expectedSize: EncDatumOverhead + 10, // This time is encoded with length 10 byte array 641 }, 642 } 643 644 for _, c := range testCases { 645 receivedSize := c.encDatum.Size() 646 if receivedSize != c.expectedSize { 647 t.Errorf("on %v\treceived %d, expected %d", c.encDatum, receivedSize, c.expectedSize) 648 } 649 } 650 651 testRow := make(EncDatumRow, len(testCases)) 652 expectedTotalSize := EncDatumRowOverhead 653 for idx, c := range testCases { 654 testRow[idx] = c.encDatum 655 expectedTotalSize += c.expectedSize 656 } 657 receivedTotalSize := testRow.Size() 658 if receivedTotalSize != expectedTotalSize { 659 t.Errorf("on %v\treceived %d, expected %d", testRow, receivedTotalSize, expectedTotalSize) 660 } 661 }