code: func (p *Projection) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan, err error) {
  	retPlan = p
  	var push []expression.Expression
  	for _, cond := range predicates {
  		canSubstitute := true
  		extractedCols := expression.ExtractColumns(cond)
  		for _, col := range extractedCols {
  			id := p.GetSchema().GetColumnIndex(col)
  			if _, ok := p.Exprs[id].(*expression.ScalarFunction); ok {
  				canSubstitute = false
  				break
  			}
  		}
  		if canSubstitute {
  			push = append(push, expression.ColumnSubstitute(cond, p.GetSchema(), p.Exprs))
  		} else {
  			ret = append(ret, cond)
  		}
  	}
  	child := p.GetChildByIndex(0).(LogicalPlan)
  	restConds, _, err1 := child.PredicatePushDown(push)
  	if err1 != nil {
  		return nil, nil, errors.Trace(err1)
  	}
  	if len(restConds) > 0 {
  		err1 = addSelection(p, child, restConds, p.allocator)
  		if err1 != nil {
  			return nil, nil, errors.Trace(err1)
  		}
  	}
  	return
  }
docs: // PredicatePushDown implements LogicalPlan PredicatePushDown interface.