Tinysql Proj5 part2 Hash Join Implementation

Hi, I’m trying to finish the Proj5 part2 tinysql. I followed instructions step by step but always fail in some test.

Here is my first function fetchAndBuildHashTable:

func (e *HashJoinExec) fetchAndBuildHashTable(ctx context.Context) error {
	// TODO: Implementing the building hash table stage.

	// In this stage, you'll read the data from the inner side executor of the join operator and
	// then use its data to build hash table.

	// You'll need to store the hash table in `e.rowContainer`
	// and you can call `newHashRowContainer` in `executor/hash_table.go` to build it.
	// In this stage you can only assign value for `e.rowContainer` without changing any value of the `HashJoinExec`.

	// init a new list for chunk
	innerResult := chunk.NewList(e.innerSideExec.base().retFieldTypes, e.ctx.GetSessionVars().InitChunkSize, e.maxChunkSize)

	for {
		chk := chunk.New(e.innerSideExec.base().retFieldTypes, e.ctx.GetSessionVars().InitChunkSize,  e.ctx.GetSessionVars().MaxChunkSize)

		err := e.innerSideExec.Next(ctx, chk)
		if err != nil {
			return errors.Trace(err)
		if chk.NumRows() == 0 {


	buildKeyColIdx := make([]int, len(e.innerKeys))
	for i := range e.innerKeys {
		buildKeyColIdx[i] = e.innerKeys[i].Index
	hCtx := &hashContext{
		allTypes:  e.innerSideExec.base().retFieldTypes,
		keyColIdx: buildKeyColIdx,
	e.rowContainer= newHashRowContainer(e.innerSideExec.base().ctx, int(e.innerSideEstCount), hCtx, innerResult)
	return nil

My another function runJoinWorkers

func (e *HashJoinExec) runJoinWorker(workerID uint, outerKeyColIdx []int) {
	// TODO: Implement the worker of probing stage.

	// In this method, you read the data from the channel e.outerResultChs[workerID].
	// Then use `e.join2Chunk` method get the joined result `joinResult`,
	// and put the `joinResult` into the channel `e.joinResultCh`.

	// You may pay attention to:
	// - e.closeCh, this is a channel tells that the join can be terminated as soon as possible.
	// Read and filter outerResult, and join the outerResult with the inner rows.

	emptyOuterResult := &outerChkResource{
		dest: e.outerResultChs[workerID],

	hCtx := &hashContext{
		allTypes:  e.outerSideExec.base().retFieldTypes,
		keyColIdx: outerKeyColIdx,

	var (
		outerChunk *chunk.Chunk
		selected    = make([]bool, 0, chunk.InitialCapacity)

	// reuse JoinResult Chk from main goroutine
	ok, joinResult := e.getNewJoinResult(workerID)
	if !ok {

	for ok = true; ok;{

		case <-e.closeCh:
		// get outerChunk from Outer Fetcher Goroutine
		case outerChunk, ok = <-e.outerResultChs[workerID]:

		if !ok{

		// look up in hash table and compare different rows
		ok, joinResult = e.join2Chunk(workerID, outerChunk, hCtx, joinResult, selected)
		if !ok{
		// send back info to outerChkResou
		emptyOuterResult.chk = outerChunk
		e.outerChkResourceCh <- emptyOuterResult
	// send result to joinResultCh
	if joinResult == nil {
	} else if joinResult.err != nil || (joinResult.chk != nil && joinResult.chk.NumRows() > 0) {
		e.joinResultCh <- joinResult
	} else if joinResult.chk != nil && joinResult.chk.NumRows() == 0 {
		e.joinChkResourceCh[workerID] <- joinResult.chk

Can you give me some advice on debugging/ Am I misunderstanding the instructions somewhere? I also tried to follow source code and master branch code, but also fail, which made me doubt at the correctness of program itself.

The test failed at join result. For example, TestJoin case:

... obtained string = ""
... expected string = "[1]\
... sql:select 1 from t as a join t as b on 1

One more thing, seems that the function name NextChunk is no longer used but github tutorial is still using it. I can only find Next.

@winoros PTAL