github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/props/col_stats_map_test.go (about) 1 // Copyright 2018 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 props_test 12 13 import ( 14 "fmt" 15 "strings" 16 "testing" 17 18 "github.com/cockroachdb/cockroach/pkg/sql/opt" 19 "github.com/cockroachdb/cockroach/pkg/sql/opt/props" 20 ) 21 22 func TestColStatsMap(t *testing.T) { 23 testcases := []struct { 24 cols []opt.ColumnID 25 remove bool 26 clear bool 27 expected string 28 }{ 29 {cols: []opt.ColumnID{1}, expected: "(1)"}, 30 {cols: []opt.ColumnID{1}, expected: "(1)"}, 31 {cols: []opt.ColumnID{2}, expected: "(1)+(2)"}, 32 {cols: []opt.ColumnID{1, 2}, expected: "(1)+(2)+(1,2)"}, 33 {cols: []opt.ColumnID{1, 2}, expected: "(1)+(2)+(1,2)"}, 34 {cols: []opt.ColumnID{2}, expected: "(1)+(2)+(1,2)"}, 35 {cols: []opt.ColumnID{1}, remove: true, expected: "(2)"}, 36 37 // Add after removing. 38 {cols: []opt.ColumnID{2, 3}, expected: "(2)+(2,3)"}, 39 {cols: []opt.ColumnID{2, 3, 4}, expected: "(2)+(2,3)+(2-4)"}, 40 {cols: []opt.ColumnID{3}, expected: "(2)+(2,3)+(2-4)+(3)"}, 41 {cols: []opt.ColumnID{3, 4}, expected: "(2)+(2,3)+(2-4)+(3)+(3,4)"}, 42 {cols: []opt.ColumnID{5, 7}, expected: "(2)+(2,3)+(2-4)+(3)+(3,4)+(5,7)"}, 43 {cols: []opt.ColumnID{5}, expected: "(2)+(2,3)+(2-4)+(3)+(3,4)+(5,7)+(5)"}, 44 {cols: []opt.ColumnID{3, 4}, remove: true, expected: "(2)+(5,7)+(5)"}, 45 46 // Add after clearing. 47 {cols: []opt.ColumnID{}, clear: true, expected: ""}, 48 {cols: []opt.ColumnID{5}, expected: "(5)"}, 49 {cols: []opt.ColumnID{1}, expected: "(5)+(1)"}, 50 {cols: []opt.ColumnID{1, 5}, expected: "(5)+(1)+(1,5)"}, 51 {cols: []opt.ColumnID{5, 6}, expected: "(5)+(1)+(1,5)+(5,6)"}, 52 {cols: []opt.ColumnID{2}, expected: "(5)+(1)+(1,5)+(5,6)+(2)"}, 53 {cols: []opt.ColumnID{1, 2}, expected: "(5)+(1)+(1,5)+(5,6)+(2)+(1,2)"}, 54 55 // Remove node, where remaining nodes still require prefix tree index. 56 {cols: []opt.ColumnID{6}, remove: true, expected: "(5)+(1)+(1,5)+(2)+(1,2)"}, 57 {cols: []opt.ColumnID{3, 4}, expected: "(5)+(1)+(1,5)+(2)+(1,2)+(3,4)"}, 58 } 59 60 tcStats := make([]props.ColStatsMap, len(testcases)) 61 // First calculate the stats for all steps, making copies every time. This 62 // also tests that the stats are copied correctly and there is no aliasing. 63 for tcIdx, tc := range testcases { 64 stats := &tcStats[tcIdx] 65 if tcIdx > 0 { 66 stats.CopyFrom(&tcStats[tcIdx-1]) 67 } 68 cols := opt.MakeColSet(tc.cols...) 69 if !tc.remove { 70 if tc.clear { 71 stats.Clear() 72 } else { 73 stats.Add(cols) 74 } 75 } else { 76 stats.RemoveIntersecting(cols) 77 } 78 } 79 80 for tcIdx, tc := range testcases { 81 stats := &tcStats[tcIdx] 82 var b strings.Builder 83 for i := 0; i < stats.Count(); i++ { 84 get := stats.Get(i) 85 if i != 0 { 86 b.WriteRune('+') 87 } 88 fmt.Fprint(&b, get.Cols) 89 90 lookup, ok := stats.Lookup(get.Cols) 91 if !ok { 92 t.Errorf("could not find cols in map: %s", get.Cols) 93 } 94 if get != lookup { 95 t.Errorf("lookup did not return expected colstat: %+v vs. %+v", get, lookup) 96 } 97 } 98 99 if b.String() != tc.expected { 100 t.Errorf("expected: %s, actual: %s", tc.expected, b.String()) 101 } 102 } 103 }