github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colexec/hashjoiner_tmpl.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 // {{/* 12 // +build execgen_template 13 // 14 // This file is the execgen template for hashjoiner.eg.go. It's formatted in a 15 // special way, so it's both valid Go and a valid text/template input. This 16 // permits editing this file with editor support. 17 // 18 // */}} 19 20 package colexec 21 22 import ( 23 "github.com/cockroachdb/cockroach/pkg/col/coldata" 24 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 25 ) 26 27 // {{/* 28 29 func _COLLECT_PROBE_OUTER( 30 hj *hashJoiner, batchSize int, nResults int, batch coldata.Batch, _USE_SEL bool, 31 ) int { // */}} 32 // {{define "collectProbeOuter" -}} 33 // Early bounds checks. 34 _ = hj.ht.probeScratch.headID[batchSize-1] 35 // {{if .UseSel}} 36 _ = sel[batchSize-1] 37 // {{end}} 38 for i := hj.probeState.prevBatchResumeIdx; i < batchSize; i++ { 39 currentID := hj.ht.probeScratch.headID[i] 40 41 for { 42 if nResults >= hj.outputBatchSize { 43 hj.probeState.prevBatch = batch 44 hj.probeState.prevBatchResumeIdx = i 45 return nResults 46 } 47 48 hj.probeState.probeRowUnmatched[nResults] = currentID == 0 49 if currentID > 0 { 50 hj.probeState.buildIdx[nResults] = int(currentID - 1) 51 } else { 52 // If currentID == 0, then probeRowUnmatched will have been set - and 53 // we set the corresponding buildIdx to zero so that (as long as the 54 // build hash table has at least one row) we can copy the values vector 55 // without paying attention to probeRowUnmatched. 56 hj.probeState.buildIdx[nResults] = 0 57 } 58 // {{if .UseSel}} 59 hj.probeState.probeIdx[nResults] = sel[i] 60 // {{else}} 61 hj.probeState.probeIdx[nResults] = i 62 // {{end}} 63 currentID = hj.ht.same[currentID] 64 hj.ht.probeScratch.headID[i] = currentID 65 nResults++ 66 67 if currentID == 0 { 68 break 69 } 70 } 71 } 72 // {{end}} 73 // {{/* 74 // Dummy return value that is never used. 75 return 0 76 } 77 78 func _COLLECT_PROBE_NO_OUTER( 79 hj *hashJoiner, batchSize int, nResults int, batch coldata.Batch, _USE_SEL bool, 80 ) int { // */}} 81 // {{define "collectProbeNoOuter" -}} 82 // Early bounds checks. 83 _ = hj.ht.probeScratch.headID[batchSize-1] 84 // {{if .UseSel}} 85 _ = sel[batchSize-1] 86 // {{end}} 87 for i := hj.probeState.prevBatchResumeIdx; i < batchSize; i++ { 88 currentID := hj.ht.probeScratch.headID[i] 89 for currentID != 0 { 90 if nResults >= hj.outputBatchSize { 91 hj.probeState.prevBatch = batch 92 hj.probeState.prevBatchResumeIdx = i 93 return nResults 94 } 95 96 hj.probeState.buildIdx[nResults] = int(currentID - 1) 97 // {{if .UseSel}} 98 hj.probeState.probeIdx[nResults] = sel[i] 99 // {{else}} 100 hj.probeState.probeIdx[nResults] = i 101 // {{end}} 102 currentID = hj.ht.same[currentID] 103 hj.ht.probeScratch.headID[i] = currentID 104 nResults++ 105 } 106 } 107 // {{end}} 108 // {{/* 109 // Dummy return value that is never used. 110 return 0 111 } 112 113 // This code snippet collects the "matches" for LEFT ANTI and EXCEPT ALL joins. 114 // "Matches" are in quotes because we're actually interested in non-matches 115 // from the left side. 116 func _COLLECT_ANTI( 117 hj *hashJoiner, batchSize int, nResults int, batch coldata.Batch, _USE_SEL bool, 118 ) int { // */}} 119 // {{define "collectAnti" -}} 120 // Early bounds checks. 121 _ = hj.ht.probeScratch.headID[batchSize-1] 122 // {{if .UseSel}} 123 _ = sel[batchSize-1] 124 // {{end}} 125 for i := int(0); i < batchSize; i++ { 126 currentID := hj.ht.probeScratch.headID[i] 127 if currentID == 0 { 128 // currentID of 0 indicates that ith probing row didn't have a match, so 129 // we include it into the output. 130 // {{if .UseSel}} 131 hj.probeState.probeIdx[nResults] = sel[i] 132 // {{else}} 133 hj.probeState.probeIdx[nResults] = i 134 // {{end}} 135 nResults++ 136 } 137 } 138 // {{end}} 139 // {{/* 140 // Dummy return value that is never used. 141 return 0 142 } 143 144 func _DISTINCT_COLLECT_PROBE_OUTER(hj *hashJoiner, batchSize int, _USE_SEL bool) { // */}} 145 // {{define "distinctCollectProbeOuter" -}} 146 // Early bounds checks. 147 _ = hj.ht.probeScratch.groupID[batchSize-1] 148 _ = hj.probeState.probeRowUnmatched[batchSize-1] 149 _ = hj.probeState.buildIdx[batchSize-1] 150 _ = hj.probeState.probeIdx[batchSize-1] 151 // {{if .UseSel}} 152 _ = sel[batchSize-1] 153 // {{end}} 154 for i := int(0); i < batchSize; i++ { 155 // Index of keys and outputs in the hash table is calculated as ID - 1. 156 id := hj.ht.probeScratch.groupID[i] 157 rowUnmatched := id == 0 158 hj.probeState.probeRowUnmatched[i] = rowUnmatched 159 if !rowUnmatched { 160 hj.probeState.buildIdx[i] = int(id - 1) 161 } 162 // {{if .UseSel}} 163 hj.probeState.probeIdx[i] = sel[i] 164 // {{else}} 165 hj.probeState.probeIdx[i] = i 166 // {{end}} 167 } 168 // {{end}} 169 // {{/* 170 } 171 172 func _DISTINCT_COLLECT_PROBE_NO_OUTER(hj *hashJoiner, batchSize int, nResults int, _USE_SEL bool) { // */}} 173 // {{define "distinctCollectProbeNoOuter" -}} 174 // Early bounds checks. 175 _ = hj.ht.probeScratch.groupID[batchSize-1] 176 _ = hj.probeState.buildIdx[batchSize-1] 177 _ = hj.probeState.probeIdx[batchSize-1] 178 // {{if .UseSel}} 179 _ = sel[batchSize-1] 180 // {{end}} 181 for i := int(0); i < batchSize; i++ { 182 if hj.ht.probeScratch.groupID[i] != 0 { 183 // Index of keys and outputs in the hash table is calculated as ID - 1. 184 hj.probeState.buildIdx[nResults] = int(hj.ht.probeScratch.groupID[i] - 1) 185 // {{if .UseSel}} 186 hj.probeState.probeIdx[nResults] = sel[i] 187 // {{else}} 188 hj.probeState.probeIdx[nResults] = i 189 // {{end}} 190 nResults++ 191 } 192 } 193 // {{end}} 194 // {{/* 195 } 196 197 // */}} 198 199 // collect prepares the buildIdx and probeIdx arrays where the buildIdx and 200 // probeIdx at each index are joined to make an output row. The total number of 201 // resulting rows is returned. 202 func (hj *hashJoiner) collect(batch coldata.Batch, batchSize int, sel []int) int { 203 nResults := int(0) 204 205 if hj.spec.left.outer { 206 if sel != nil { 207 _COLLECT_PROBE_OUTER(hj, batchSize, nResults, batch, true) 208 } else { 209 _COLLECT_PROBE_OUTER(hj, batchSize, nResults, batch, false) 210 } 211 } else { 212 if sel != nil { 213 switch hj.spec.joinType { 214 case sqlbase.LeftAntiJoin, sqlbase.ExceptAllJoin: 215 _COLLECT_ANTI(hj, batchSize, nResults, batch, true) 216 default: 217 _COLLECT_PROBE_NO_OUTER(hj, batchSize, nResults, batch, true) 218 } 219 } else { 220 switch hj.spec.joinType { 221 case sqlbase.LeftAntiJoin, sqlbase.ExceptAllJoin: 222 _COLLECT_ANTI(hj, batchSize, nResults, batch, false) 223 default: 224 _COLLECT_PROBE_NO_OUTER(hj, batchSize, nResults, batch, false) 225 } 226 } 227 } 228 229 return nResults 230 } 231 232 // distinctCollect prepares the batch with the joined output columns where the build 233 // row index for each probe row is given in the groupID slice. This function 234 // requires assumes a N-1 hash join. 235 func (hj *hashJoiner) distinctCollect(batch coldata.Batch, batchSize int, sel []int) int { 236 nResults := int(0) 237 238 if hj.spec.left.outer { 239 nResults = batchSize 240 241 if sel != nil { 242 _DISTINCT_COLLECT_PROBE_OUTER(hj, batchSize, true) 243 } else { 244 _DISTINCT_COLLECT_PROBE_OUTER(hj, batchSize, false) 245 } 246 } else { 247 if sel != nil { 248 switch hj.spec.joinType { 249 case sqlbase.LeftAntiJoin, sqlbase.ExceptAllJoin: 250 // {{/* For LEFT ANTI and EXCEPT ALL joins we don't care whether the build 251 // (right) side was distinct, so we only have single variation of COLLECT 252 // method. */}} 253 _COLLECT_ANTI(hj, batchSize, nResults, batch, true) 254 default: 255 _DISTINCT_COLLECT_PROBE_NO_OUTER(hj, batchSize, nResults, true) 256 } 257 } else { 258 switch hj.spec.joinType { 259 case sqlbase.LeftAntiJoin, sqlbase.ExceptAllJoin: 260 // {{/* For LEFT ANTI and EXCEPT ALL joins we don't care whether the build 261 // (right) side was distinct, so we only have single variation of COLLECT 262 // method. */}} 263 _COLLECT_ANTI(hj, batchSize, nResults, batch, false) 264 default: 265 _DISTINCT_COLLECT_PROBE_NO_OUTER(hj, batchSize, nResults, false) 266 } 267 } 268 } 269 270 return nResults 271 }