code: func (ds *DataSource) PruneColumns(parentUsedCols []*expression.Column) error {
  	used, err := getUsedList(parentUsedCols, ds.schema)
  	if err != nil {
  		return err
  	}
  
  	var (
  		handleCol     *expression.Column
  		handleColInfo *model.ColumnInfo
  	)
  	for i := len(used) - 1; i >= 0; i-- {
  		if ds.tableInfo.PKIsHandle && mysql.HasPriKeyFlag(ds.Columns[i].Flag) {
  			handleCol = ds.schema.Columns[i]
  			handleColInfo = ds.Columns[i]
  		}
  		if !used[i] {
  			ds.schema.Columns = append(ds.schema.Columns[:i], ds.schema.Columns[i+1:]...)
  			ds.Columns = append(ds.Columns[:i], ds.Columns[i+1:]...)
  		}
  	}
  	for k, cols := range ds.schema.TblID2Handle {
  		if ds.schema.ColumnIndex(cols[0]) == -1 {
  			delete(ds.schema.TblID2Handle, k)
  		}
  	}
  	// For SQL like `select 1 from t`, tikv's response will be empty if no column is in schema.
  	// So we'll force to push one if schema doesn't have any column.
  	if ds.schema.Len() == 0 && !infoschema.IsMemoryDB(ds.DBName.L) {
  		if handleCol == nil {
  			handleCol = ds.newExtraHandleSchemaCol()
  			handleColInfo = model.NewExtraHandleColInfo()
  		}
  		ds.Columns = append(ds.Columns, handleColInfo)
  		ds.schema.Append(handleCol)
  	}
  	return nil
  }
docs: // PruneColumns implements LogicalPlan interface.