code: func ParseSlowLog(tz *time.Location, scanner *bufio.Scanner) ([][]types.Datum, error) {
  	var rows [][]types.Datum
  	startFlag := false
  	var st *slowQueryTuple
  	var err error
  	for scanner.Scan() {
  		line := scanner.Text()
  		// Check slow log entry start flag.
  		if !startFlag && strings.HasPrefix(line, variable.SlowLogStartPrefixStr) {
  			st = &slowQueryTuple{}
  			err = st.setFieldValue(tz, variable.SlowLogTimeStr, line[len(variable.SlowLogStartPrefixStr):])
  			if err != nil {
  				return rows, err
  			}
  			startFlag = true
  			continue
  		}
  
  		if startFlag {
  			// Parse slow log field.
  			if strings.HasPrefix(line, variable.SlowLogRowPrefixStr) {
  				line = line[len(variable.SlowLogRowPrefixStr):]
  				fieldValues := strings.Split(line, " ")
  				for i := 0; i < len(fieldValues)-1; i += 2 {
  					field := fieldValues[i]
  					if strings.HasSuffix(field, ":") {
  						field = field[:len(field)-1]
  					}
  					err = st.setFieldValue(tz, field, fieldValues[i+1])
  					if err != nil {
  						return rows, err
  					}
  				}
  			} else if strings.HasSuffix(line, variable.SlowLogSQLSuffixStr) {
  				// Get the sql string, and mark the start flag to false.
  				err = st.setFieldValue(tz, variable.SlowLogQuerySQLStr, string(hack.Slice(line)))
  				if err != nil {
  					return rows, err
  				}
  				rows = append(rows, st.convertToDatumRow())
  				startFlag = false
  			}
  		}
  	}
  	if err := scanner.Err(); err != nil {
  		return nil, errors.AddStack(err)
  	}
  	return rows, nil
  }
docs: // ParseSlowLog exports for testing.
  // TODO: optimize for parse huge log-file.