github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/col/coldata/nulls_test.go (about) 1 // Copyright 2019 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 coldata 12 13 import ( 14 "fmt" 15 "testing" 16 17 "github.com/cockroachdb/cockroach/pkg/sql/types" 18 "github.com/stretchr/testify/require" 19 ) 20 21 // nulls3 is a nulls vector with every third value set to null. 22 var nulls3 Nulls 23 24 // nulls5 is a nulls vector with every fifth value set to null. 25 var nulls5 Nulls 26 27 // nulls10 is a double-length nulls vector with every tenth value set to null. 28 var nulls10 Nulls 29 30 // pos is a collection of interesting boundary indices to use in tests. 31 var pos = []int{0, 1, 63, 64, 65, BatchSize() - 1, BatchSize()} 32 33 func init() { 34 nulls3 = NewNulls(BatchSize()) 35 nulls5 = NewNulls(BatchSize()) 36 nulls10 = NewNulls(BatchSize() * 2) 37 for i := 0; i < BatchSize(); i++ { 38 if i%3 == 0 { 39 nulls3.SetNull(i) 40 } 41 if i%5 == 0 { 42 nulls5.SetNull(i) 43 } 44 } 45 for i := 0; i < BatchSize()*2; i++ { 46 if i%10 == 0 { 47 nulls10.SetNull(i) 48 } 49 } 50 } 51 52 func TestNullAt(t *testing.T) { 53 for i := 0; i < BatchSize(); i++ { 54 if i%3 == 0 { 55 require.True(t, nulls3.NullAt(i)) 56 } else { 57 require.False(t, nulls3.NullAt(i)) 58 } 59 } 60 } 61 62 func TestSetNullRange(t *testing.T) { 63 for _, start := range pos { 64 for _, end := range pos { 65 n := NewNulls(BatchSize()) 66 n.SetNullRange(start, end) 67 for i := 0; i < BatchSize(); i++ { 68 expected := i >= start && i < end 69 require.Equal(t, expected, n.NullAt(i), 70 "NullAt(%d) should be %t after SetNullRange(%d, %d)", i, expected, start, end) 71 } 72 } 73 } 74 } 75 76 func TestUnsetNullRange(t *testing.T) { 77 for _, start := range pos { 78 for _, end := range pos { 79 n := NewNulls(BatchSize()) 80 n.SetNulls() 81 n.UnsetNullRange(start, end) 82 for i := 0; i < BatchSize(); i++ { 83 notExpected := i >= start && i < end 84 require.NotEqual(t, notExpected, n.NullAt(i), 85 "NullAt(%d) saw %t, expected %t, after SetNullRange(%d, %d)", i, n.NullAt(i), !notExpected, start, end) 86 } 87 } 88 } 89 } 90 91 func TestSwapNulls(t *testing.T) { 92 n := NewNulls(BatchSize()) 93 swapPos := []int{0, 1, 63, 64, 65, BatchSize() - 1} 94 idxInSwapPos := func(idx int) bool { 95 for _, p := range swapPos { 96 if p == idx { 97 return true 98 } 99 } 100 return false 101 } 102 103 t.Run("TestSwapNullWithNull", func(t *testing.T) { 104 // Test that swapping null with null doesn't change anything. 105 for _, p := range swapPos { 106 n.SetNull(p) 107 } 108 for _, i := range swapPos { 109 for _, j := range swapPos { 110 n.swap(i, j) 111 for k := 0; k < BatchSize(); k++ { 112 require.Equal(t, idxInSwapPos(k), n.NullAt(k), 113 "after swapping NULLS (%d, %d), NullAt(%d) saw %t, expected %t", i, j, k, n.NullAt(k), idxInSwapPos(k)) 114 } 115 } 116 } 117 }) 118 119 t.Run("TestSwapNullWithNotNull", func(t *testing.T) { 120 // Test that swapping null with not null changes things appropriately. 121 n.UnsetNulls() 122 swaps := map[int]int{ 123 0: BatchSize() - 1, 124 1: 62, 125 2: 3, 126 63: 65, 127 68: 120, 128 } 129 idxInSwaps := func(idx int) bool { 130 for k, v := range swaps { 131 if idx == k || idx == v { 132 return true 133 } 134 } 135 return false 136 } 137 for _, j := range swaps { 138 n.SetNull(j) 139 } 140 for i, j := range swaps { 141 n.swap(i, j) 142 require.Truef(t, n.NullAt(i), "after swapping not null and null (%d, %d), found null=%t at %d", i, j, n.NullAt(i), i) 143 require.Truef(t, !n.NullAt(j), "after swapping not null and null (%d, %d), found null=%t at %d", i, j, !n.NullAt(j), j) 144 for k := 0; k < BatchSize(); k++ { 145 if idxInSwaps(k) { 146 continue 147 } 148 require.Falsef(t, n.NullAt(k), 149 "after swapping NULLS (%d, %d), NullAt(%d) saw %t, expected false", i, j, k, n.NullAt(k)) 150 } 151 } 152 }) 153 154 t.Run("TestSwapNullWithNull", func(t *testing.T) { 155 // Test that swapping not null with not null doesn't do anything. 156 n.SetNulls() 157 for _, p := range swapPos { 158 n.UnsetNull(p) 159 } 160 for _, i := range swapPos { 161 for _, j := range swapPos { 162 n.swap(i, j) 163 for k := 0; k < BatchSize(); k++ { 164 require.Equal(t, idxInSwapPos(k), !n.NullAt(k), 165 "after swapping NULLS (%d, %d), NullAt(%d) saw %t, expected %t", i, j, k, !n.NullAt(k), idxInSwapPos(k)) 166 } 167 } 168 } 169 }) 170 } 171 172 func TestNullsTruncate(t *testing.T) { 173 for _, size := range pos { 174 n := NewNulls(BatchSize()) 175 n.Truncate(size) 176 for i := 0; i < BatchSize(); i++ { 177 expected := i >= size 178 require.Equal(t, expected, n.NullAt(i), 179 "NullAt(%d) should be %t after Truncate(%d)", i, expected, size) 180 } 181 } 182 } 183 184 func TestUnsetNullsAfter(t *testing.T) { 185 for _, size := range pos { 186 n := NewNulls(BatchSize()) 187 n.SetNulls() 188 n.UnsetNullsAfter(size) 189 for i := 0; i < BatchSize(); i++ { 190 expected := i < size 191 require.Equal(t, expected, n.NullAt(i), 192 "NullAt(%d) should be %t after UnsetNullsAfter(%d)", i, expected, size) 193 } 194 } 195 } 196 197 func TestSetAndUnsetNulls(t *testing.T) { 198 n := NewNulls(BatchSize()) 199 for i := 0; i < BatchSize(); i++ { 200 require.False(t, n.NullAt(i)) 201 } 202 n.SetNulls() 203 for i := 0; i < BatchSize(); i++ { 204 require.True(t, n.NullAt(i)) 205 } 206 207 for i := 0; i < BatchSize(); i += 3 { 208 n.UnsetNull(i) 209 } 210 for i := 0; i < BatchSize(); i++ { 211 if i%3 == 0 { 212 require.False(t, n.NullAt(i)) 213 } else { 214 require.True(t, n.NullAt(i)) 215 } 216 } 217 218 n.UnsetNulls() 219 for i := 0; i < BatchSize(); i++ { 220 require.False(t, n.NullAt(i)) 221 } 222 } 223 224 func TestNullsSet(t *testing.T) { 225 args := SliceArgs{ 226 // Neither type nor the length here matter. 227 Src: NewMemColumn(types.Bool, 0, StandardColumnFactory), 228 } 229 for _, withSel := range []bool{false, true} { 230 t.Run(fmt.Sprintf("WithSel=%t", withSel), func(t *testing.T) { 231 var srcNulls *Nulls 232 if withSel { 233 args.Sel = make([]int, BatchSize()) 234 // Make a selection vector with every even index. (This turns nulls10 into 235 // nulls5.) 236 for i := range args.Sel { 237 args.Sel[i] = i * 2 238 } 239 srcNulls = &nulls10 240 } else { 241 args.Sel = nil 242 srcNulls = &nulls5 243 } 244 for _, destStartIdx := range pos { 245 for _, srcStartIdx := range pos { 246 for _, srcEndIdx := range pos { 247 if destStartIdx <= srcStartIdx && srcStartIdx <= srcEndIdx { 248 toAppend := srcEndIdx - srcStartIdx 249 name := fmt.Sprintf("destStartIdx=%d,srcStartIdx=%d,toAppend=%d", destStartIdx, 250 srcStartIdx, toAppend) 251 t.Run(name, func(t *testing.T) { 252 n := nulls3.Copy() 253 args.Src.SetNulls(srcNulls) 254 args.DestIdx = destStartIdx 255 args.SrcStartIdx = srcStartIdx 256 args.SrcEndIdx = srcEndIdx 257 // Set some garbage values in the destination nulls that should 258 // be overwritten. 259 n.SetNullRange(destStartIdx, destStartIdx+toAppend) 260 n.set(args) 261 for i := 0; i < destStartIdx; i++ { 262 require.Equal(t, nulls3.NullAt(i), n.NullAt(i)) 263 } 264 for i := 0; i < toAppend; i++ { 265 require.Equal(t, nulls5.NullAt(srcStartIdx+i), n.NullAt(destStartIdx+i)) 266 } 267 for i := destStartIdx + toAppend; i < BatchSize(); i++ { 268 require.Equal(t, nulls3.NullAt(i), n.NullAt(i)) 269 } 270 }) 271 } 272 } 273 } 274 } 275 }) 276 } 277 } 278 279 func TestSlice(t *testing.T) { 280 for _, start := range pos { 281 for _, end := range pos { 282 n := nulls3.Slice(start, end) 283 for i := 0; i < 8*len(n.nulls); i++ { 284 expected := start+i < end && nulls3.NullAt(start+i) 285 require.Equal(t, expected, n.NullAt(i), 286 "expected nulls3.Slice(%d, %d).NullAt(%d) to be %b", start, end, i, expected) 287 } 288 } 289 } 290 // Ensure we haven't modified the receiver. 291 for i := 0; i < BatchSize(); i++ { 292 expected := i%3 == 0 293 require.Equal(t, expected, nulls3.NullAt(i)) 294 } 295 } 296 297 func TestNullsOr(t *testing.T) { 298 length1, length2 := 300, 400 299 n1 := nulls3.Slice(0, length1) 300 n2 := nulls5.Slice(0, length2) 301 or := n1.Or(&n2) 302 require.True(t, or.maybeHasNulls) 303 for i := 0; i < length2; i++ { 304 if i < length1 && n1.NullAt(i) || i < length2 && n2.NullAt(i) { 305 require.True(t, or.NullAt(i), "or.NullAt(%d) should be true", i) 306 } else { 307 require.False(t, or.NullAt(i), "or.NullAt(%d) should be false", i) 308 } 309 } 310 }