github.com/dolthub/go-mysql-server@v0.18.0/sql/stats/join_test.go (about) 1 package stats 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 9 "github.com/dolthub/go-mysql-server/sql" 10 "github.com/dolthub/go-mysql-server/sql/types" 11 ) 12 13 func TestBinMerge(t *testing.T) { 14 tests := []struct { 15 inp []sql.HistogramBucket 16 exp []sql.HistogramBucket 17 }{ 18 { 19 inp: sql.Histogram{ 20 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{2}, BoundCnt: 5}, 21 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{2}, BoundCnt: 5}, 22 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{3}, BoundCnt: 5}, 23 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{4}, BoundCnt: 5}, 24 }, 25 exp: sql.Histogram{ 26 &Bucket{RowCnt: 10, DistinctCnt: 5, BoundVal: sql.Row{2}, BoundCnt: 5}, 27 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{3}, BoundCnt: 5}, 28 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{4}, BoundCnt: 5}, 29 }, 30 }, 31 { 32 inp: sql.Histogram{ 33 &Bucket{RowCnt: 5, DistinctCnt: 10, BoundVal: sql.Row{2}, BoundCnt: 5}, 34 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{3}, BoundCnt: 5}, 35 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{3}, BoundCnt: 5}, 36 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{4}, BoundCnt: 5}, 37 }, 38 exp: sql.Histogram{ 39 &Bucket{RowCnt: 5, DistinctCnt: 10, BoundVal: sql.Row{2}, BoundCnt: 5}, 40 &Bucket{RowCnt: 10, DistinctCnt: 1, BoundVal: sql.Row{3}, BoundCnt: 10}, 41 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{4}, BoundCnt: 5}, 42 }, 43 }, 44 { 45 inp: sql.Histogram{ 46 &Bucket{RowCnt: 5, DistinctCnt: 10, BoundVal: sql.Row{2}, BoundCnt: 5}, 47 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{2}, BoundCnt: 5}, 48 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{4}, BoundCnt: 5}, 49 &Bucket{RowCnt: 5, DistinctCnt: 1, BoundVal: sql.Row{4}, BoundCnt: 5}, 50 }, 51 exp: sql.Histogram{ 52 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{2}, BoundCnt: 10}, 53 &Bucket{RowCnt: 10, DistinctCnt: 5, BoundVal: sql.Row{4}, BoundCnt: 10}, 54 }, 55 }, 56 } 57 for i, tt := range tests { 58 t.Run(fmt.Sprintf("bin merge %d", i), func(t *testing.T) { 59 cmp, err := mergeOverlappingBuckets(tt.inp, []sql.Type{types.Int64}) 60 require.NoError(t, err) 61 compareHist(t, tt.exp, cmp) 62 }) 63 } 64 } 65 66 func TestEuclideanDistance(t *testing.T) { 67 tests := []struct { 68 x, y sql.Row 69 dist float64 70 }{ 71 { 72 x: sql.Row{0, 3}, 73 y: sql.Row{4, 0}, 74 dist: 5, 75 }, 76 { 77 x: sql.Row{5, 0, 0}, 78 y: sql.Row{0, 12, 0}, 79 dist: 13, 80 }, 81 } 82 for _, tt := range tests { 83 t.Run(fmt.Sprintf("%v x %v = %.2f", tt.x, tt.y, tt.dist), func(t *testing.T) { 84 cmp, err := euclideanDistance(tt.x, tt.y, len(tt.x)) 85 require.NoError(t, err) 86 require.Equal(t, tt.dist, cmp) 87 }) 88 } 89 } 90 91 func TestBinAlignment(t *testing.T) { 92 tests := []struct { 93 left []sql.HistogramBucket 94 right []sql.HistogramBucket 95 expLeft []sql.HistogramBucket 96 expRight []sql.HistogramBucket 97 }{ 98 { 99 left: []sql.HistogramBucket{ 100 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 101 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 102 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 103 }, 104 right: []sql.HistogramBucket{ 105 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 106 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 107 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 108 }, 109 expLeft: []sql.HistogramBucket{ 110 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 111 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 112 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{20}, BoundCnt: 1}, 113 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{30}, BoundCnt: 1}, 114 }, 115 expRight: []sql.HistogramBucket{ 116 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 117 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{10}, BoundCnt: 1}, 118 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{20}, BoundCnt: 1}, 119 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 120 }, 121 }, 122 { 123 left: []sql.HistogramBucket{ 124 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 125 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 126 }, 127 right: []sql.HistogramBucket{ 128 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 129 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 130 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 131 }, 132 expLeft: []sql.HistogramBucket{ 133 &Bucket{RowCnt: 12, DistinctCnt: 12, BoundVal: sql.Row{10}, BoundCnt: 1}, 134 &Bucket{RowCnt: 2, DistinctCnt: 2, BoundVal: sql.Row{20}, BoundCnt: 1}, 135 &Bucket{RowCnt: 6, DistinctCnt: 6, BoundVal: sql.Row{50}, BoundCnt: 1}, 136 }, 137 expRight: []sql.HistogramBucket{ 138 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 139 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 140 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 141 }, 142 }, 143 { 144 left: []sql.HistogramBucket{ 145 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 146 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 147 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{40}, BoundCnt: 1}, 148 }, 149 right: []sql.HistogramBucket{ 150 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 151 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 152 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 153 }, 154 expLeft: []sql.HistogramBucket{ 155 &Bucket{RowCnt: 23, DistinctCnt: 23, BoundVal: sql.Row{20}, BoundCnt: 1}, 156 &Bucket{RowCnt: 3, DistinctCnt: 3, BoundVal: sql.Row{30}, BoundCnt: 1}, 157 &Bucket{RowCnt: 3, DistinctCnt: 3, BoundVal: sql.Row{40}, BoundCnt: 1}, 158 }, 159 expRight: []sql.HistogramBucket{ 160 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 161 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 162 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 163 }, 164 }, 165 { 166 left: []sql.HistogramBucket{ 167 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 168 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 169 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{40}, BoundCnt: 1}, 170 }, 171 right: []sql.HistogramBucket{ 172 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 173 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 174 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{60}, BoundCnt: 1}, 175 }, 176 expLeft: []sql.HistogramBucket{ 177 &Bucket{RowCnt: 26, DistinctCnt: 26, BoundVal: sql.Row{30}, BoundCnt: 1}, 178 &Bucket{RowCnt: 3, DistinctCnt: 3, BoundVal: sql.Row{40}, BoundCnt: 1}, 179 }, 180 expRight: []sql.HistogramBucket{ 181 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 182 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 183 }, 184 }, 185 { 186 left: []sql.HistogramBucket{ 187 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 188 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 189 }, 190 right: []sql.HistogramBucket{ 191 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 192 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 193 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{60}, BoundCnt: 1}, 194 }, 195 expLeft: []sql.HistogramBucket{ 196 &Bucket{RowCnt: 20, DistinctCnt: 20, BoundVal: sql.Row{10}, BoundCnt: 1}, 197 }, 198 expRight: []sql.HistogramBucket{ 199 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 200 }, 201 }, 202 { 203 left: []sql.HistogramBucket{ 204 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 205 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 206 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 207 }, 208 right: []sql.HistogramBucket{ 209 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 210 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 211 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{60}, BoundCnt: 1}, 212 }, 213 expLeft: []sql.HistogramBucket{ 214 &Bucket{RowCnt: 30, DistinctCnt: 30, BoundVal: sql.Row{30}, BoundCnt: 1}, 215 }, 216 expRight: []sql.HistogramBucket{ 217 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 218 }, 219 }, 220 { 221 left: []sql.HistogramBucket{ 222 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 223 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 224 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 225 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 226 }, 227 right: []sql.HistogramBucket{ 228 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 229 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 230 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{60}, BoundCnt: 1}, 231 }, 232 expLeft: []sql.HistogramBucket{ 233 &Bucket{RowCnt: 30, DistinctCnt: 30, BoundVal: sql.Row{30}, BoundCnt: 1}, 234 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 235 }, 236 expRight: []sql.HistogramBucket{ 237 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 238 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 239 }, 240 }, 241 { 242 left: []sql.HistogramBucket{ 243 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 244 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 245 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 246 }, 247 right: []sql.HistogramBucket{ 248 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 249 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 250 }, 251 expLeft: []sql.HistogramBucket{ 252 &Bucket{RowCnt: 30, DistinctCnt: 30, BoundVal: sql.Row{20}, BoundCnt: 1}, 253 }, 254 expRight: []sql.HistogramBucket{ 255 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 256 }, 257 }, 258 { 259 left: []sql.HistogramBucket{ 260 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 261 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 262 }, 263 right: []sql.HistogramBucket{ 264 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 265 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 266 }, 267 expLeft: []sql.HistogramBucket{ 268 &Bucket{RowCnt: 20, DistinctCnt: 20, BoundVal: sql.Row{10}, BoundCnt: 1}, 269 }, 270 expRight: []sql.HistogramBucket{ 271 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 272 }, 273 }, 274 } 275 276 cmp := func(i, j sql.Row) (int, error) { 277 return types.Int64.Compare(i[0], j[0]) 278 } 279 280 for i, tt := range tests { 281 t.Run(fmt.Sprintf("alignment test %d", i), func(t *testing.T) { 282 lCmp, rCmp, err := AlignBuckets(tt.left, tt.right, nil, nil, []sql.Type{types.Int64}, []sql.Type{types.Int64}, cmp) 283 require.NoError(t, err) 284 compareHist(t, tt.expLeft, lCmp) 285 compareHist(t, tt.expRight, rCmp) 286 }) 287 } 288 } 289 290 func TestJoin(t *testing.T) { 291 tests := []struct { 292 left sql.Histogram 293 right sql.Histogram 294 exp sql.Histogram 295 }{ 296 { 297 left: []sql.HistogramBucket{ 298 &Bucket{RowCnt: 20, DistinctCnt: 20, BoundVal: sql.Row{10}, BoundCnt: 1}, 299 }, 300 right: []sql.HistogramBucket{ 301 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 302 }, 303 exp: []sql.HistogramBucket{ 304 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 305 }, 306 }, 307 { 308 left: []sql.HistogramBucket{ 309 &Bucket{RowCnt: 20, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 310 }, 311 right: []sql.HistogramBucket{ 312 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 313 }, 314 exp: []sql.HistogramBucket{ 315 &Bucket{RowCnt: 20, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 316 }, 317 }, 318 { 319 left: []sql.HistogramBucket{ 320 &Bucket{RowCnt: 20, DistinctCnt: 11, BoundVal: sql.Row{10}, McvVals: []sql.Row{{1}, {2}}, McvsCnt: []uint64{5, 5}, BoundCnt: 1}, 321 }, 322 right: []sql.HistogramBucket{ 323 &Bucket{RowCnt: 10, DistinctCnt: 6, BoundVal: sql.Row{10}, McvVals: []sql.Row{{2}}, McvsCnt: []uint64{4}, BoundCnt: 1}, 324 }, 325 exp: []sql.HistogramBucket{ 326 &Bucket{RowCnt: 29, DistinctCnt: 6, BoundVal: sql.Row{10}, BoundCnt: 1}, 327 }, 328 }, 329 { 330 left: []sql.HistogramBucket{ 331 &Bucket{RowCnt: 20, DistinctCnt: 10, BoundVal: sql.Row{10}, McvVals: []sql.Row{{1}, {2}}, McvsCnt: []uint64{5, 5}, BoundCnt: 1}, 332 }, 333 right: []sql.HistogramBucket{ 334 &Bucket{RowCnt: 10, DistinctCnt: 6, BoundVal: sql.Row{10}, McvVals: []sql.Row{{3}}, McvsCnt: []uint64{4}, BoundCnt: 1}, 335 }, 336 exp: []sql.HistogramBucket{ 337 &Bucket{RowCnt: 20, DistinctCnt: 6, BoundVal: sql.Row{10}, BoundCnt: 1}, 338 }, 339 }, 340 { 341 left: []sql.HistogramBucket{ 342 &Bucket{RowCnt: 20, DistinctCnt: 10, BoundVal: sql.Row{10}, McvVals: []sql.Row{{1}, {2}}, McvsCnt: []uint64{5, 5}, BoundCnt: 1}, 343 }, 344 right: []sql.HistogramBucket{ 345 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, McvVals: []sql.Row{{3}}, McvsCnt: []uint64{4}, BoundCnt: 1}, 346 }, 347 exp: []sql.HistogramBucket{ 348 &Bucket{RowCnt: 20, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 349 }, 350 }, 351 { 352 left: []sql.HistogramBucket{ 353 &Bucket{RowCnt: 23, DistinctCnt: 23, BoundVal: sql.Row{20}, BoundCnt: 1}, 354 &Bucket{RowCnt: 3, DistinctCnt: 3, BoundVal: sql.Row{30}, BoundCnt: 1}, 355 &Bucket{RowCnt: 3, DistinctCnt: 3, BoundVal: sql.Row{40}, BoundCnt: 1}, 356 }, 357 right: []sql.HistogramBucket{ 358 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 359 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 360 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{50}, BoundCnt: 1}, 361 }, 362 exp: []sql.HistogramBucket{ 363 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 364 &Bucket{RowCnt: 3, DistinctCnt: 3, BoundVal: sql.Row{30}, BoundCnt: 1}, 365 &Bucket{RowCnt: 3, DistinctCnt: 3, BoundVal: sql.Row{40}, BoundCnt: 1}, 366 }, 367 }, 368 { 369 left: []sql.HistogramBucket{ 370 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 371 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 372 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{20}, BoundCnt: 1}, 373 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{30}, BoundCnt: 1}, 374 }, 375 right: []sql.HistogramBucket{ 376 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 377 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{10}, BoundCnt: 1}, 378 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{20}, BoundCnt: 1}, 379 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 380 }, 381 exp: []sql.HistogramBucket{ 382 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{0}, BoundCnt: 1}, 383 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{10}, BoundCnt: 1}, 384 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{20}, BoundCnt: 1}, 385 &Bucket{RowCnt: 5, DistinctCnt: 5, BoundVal: sql.Row{30}, BoundCnt: 1}, 386 }, 387 }, 388 { 389 left: []sql.HistogramBucket{ 390 &Bucket{RowCnt: 12, DistinctCnt: 12, BoundVal: sql.Row{10}, BoundCnt: 1}, 391 &Bucket{RowCnt: 6, DistinctCnt: 6, BoundVal: sql.Row{20}, BoundCnt: 1}, 392 &Bucket{RowCnt: 1, DistinctCnt: 1, BoundVal: sql.Row{50}, BoundCnt: 1}, 393 }, 394 right: []sql.HistogramBucket{ 395 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 396 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{20}, BoundCnt: 1}, 397 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{30}, BoundCnt: 1}, 398 }, 399 exp: []sql.HistogramBucket{ 400 &Bucket{RowCnt: 10, DistinctCnt: 10, BoundVal: sql.Row{10}, BoundCnt: 1}, 401 &Bucket{RowCnt: 6, DistinctCnt: 6, BoundVal: sql.Row{20}, BoundCnt: 1}, 402 &Bucket{RowCnt: 1, DistinctCnt: 1, BoundVal: sql.Row{50}, BoundCnt: 1}, 403 }, 404 }, 405 { 406 left: []sql.HistogramBucket{ 407 &Bucket{RowCnt: 10, DistinctCnt: 3, BoundVal: sql.Row{0}, BoundCnt: 1}, 408 &Bucket{RowCnt: 10, DistinctCnt: 3, BoundVal: sql.Row{10}, BoundCnt: 1}, 409 &Bucket{RowCnt: 5, DistinctCnt: 2, BoundVal: sql.Row{20}, BoundCnt: 1}, 410 &Bucket{RowCnt: 5, DistinctCnt: 2, BoundVal: sql.Row{30}, BoundCnt: 1}, 411 }, 412 right: []sql.HistogramBucket{ 413 &Bucket{RowCnt: 10, DistinctCnt: 3, BoundVal: sql.Row{0}, BoundCnt: 1}, 414 &Bucket{RowCnt: 5, DistinctCnt: 2, BoundVal: sql.Row{10}, BoundCnt: 1}, 415 &Bucket{RowCnt: 5, DistinctCnt: 2, BoundVal: sql.Row{20}, BoundCnt: 1}, 416 &Bucket{RowCnt: 10, DistinctCnt: 3, BoundVal: sql.Row{30}, BoundCnt: 1}, 417 }, 418 exp: []sql.HistogramBucket{ 419 &Bucket{RowCnt: 33, DistinctCnt: 3, BoundVal: sql.Row{0}, BoundCnt: 1}, 420 &Bucket{RowCnt: 16, DistinctCnt: 2, BoundVal: sql.Row{10}, BoundCnt: 1}, 421 &Bucket{RowCnt: 12, DistinctCnt: 2, BoundVal: sql.Row{20}, BoundCnt: 1}, 422 &Bucket{RowCnt: 16, DistinctCnt: 2, BoundVal: sql.Row{30}, BoundCnt: 1}, 423 }, 424 }, 425 } 426 427 cmp := func(i, j sql.Row) (int, error) { 428 return types.Int64.Compare(i[0], j[0]) 429 } 430 431 for i, tt := range tests { 432 t.Run(fmt.Sprintf("join test %d", i), func(t *testing.T) { 433 cmp, err := joinAlignedStats(tt.left, tt.right, cmp) 434 require.NoError(t, err) 435 cmpHist := make(sql.Histogram, len(cmp)) 436 for i, v := range cmp { 437 cmpHist[i] = v 438 } 439 compareHist(t, tt.exp, cmpHist) 440 }) 441 } 442 } 443 444 func compareHist(t *testing.T, exp, cmp sql.Histogram) { 445 if len(exp) != len(cmp) { 446 t.Errorf("histograms not same length: %d != %d\n%s\n%s\n", len(exp), len(cmp), exp.DebugString(), cmp.DebugString()) 447 } 448 for i, b := range exp { 449 require.Equalf(t, b.UpperBound(), cmp[i].UpperBound(), "bound not equal: %v != %v\n%s\n%s", b.UpperBound(), cmp[i].UpperBound(), exp.DebugString(), cmp.DebugString()) 450 if b.RowCount() != cmp[i].RowCount() { 451 t.Errorf("histograms row count not equal: %d != %d\n%s\n%s", b.RowCount(), cmp[i].RowCount(), exp.DebugString(), cmp.DebugString()) 452 } 453 if b.DistinctCount() != cmp[i].DistinctCount() { 454 t.Errorf("histograms distinct not equal: %d != %d\n%s\n%s", b.DistinctCount(), cmp[i].DistinctCount(), exp.DebugString(), cmp.DebugString()) 455 } 456 if b.NullCount() != cmp[i].NullCount() { 457 t.Errorf("histograms null not equal: %d != %d\n%s\n%s", b.NullCount(), cmp[i].NullCount(), exp.DebugString(), cmp.DebugString()) 458 } 459 } 460 }