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 }