Repository: pingcap/tidb
File: pkg/executor/builder.go (Go)

Code before:
		e.numWorkers = 0
	}
	return e
}

func (b *executorBuilder) buildProjection(v *physicalop.PhysicalProjection) exec.Executor {
	childExec := b.build(v.Children()[0])
	if b.err != nil {
		return nil
	}
	return b.newProjectionExec(childExec, v)
}

func (b *executorBuilder) newProjectionExec(childExec exec.Executor, v *physicalop.PhysicalProjection) *ProjectionExec {
	e := &ProjectionExec{
		projectionExecutorContext: newProjectionExecutorContext(b.ctx),
		BaseExecutorV2:            exec.NewBaseExecutorV2(b.ctx.GetSessionVars(), v.Schema(), v.ID(), childExec),
		numWorkers:                int64(b.ctx.GetSessionVars().ProjectionConcurrency()),
		evaluatorSuit:             expression.NewEvaluatorSuite(v.Exprs, v.AvoidColumnEvaluator),
		calculateNoDelay:          v.CalculateNoDelay,
	}

	// If the calculation row count for this Projection operator is smaller
	// than a Chunk size, we turn back to the un-parallel Projection
	// implementation to reduce the goroutine overhead.
	// index join would have the same logic with here.
	if int64(v.StatsCount()) < int64(b.ctx.GetSessionVars().MaxChunkSize) {
		e.numWorkers = 0
	}

	// Use un-parallel projection for query that write on memdb to avoid data race.
	// See also https://github.com/pingcap/tidb/issues/26832
	if b.inUpdateStmt || b.inDeleteStmt || b.inInsertStmt || b.hasLock {
		e.numWorkers = 0
	}
	return e
}

func (b *executorBuilder) buildTableDual(v *physicalop.PhysicalTableDual) exec.Executor {
	if v.RowCount != 0 && v.RowCount != 1 {
		b.err = errors.Errorf("buildTableDual failed, invalid row count for dual table: %v", v.RowCount)
		return nil
	}
	base := exec.NewBaseExecutorV2(b.ctx.GetSessionVars(), v.Schema(), v.ID())
	base.SetInitCap(v.RowCount)
	e := &TableDualExec{
		BaseExecutorV2: base,
		numDualRows:    v.RowCount,
	}
	return e
}

Review comment (suggestion):
Minor grammatical issue in the comment. Consider changing 'index join would have the same logic with here' to 'index join would have the same logic as here' or 'index join would use the same logic'.
```suggestion
	// index join would use the same logic.
```

Code after:
		e.numWorkers = 0
	}
	return e
}

func (b *executorBuilder) buildProjection(v *physicalop.PhysicalProjection) exec.Executor {
	childExec := b.build(v.Children()[0])
	if b.err != nil {
		return nil
	}
	return b.newProjectionExec(childExec, v)
}

func (b *executorBuilder) newProjectionExec(childExec exec.Executor, v *physicalop.PhysicalProjection) *ProjectionExec {
	e := &ProjectionExec{
		projectionExecutorContext: newProjectionExecutorContext(b.ctx),
		BaseExecutorV2:            exec.NewBaseExecutorV2(b.ctx.GetSessionVars(), v.Schema(), v.ID(), childExec),
		numWorkers:                int64(b.ctx.GetSessionVars().ProjectionConcurrency()),
		evaluatorSuit:             expression.NewEvaluatorSuite(v.Exprs, v.AvoidColumnEvaluator),
		calculateNoDelay:          v.CalculateNoDelay,
	}

	// If the calculation row count for this Projection operator is smaller
	// than a Chunk size, we turn back to the un-parallel Projection
	// implementation to reduce the goroutine overhead.
	// index join would use the same logic.
	if int64(v.StatsCount()) < int64(b.ctx.GetSessionVars().MaxChunkSize) {
		e.numWorkers = 0
	}

	// Use un-parallel projection for query that write on memdb to avoid data race.
	// See also https://github.com/pingcap/tidb/issues/26832
	if b.inUpdateStmt || b.inDeleteStmt || b.inInsertStmt || b.hasLock {
		e.numWorkers = 0
	}
	return e
}

func (b *executorBuilder) buildTableDual(v *physicalop.PhysicalTableDual) exec.Executor {
	if v.RowCount != 0 && v.RowCount != 1 {
		b.err = errors.Errorf("buildTableDual failed, invalid row count for dual table: %v", v.RowCount)
		return nil
	}
	base := exec.NewBaseExecutorV2(b.ctx.GetSessionVars(), v.Schema(), v.ID())
	base.SetInitCap(v.RowCount)
	e := &TableDualExec{
		BaseExecutorV2: base,
		numDualRows:    v.RowCount,
	}
	return e
}