github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/export.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package frontend
    16  
    17  import (
    18  	"bufio"
    19  	"bytes"
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"os"
    24  	"slices"
    25  	"strconv"
    26  	"strings"
    27  	"sync"
    28  
    29  	"go.uber.org/zap"
    30  	"golang.org/x/sync/errgroup"
    31  
    32  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    33  	util2 "github.com/matrixorigin/matrixone/pkg/common/util"
    34  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    35  	"github.com/matrixorigin/matrixone/pkg/container/bytejson"
    36  	"github.com/matrixorigin/matrixone/pkg/container/types"
    37  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    38  	"github.com/matrixorigin/matrixone/pkg/defines"
    39  	"github.com/matrixorigin/matrixone/pkg/fileservice"
    40  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    41  )
    42  
    43  type ExportConfig struct {
    44  	// configs from user input
    45  	userConfig *tree.ExportParam
    46  	// file handler
    47  	File *os.File
    48  	// bufio.writer
    49  	Writer *bufio.Writer
    50  	// curFileSize
    51  	CurFileSize uint64
    52  	Rows        uint64
    53  	FileCnt     uint
    54  	ColumnFlag  []bool
    55  	Symbol      [][]byte
    56  	// default flush size
    57  	DefaultBufSize int64
    58  	OutputStr      []byte
    59  	LineSize       uint64
    60  
    61  	//file service & buffer for the line
    62  	UseFileService bool
    63  	writeParam
    64  	FileService fileservice.FileService
    65  	LineBuffer  *bytes.Buffer
    66  	Ctx         context.Context
    67  	AsyncReader *io.PipeReader
    68  	AsyncWriter *io.PipeWriter
    69  	AsyncGroup  *errgroup.Group
    70  }
    71  
    72  type writeParam struct {
    73  	First      bool
    74  	OutTofile  bool
    75  	Index      int32
    76  	WriteIndex int32
    77  	ByteChan   chan *BatchByte
    78  	BatchMap   map[int32][]byte
    79  }
    80  
    81  type BatchByte struct {
    82  	index     int32
    83  	writeByte []byte
    84  	err       error
    85  }
    86  
    87  var OpenFile = os.OpenFile
    88  var escape byte = '"'
    89  
    90  type CloseExportData struct {
    91  	stopExportData chan interface{}
    92  	onceClose      sync.Once
    93  }
    94  
    95  func NewCloseExportData() *CloseExportData {
    96  	return &CloseExportData{
    97  		stopExportData: make(chan interface{}),
    98  	}
    99  }
   100  
   101  func (cld *CloseExportData) Open() {
   102  }
   103  
   104  func (cld *CloseExportData) Close() {
   105  	cld.onceClose.Do(func() {
   106  		close(cld.stopExportData)
   107  	})
   108  }
   109  
   110  // needExportToFile checks needing to export into file or not
   111  func (ec *ExportConfig) needExportToFile() bool {
   112  	return ec != nil && ec.userConfig != nil && ec.userConfig.Outfile
   113  }
   114  
   115  func initExportFileParam(ep *ExportConfig, mrs *MysqlResultSet) {
   116  	ep.DefaultBufSize *= 1024 * 1024
   117  	n := (int)(mrs.GetColumnCount())
   118  	if n <= 0 {
   119  		return
   120  	}
   121  	ep.Symbol = make([][]byte, n)
   122  	for i := 0; i < n-1; i++ {
   123  		ep.Symbol[i] = []byte(ep.userConfig.Fields.Terminated.Value)
   124  	}
   125  	ep.Symbol[n-1] = []byte(ep.userConfig.Lines.TerminatedBy.Value)
   126  	ep.ColumnFlag = make([]bool, len(mrs.Name2Index))
   127  	for i := 0; i < len(ep.userConfig.ForceQuote); i++ {
   128  		col, ok := mrs.Name2Index[ep.userConfig.ForceQuote[i]]
   129  		if ok {
   130  			ep.ColumnFlag[col] = true
   131  		}
   132  	}
   133  }
   134  
   135  var openNewFile = func(ctx context.Context, ep *ExportConfig, mrs *MysqlResultSet) error {
   136  	lineSize := ep.LineSize
   137  	var err error
   138  	ep.CurFileSize = 0
   139  	if !ep.UseFileService {
   140  		var filePath string
   141  		if len(ep.userConfig.StageFilePath) != 0 {
   142  			filePath = getExportFilePath(ep.userConfig.StageFilePath, ep.FileCnt)
   143  		} else {
   144  			filePath = getExportFilePath(ep.userConfig.FilePath, ep.FileCnt)
   145  		}
   146  		ep.File, err = OpenFile(filePath, os.O_RDWR|os.O_EXCL|os.O_CREATE, 0o666)
   147  		if err != nil {
   148  			return err
   149  		}
   150  		ep.Writer = bufio.NewWriterSize(ep.File, int(ep.DefaultBufSize))
   151  	} else {
   152  		//default 1MB
   153  		if ep.LineBuffer == nil {
   154  			ep.LineBuffer = &bytes.Buffer{}
   155  		} else {
   156  			ep.LineBuffer.Reset()
   157  		}
   158  		ep.AsyncReader, ep.AsyncWriter = io.Pipe()
   159  		filePath := getExportFilePath(ep.userConfig.FilePath, ep.FileCnt)
   160  
   161  		asyncWriteFunc := func() error {
   162  			vec := fileservice.IOVector{
   163  				FilePath: filePath,
   164  				Entries: []fileservice.IOEntry{
   165  					{
   166  						ReaderForWrite: ep.AsyncReader,
   167  						Size:           -1,
   168  					},
   169  				},
   170  			}
   171  			err := ep.FileService.Write(ctx, vec)
   172  			if err != nil {
   173  				err2 := ep.AsyncReader.CloseWithError(err)
   174  				if err2 != nil {
   175  					return err2
   176  				}
   177  			}
   178  			return err
   179  		}
   180  
   181  		ep.AsyncGroup, _ = errgroup.WithContext(ctx)
   182  		ep.AsyncGroup.Go(asyncWriteFunc)
   183  	}
   184  	if ep.userConfig.Header {
   185  		var header string
   186  		n := len(mrs.Columns)
   187  		if n == 0 {
   188  			return nil
   189  		}
   190  		for i := 0; i < n-1; i++ {
   191  			header += mrs.Columns[i].Name() + ep.userConfig.Fields.Terminated.Value
   192  		}
   193  		header += mrs.Columns[n-1].Name() + ep.userConfig.Lines.TerminatedBy.Value
   194  		if ep.userConfig.MaxFileSize != 0 && uint64(len(header)) >= ep.userConfig.MaxFileSize {
   195  			return moerr.NewInternalError(ctx, "the header line size is over the maxFileSize")
   196  		}
   197  		if err := writeDataToCSVFile(ep, []byte(header)); err != nil {
   198  			return err
   199  		}
   200  		if _, err := EndOfLine(ep); err != nil {
   201  			return err
   202  		}
   203  	}
   204  	if lineSize != 0 {
   205  		ep.LineSize = 0
   206  		ep.Rows = 0
   207  		if err := writeDataToCSVFile(ep, ep.OutputStr); err != nil {
   208  			return err
   209  		}
   210  	}
   211  	return nil
   212  }
   213  
   214  func getExportFilePath(filename string, fileCnt uint) string {
   215  	if fileCnt == 0 {
   216  		return filename
   217  	} else {
   218  		return fmt.Sprintf("%s.%d", filename, fileCnt)
   219  	}
   220  }
   221  
   222  var formatOutputString = func(oq *outputQueue, tmp, symbol []byte, enclosed byte, flag bool) error {
   223  	var err error
   224  	if flag && enclosed != 0 {
   225  		if err = writeToCSVFile(oq, []byte{enclosed}); err != nil {
   226  			return err
   227  		}
   228  	}
   229  	if err = writeToCSVFile(oq, tmp); err != nil {
   230  		return err
   231  	}
   232  	if flag && enclosed != 0 {
   233  		if err = writeToCSVFile(oq, []byte{enclosed}); err != nil {
   234  			return err
   235  		}
   236  	}
   237  	if err = writeToCSVFile(oq, symbol); err != nil {
   238  		return err
   239  	}
   240  	return nil
   241  }
   242  
   243  var Flush = func(ep *ExportConfig) error {
   244  	if !ep.UseFileService {
   245  		return ep.Writer.Flush()
   246  	}
   247  	return nil
   248  }
   249  
   250  var Seek = func(ep *ExportConfig) (int64, error) {
   251  	if !ep.UseFileService {
   252  		return ep.File.Seek(int64(ep.CurFileSize-ep.LineSize), io.SeekStart)
   253  	}
   254  	return 0, nil
   255  }
   256  
   257  var Read = func(ep *ExportConfig) (int, error) {
   258  	if !ep.UseFileService {
   259  		ep.OutputStr = make([]byte, ep.LineSize)
   260  		return ep.File.Read(ep.OutputStr)
   261  	} else {
   262  		ep.OutputStr = make([]byte, ep.LineSize)
   263  		copy(ep.OutputStr, ep.LineBuffer.Bytes())
   264  		ep.LineBuffer.Reset()
   265  		return int(ep.LineSize), nil
   266  	}
   267  }
   268  
   269  var Truncate = func(ep *ExportConfig) error {
   270  	if !ep.UseFileService {
   271  		return ep.File.Truncate(int64(ep.CurFileSize - ep.LineSize))
   272  	} else {
   273  		return nil
   274  	}
   275  }
   276  
   277  var Close = func(ep *ExportConfig) error {
   278  	if !ep.UseFileService {
   279  		ep.FileCnt++
   280  		return ep.File.Close()
   281  	} else {
   282  		ep.FileCnt++
   283  		err := ep.AsyncWriter.Close()
   284  		if err != nil {
   285  			return err
   286  		}
   287  		err = ep.AsyncGroup.Wait()
   288  		if err != nil {
   289  			return err
   290  		}
   291  		err = ep.AsyncReader.Close()
   292  		if err != nil {
   293  			return err
   294  		}
   295  		ep.AsyncReader = nil
   296  		ep.AsyncWriter = nil
   297  		ep.AsyncGroup = nil
   298  		return err
   299  	}
   300  }
   301  
   302  var Write = func(ep *ExportConfig, output []byte) (int, error) {
   303  	if !ep.UseFileService {
   304  		return ep.Writer.Write(output)
   305  	} else {
   306  		return ep.LineBuffer.Write(output)
   307  	}
   308  }
   309  
   310  var EndOfLine = func(ep *ExportConfig) (int, error) {
   311  	if ep.UseFileService {
   312  		n, err := ep.AsyncWriter.Write(ep.LineBuffer.Bytes())
   313  		if err != nil {
   314  			err2 := ep.AsyncWriter.CloseWithError(err)
   315  			if err2 != nil {
   316  				return 0, err2
   317  			}
   318  		}
   319  		ep.LineBuffer.Reset()
   320  		return n, err
   321  	}
   322  	return 0, nil
   323  }
   324  
   325  func writeToCSVFile(oq *outputQueue, output []byte) error {
   326  	if oq.ep.userConfig.MaxFileSize != 0 && oq.ep.CurFileSize+uint64(len(output)) > oq.ep.userConfig.MaxFileSize {
   327  		if err := Flush(oq.ep); err != nil {
   328  			return err
   329  		}
   330  		if oq.ep.LineSize != 0 && oq.ep.OutTofile {
   331  			if _, err := Seek(oq.ep); err != nil {
   332  				return err
   333  			}
   334  			for {
   335  				if n, err := Read(oq.ep); err != nil {
   336  					return err
   337  				} else if uint64(n) == oq.ep.LineSize {
   338  					break
   339  				}
   340  			}
   341  			if err := Truncate(oq.ep); err != nil {
   342  				return err
   343  			}
   344  		}
   345  		if err := Close(oq.ep); err != nil {
   346  			return err
   347  		}
   348  		if err := openNewFile(oq.ctx, oq.ep, oq.mrs); err != nil {
   349  			return err
   350  		}
   351  	}
   352  
   353  	if err := writeDataToCSVFile(oq.ep, output); err != nil {
   354  		return err
   355  	}
   356  	return nil
   357  }
   358  
   359  var writeDataToCSVFile = func(ep *ExportConfig, output []byte) error {
   360  	for {
   361  		if n, err := Write(ep, output); err != nil {
   362  			return err
   363  		} else if n == len(output) {
   364  			break
   365  		}
   366  	}
   367  	ep.LineSize += uint64(len(output))
   368  	ep.CurFileSize += uint64(len(output))
   369  	return nil
   370  }
   371  
   372  func appendBytes(writeByte, tmp, symbol []byte, enclosed byte, flag bool) []byte {
   373  	if flag && enclosed != 0 {
   374  		writeByte = append(writeByte, enclosed)
   375  	}
   376  	writeByte = append(writeByte, tmp...)
   377  	if flag && enclosed != 0 {
   378  		writeByte = append(writeByte, enclosed)
   379  	}
   380  	writeByte = append(writeByte, symbol...)
   381  	return writeByte
   382  }
   383  
   384  func preCopyBat(obj interface{}, bat *batch.Batch) *batch.Batch {
   385  	ses := obj.(*Session)
   386  	bat2 := batch.NewWithSize(len(bat.Vecs))
   387  	for i, vec := range bat.Vecs {
   388  		bat2.Vecs[i], _ = vec.Dup(ses.GetMemPool())
   389  	}
   390  	bat2.SetRowCount(bat.RowCount())
   391  	return bat2
   392  }
   393  
   394  func initExportFirst(oq *outputQueue) {
   395  	if !oq.ep.First {
   396  		oq.ep.First = true
   397  		oq.ep.ByteChan = make(chan *BatchByte, 10)
   398  		oq.ep.BatchMap = make(map[int32][]byte)
   399  		oq.ep.Index = 0
   400  		oq.ep.WriteIndex = 0
   401  	}
   402  	oq.ep.Index++
   403  }
   404  
   405  func formatJsonString(str string, flag bool, terminatedBy string) string {
   406  	if len(str) < 2 {
   407  		return "\"" + str + "\""
   408  	}
   409  	var tmp string
   410  	if !flag {
   411  		tmp = strings.ReplaceAll(str, terminatedBy, "\\"+terminatedBy)
   412  	} else {
   413  		tmp = strings.ReplaceAll(str, "\",", "\"\",")
   414  	}
   415  	return tmp
   416  }
   417  
   418  func constructByte(ctx context.Context, obj interface{}, bat *batch.Batch, index int32, ByteChan chan *BatchByte, oq *outputQueue) {
   419  	ses := obj.(*Session)
   420  	symbol := oq.ep.Symbol
   421  	closeby := oq.ep.userConfig.Fields.EnclosedBy.Value
   422  	terminated := oq.ep.userConfig.Fields.Terminated.Value
   423  	flag := oq.ep.ColumnFlag
   424  	writeByte := make([]byte, 0)
   425  	for i := 0; i < bat.RowCount(); i++ {
   426  		for j, vec := range bat.Vecs {
   427  			if vec.GetNulls().Contains(uint64(i)) {
   428  				writeByte = appendBytes(writeByte, []byte("\\N"), symbol[j], closeby, flag[j])
   429  				continue
   430  			}
   431  			switch vec.GetType().Oid { //get col
   432  			case types.T_json:
   433  				val := types.DecodeJson(vec.GetBytesAt(i))
   434  				writeByte = appendBytes(writeByte, []byte(formatJsonString(val.String(), flag[j], terminated)), symbol[j], closeby, flag[j])
   435  			case types.T_bool:
   436  				val := vector.GetFixedAt[bool](vec, i)
   437  				if val {
   438  					writeByte = appendBytes(writeByte, []byte("true"), symbol[j], closeby, flag[j])
   439  				} else {
   440  					writeByte = appendBytes(writeByte, []byte("false"), symbol[j], closeby, flag[j])
   441  				}
   442  			case types.T_bit:
   443  				val := vector.GetFixedAt[uint64](vec, i)
   444  				bitLength := vec.GetType().Width
   445  				byteLength := (bitLength + 7) / 8
   446  				b := types.EncodeUint64(&val)[:byteLength]
   447  				slices.Reverse(b)
   448  				writeByte = appendBytes(writeByte, b, symbol[j], closeby, flag[j])
   449  			case types.T_int8:
   450  				val := vector.GetFixedAt[int8](vec, i)
   451  				writeByte = appendBytes(writeByte, []byte(strconv.FormatInt(int64(val), 10)), symbol[j], closeby, flag[j])
   452  			case types.T_int16:
   453  				val := vector.GetFixedAt[int16](vec, i)
   454  				writeByte = appendBytes(writeByte, []byte(strconv.FormatInt(int64(val), 10)), symbol[j], closeby, flag[j])
   455  			case types.T_int32:
   456  				val := vector.GetFixedAt[int32](vec, i)
   457  				writeByte = appendBytes(writeByte, []byte(strconv.FormatInt(int64(val), 10)), symbol[j], closeby, flag[j])
   458  			case types.T_int64:
   459  				val := vector.GetFixedAt[int64](vec, i)
   460  				writeByte = appendBytes(writeByte, []byte(strconv.FormatInt(int64(val), 10)), symbol[j], closeby, flag[j])
   461  			case types.T_uint8:
   462  				val := vector.GetFixedAt[uint8](vec, i)
   463  				writeByte = appendBytes(writeByte, []byte(strconv.FormatUint(uint64(val), 10)), symbol[j], closeby, flag[j])
   464  			case types.T_uint16:
   465  				val := vector.GetFixedAt[uint16](vec, i)
   466  				writeByte = appendBytes(writeByte, []byte(strconv.FormatUint(uint64(val), 10)), symbol[j], closeby, flag[j])
   467  			case types.T_uint32:
   468  				val := vector.GetFixedAt[uint32](vec, i)
   469  				writeByte = appendBytes(writeByte, []byte(strconv.FormatUint(uint64(val), 10)), symbol[j], closeby, flag[j])
   470  			case types.T_uint64:
   471  				val := vector.GetFixedAt[uint64](vec, i)
   472  				writeByte = appendBytes(writeByte, []byte(strconv.FormatUint(uint64(val), 10)), symbol[j], closeby, flag[j])
   473  			case types.T_float32:
   474  				val := vector.GetFixedAt[float32](vec, i)
   475  				if vec.GetType().Scale < 0 || vec.GetType().Width == 0 {
   476  					writeByte = appendBytes(writeByte, []byte(strconv.FormatFloat(float64(val), 'f', -1, 32)), symbol[j], closeby, flag[j])
   477  				} else {
   478  					writeByte = appendBytes(writeByte, []byte(strconv.FormatFloat(float64(val), 'f', int(vec.GetType().Scale), 64)), symbol[j], closeby, flag[j])
   479  				}
   480  			case types.T_float64:
   481  				val := vector.GetFixedAt[float64](vec, i)
   482  				if vec.GetType().Scale < 0 || vec.GetType().Width == 0 {
   483  					writeByte = appendBytes(writeByte, []byte(strconv.FormatFloat(float64(val), 'f', -1, 32)), symbol[j], closeby, flag[j])
   484  				} else {
   485  					writeByte = appendBytes(writeByte, []byte(strconv.FormatFloat(float64(val), 'f', int(vec.GetType().Scale), 64)), symbol[j], closeby, flag[j])
   486  				}
   487  			case types.T_char, types.T_varchar, types.T_blob, types.T_text, types.T_binary, types.T_varbinary:
   488  				value := addEscapeToString(vec.GetBytesAt(i))
   489  				writeByte = appendBytes(writeByte, value, symbol[j], closeby, true)
   490  			case types.T_array_float32:
   491  				arrStr := types.BytesToArrayToString[float32](vec.GetBytesAt(i))
   492  				value := addEscapeToString(util2.UnsafeStringToBytes(arrStr))
   493  				writeByte = appendBytes(writeByte, value, symbol[j], closeby, true)
   494  			case types.T_array_float64:
   495  				arrStr := types.BytesToArrayToString[float64](vec.GetBytesAt(i))
   496  				value := addEscapeToString(util2.UnsafeStringToBytes(arrStr))
   497  				writeByte = appendBytes(writeByte, value, symbol[j], closeby, true)
   498  			case types.T_date:
   499  				val := vector.GetFixedAt[types.Date](vec, i)
   500  				writeByte = appendBytes(writeByte, []byte(val.String()), symbol[j], closeby, flag[j])
   501  			case types.T_datetime:
   502  				scale := vec.GetType().Scale
   503  				val := vector.GetFixedAt[types.Datetime](vec, i).String2(scale)
   504  				writeByte = appendBytes(writeByte, []byte(val), symbol[j], closeby, flag[j])
   505  			case types.T_time:
   506  				scale := vec.GetType().Scale
   507  				val := vector.GetFixedAt[types.Time](vec, i).String2(scale)
   508  				writeByte = appendBytes(writeByte, []byte(val), symbol[j], closeby, flag[j])
   509  			case types.T_timestamp:
   510  				scale := vec.GetType().Scale
   511  				timeZone := ses.GetTimeZone()
   512  				val := vector.GetFixedAt[types.Timestamp](vec, i).String2(timeZone, scale)
   513  				writeByte = appendBytes(writeByte, []byte(val), symbol[j], closeby, flag[j])
   514  			case types.T_decimal64:
   515  				scale := vec.GetType().Scale
   516  				val := vector.GetFixedAt[types.Decimal64](vec, i).Format(scale)
   517  				writeByte = appendBytes(writeByte, []byte(val), symbol[j], closeby, flag[j])
   518  			case types.T_decimal128:
   519  				scale := vec.GetType().Scale
   520  				val := vector.GetFixedAt[types.Decimal128](vec, i).Format(scale)
   521  				writeByte = appendBytes(writeByte, []byte(val), symbol[j], closeby, flag[j])
   522  			case types.T_uuid:
   523  				val := vector.GetFixedAt[types.Uuid](vec, i).ToString()
   524  				writeByte = appendBytes(writeByte, []byte(val), symbol[j], closeby, flag[j])
   525  			case types.T_Rowid:
   526  				val := vector.GetFixedAt[types.Rowid](vec, i)
   527  				writeByte = appendBytes(writeByte, []byte(val.String()), symbol[j], closeby, flag[j])
   528  			case types.T_Blockid:
   529  				val := vector.GetFixedAt[types.Blockid](vec, i)
   530  				writeByte = appendBytes(writeByte, []byte(val.String()), symbol[j], closeby, flag[j])
   531  			case types.T_enum:
   532  				val := vector.GetFixedAt[types.Blockid](vec, i)
   533  				writeByte = appendBytes(writeByte, []byte(val.String()), symbol[j], closeby, flag[j])
   534  			default:
   535  				logError(ses, ses.GetDebugString(),
   536  					"Failed to construct byte due to unsupported type",
   537  					zap.Int("typeOid", int(vec.GetType().Oid)))
   538  				ByteChan <- &BatchByte{
   539  					err: moerr.NewInternalError(ctx, "constructByte : unsupported type %d", vec.GetType().Oid),
   540  				}
   541  				bat.Clean(ses.GetMemPool())
   542  				return
   543  			}
   544  		}
   545  	}
   546  
   547  	ByteChan <- &BatchByte{
   548  		index:     index,
   549  		writeByte: writeByte,
   550  		err:       nil,
   551  	}
   552  	ses.writeCsvBytes.Add(int64(len(writeByte))) // statistic out traffic, CASE 2: select into
   553  	bat.Clean(ses.GetMemPool())
   554  }
   555  
   556  func addEscapeToString(s []byte) []byte {
   557  	pos := make([]int, 0)
   558  	for i := 0; i < len(s); i++ {
   559  		if s[i] == escape {
   560  			pos = append(pos, i)
   561  		}
   562  	}
   563  	if len(pos) == 0 {
   564  		return s
   565  	}
   566  	ret := make([]byte, 0)
   567  	cur := 0
   568  	for i := 0; i < len(pos); i++ {
   569  		ret = append(ret, s[cur:pos[i]]...)
   570  		ret = append(ret, escape)
   571  		cur = pos[i]
   572  	}
   573  	ret = append(ret, s[cur:]...)
   574  	return ret
   575  }
   576  
   577  func exportDataToCSVFile(oq *outputQueue) error {
   578  	if !oq.ep.OutTofile {
   579  		return exportDataToCSVFile2(oq)
   580  	}
   581  	oq.ep.LineSize = 0
   582  
   583  	symbol := oq.ep.Symbol
   584  	closeby := oq.ep.userConfig.Fields.EnclosedBy.Value
   585  	flag := oq.ep.ColumnFlag
   586  	for i := uint64(0); i < oq.mrs.GetColumnCount(); i++ {
   587  		column, err := oq.mrs.GetColumn(oq.ctx, i)
   588  		if err != nil {
   589  			return err
   590  		}
   591  		mysqlColumn, ok := column.(*MysqlColumn)
   592  		if !ok {
   593  			return moerr.NewInternalError(oq.ctx, "sendColumn need MysqlColumn")
   594  		}
   595  		if isNil, err := oq.mrs.ColumnIsNull(oq.ctx, 0, i); err != nil {
   596  			return err
   597  		} else if isNil {
   598  			//NULL is output as \N
   599  			if err = formatOutputString(oq, []byte{'\\', 'N'}, symbol[i], closeby, false); err != nil {
   600  				return err
   601  			}
   602  			continue
   603  		}
   604  
   605  		switch mysqlColumn.ColumnType() {
   606  		case defines.MYSQL_TYPE_DECIMAL:
   607  			value, err := oq.mrs.GetString(oq.ctx, 0, i)
   608  			if err != nil {
   609  				return err
   610  			}
   611  			if err = formatOutputString(oq, []byte(value), symbol[i], closeby, flag[i]); err != nil {
   612  				return err
   613  			}
   614  		case defines.MYSQL_TYPE_BOOL:
   615  			value, err := oq.mrs.GetString(oq.ctx, 0, i)
   616  			if err != nil {
   617  				return err
   618  			}
   619  			if err = formatOutputString(oq, []byte(value), symbol[i], closeby, flag[i]); err != nil {
   620  				return err
   621  			}
   622  		case defines.MYSQL_TYPE_BIT:
   623  			value, err := oq.mrs.GetString(oq.ctx, 0, i)
   624  			if err != nil {
   625  				return err
   626  			}
   627  			if err = formatOutputString(oq, []byte(value), symbol[i], closeby, flag[i]); err != nil {
   628  				return err
   629  			}
   630  		case defines.MYSQL_TYPE_TINY, defines.MYSQL_TYPE_SHORT, defines.MYSQL_TYPE_INT24, defines.MYSQL_TYPE_LONG, defines.MYSQL_TYPE_YEAR:
   631  			value, err := oq.mrs.GetInt64(oq.ctx, 0, i)
   632  			if err != nil {
   633  				return err
   634  			}
   635  			if mysqlColumn.ColumnType() == defines.MYSQL_TYPE_YEAR {
   636  				if value == 0 {
   637  					if err = formatOutputString(oq, []byte("0000"), symbol[i], closeby, flag[i]); err != nil {
   638  						return err
   639  					}
   640  				} else {
   641  					oq.resetLineStr()
   642  					oq.lineStr = strconv.AppendInt(oq.lineStr, value, 10)
   643  					if err = formatOutputString(oq, oq.lineStr, symbol[i], closeby, flag[i]); err != nil {
   644  						return err
   645  					}
   646  				}
   647  			} else {
   648  				oq.resetLineStr()
   649  				oq.lineStr = strconv.AppendInt(oq.lineStr, value, 10)
   650  				if err = formatOutputString(oq, oq.lineStr, symbol[i], closeby, flag[i]); err != nil {
   651  					return err
   652  				}
   653  			}
   654  		case defines.MYSQL_TYPE_FLOAT, defines.MYSQL_TYPE_DOUBLE:
   655  			value, err := oq.mrs.GetFloat64(oq.ctx, 0, i)
   656  			if err != nil {
   657  				return err
   658  			}
   659  			oq.lineStr = []byte(fmt.Sprintf("%v", value))
   660  			if err = formatOutputString(oq, oq.lineStr, symbol[i], closeby, flag[i]); err != nil {
   661  				return err
   662  			}
   663  		case defines.MYSQL_TYPE_LONGLONG:
   664  			if uint32(mysqlColumn.Flag())&defines.UNSIGNED_FLAG != 0 {
   665  				if value, err := oq.mrs.GetUint64(oq.ctx, 0, i); err != nil {
   666  					return err
   667  				} else {
   668  					oq.resetLineStr()
   669  					oq.lineStr = strconv.AppendUint(oq.lineStr, value, 10)
   670  					if err = formatOutputString(oq, oq.lineStr, symbol[i], closeby, flag[i]); err != nil {
   671  						return err
   672  					}
   673  				}
   674  			} else {
   675  				if value, err := oq.mrs.GetInt64(oq.ctx, 0, i); err != nil {
   676  					return err
   677  				} else {
   678  					oq.resetLineStr()
   679  					oq.lineStr = strconv.AppendInt(oq.lineStr, value, 10)
   680  					if err = formatOutputString(oq, oq.lineStr, symbol[i], closeby, flag[i]); err != nil {
   681  						return err
   682  					}
   683  				}
   684  			}
   685  		// Binary/varbinary has mysql_type_varchar.
   686  		case defines.MYSQL_TYPE_VARCHAR, defines.MYSQL_TYPE_VAR_STRING, defines.MYSQL_TYPE_STRING,
   687  			defines.MYSQL_TYPE_BLOB, defines.MYSQL_TYPE_TEXT:
   688  			value, err := oq.mrs.GetValue(oq.ctx, 0, i)
   689  			if err != nil {
   690  				return err
   691  			}
   692  			value = addEscapeToString(value.([]byte))
   693  			if err = formatOutputString(oq, value.([]byte), symbol[i], closeby, true); err != nil {
   694  				return err
   695  			}
   696  		case defines.MYSQL_TYPE_DATE:
   697  			value, err := oq.mrs.GetValue(oq.ctx, 0, i)
   698  			if err != nil {
   699  				return err
   700  			}
   701  			if err = formatOutputString(oq, []byte(value.(types.Date).String()), symbol[i], closeby, flag[i]); err != nil {
   702  				return err
   703  			}
   704  		case defines.MYSQL_TYPE_TIME:
   705  			value, err := oq.mrs.GetValue(oq.ctx, 0, i)
   706  			if err != nil {
   707  				return err
   708  			}
   709  			if err = formatOutputString(oq, []byte(value.(types.Time).String()), symbol[i], closeby, flag[i]); err != nil {
   710  				return err
   711  			}
   712  		case defines.MYSQL_TYPE_DATETIME:
   713  			value, err := oq.mrs.GetValue(oq.ctx, 0, i)
   714  			if err != nil {
   715  				return err
   716  			}
   717  			if err = formatOutputString(oq, []byte(value.(string)), symbol[i], closeby, flag[i]); err != nil {
   718  				return err
   719  			}
   720  		case defines.MYSQL_TYPE_TIMESTAMP:
   721  			value, err := oq.mrs.GetString(oq.ctx, 0, i)
   722  			if err != nil {
   723  				return err
   724  			}
   725  			if err = formatOutputString(oq, []byte(value), symbol[i], closeby, flag[i]); err != nil {
   726  				return err
   727  			}
   728  		case defines.MYSQL_TYPE_JSON:
   729  			value, err := oq.mrs.GetValue(oq.ctx, 0, i)
   730  			if err != nil {
   731  				return err
   732  			}
   733  			jsonStr := value.(bytejson.ByteJson).String()
   734  			if err = formatOutputString(oq, []byte(jsonStr), symbol[i], closeby, flag[i]); err != nil {
   735  				return err
   736  			}
   737  		case defines.MYSQL_TYPE_UUID:
   738  			value, err := oq.mrs.GetString(oq.ctx, 0, i)
   739  			if err != nil {
   740  				return err
   741  			}
   742  			if err = formatOutputString(oq, []byte(value), symbol[i], closeby, flag[i]); err != nil {
   743  				return err
   744  			}
   745  		default:
   746  			return moerr.NewInternalError(oq.ctx, "unsupported column type %d ", mysqlColumn.ColumnType())
   747  		}
   748  	}
   749  	oq.ep.Rows++
   750  	_, err := EndOfLine(oq.ep)
   751  	return err
   752  }
   753  
   754  func exportDataToCSVFile2(oq *outputQueue) error {
   755  	var tmp *BatchByte
   756  	select {
   757  	case tmp = <-oq.ep.ByteChan:
   758  	default:
   759  	}
   760  	if tmp != nil {
   761  		if tmp.err != nil {
   762  			return tmp.err
   763  		}
   764  		oq.ep.BatchMap[tmp.index] = tmp.writeByte
   765  	}
   766  
   767  	value, ok := oq.ep.BatchMap[oq.ep.WriteIndex+1]
   768  	if !ok {
   769  		return nil
   770  	}
   771  
   772  	if err := writeToCSVFile(oq, value); err != nil {
   773  		return err
   774  	}
   775  	oq.ep.WriteIndex++
   776  	oq.ep.BatchMap[oq.ep.WriteIndex] = nil
   777  	_, err := EndOfLine(oq.ep)
   778  	return err
   779  }
   780  
   781  func exportAllData(oq *outputQueue) error {
   782  	var tmp *BatchByte
   783  	for {
   784  		tmp = nil
   785  		if oq.ep.WriteIndex == oq.ep.Index {
   786  			break
   787  		}
   788  		select {
   789  		case tmp = <-oq.ep.ByteChan:
   790  		default:
   791  		}
   792  		if tmp != nil {
   793  			if tmp.err != nil {
   794  				return tmp.err
   795  			}
   796  			oq.ep.BatchMap[tmp.index] = tmp.writeByte
   797  		}
   798  
   799  		value, ok := oq.ep.BatchMap[oq.ep.WriteIndex+1]
   800  		if !ok {
   801  			continue
   802  		}
   803  		if err := writeToCSVFile(oq, value); err != nil {
   804  			return err
   805  		}
   806  		oq.ep.WriteIndex++
   807  		oq.ep.BatchMap[oq.ep.WriteIndex] = nil
   808  	}
   809  	oq.ep.First = false
   810  	oq.ep.FileCnt = 0
   811  	oq.ep.ByteChan = nil
   812  	oq.ep.BatchMap = nil
   813  	return nil
   814  }