@@ -20,6 +20,7 @@ import (
2020
2121 "github.com/matrixorigin/matrixone/pkg/common/moerr"
2222 "github.com/matrixorigin/matrixone/pkg/container/types"
23+ "github.com/matrixorigin/matrixone/pkg/fileservice"
2324 pbplan "github.com/matrixorigin/matrixone/pkg/pb/plan"
2425 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
2526 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/options"
@@ -292,7 +293,7 @@ func TestMakeLoadExternalStatsUsesInputBytes(t *testing.T) {
292293 }
293294 stats := makeLoadExternalStats (& tree.ExternParam {
294295 ExParamConst : tree.ExParamConst {FileSize : 100 },
295- }, tableDef , 25 )
296+ }, tableDef , 25 , context . Background () )
296297 require .GreaterOrEqual (t , stats .Cost , float64 (1 ))
297298 require .GreaterOrEqual (t , stats .Rowsize , float64 (1 ))
298299 requireLoadByteHint (t , stats , 75 )
@@ -301,7 +302,7 @@ func TestMakeLoadExternalStatsUsesInputBytes(t *testing.T) {
301302
302303 stats = makeLoadExternalStats (& tree.ExternParam {
303304 ExParamConst : tree.ExParamConst {FileSize : 10 },
304- }, tableDef , 20 )
305+ }, tableDef , 20 , context . Background () )
305306 require .Equal (t , float64 (0 ), stats .Cost )
306307 require .Equal (t , float64 (1 ), stats .Rowsize )
307308 require .Equal (t , int32 (0 ), stats .BlockNum )
@@ -312,9 +313,43 @@ func TestMakeLoadExternalStatsUsesInputBytes(t *testing.T) {
312313 Format : tree .CSV ,
313314 Data : "1,2\n 3,4\n " ,
314315 },
315- }, tableDef , 0 )
316- require .Equal (t , float64 (3 ), stats .Rowsize )
316+ }, tableDef , 0 , context .Background ())
317+ require .Equal (t , float64 (4 ), stats .Rowsize )
318+ require .Equal (t , float64 (2 ), stats .Cost )
317319 requireLoadByteHint (t , stats , 8 )
320+
321+ stats = makeLoadExternalStats (& tree.ExternParam {
322+ ExParamConst : tree.ExParamConst {
323+ ScanType : tree .INLINE ,
324+ Format : tree .CSV ,
325+ Data : "a\n b\n c\n " ,
326+ },
327+ }, tableDef , 0 , context .Background ())
328+ require .Equal (t , float64 (2 ), stats .Rowsize )
329+ require .Equal (t , float64 (3 ), stats .Cost )
330+ requireLoadByteHint (t , stats , 6 )
331+
332+ stats = makeLoadExternalStats (& tree.ExternParam {
333+ ExParamConst : tree.ExParamConst {
334+ ScanType : tree .INLINE ,
335+ Format : tree .CSV ,
336+ Data : "a|b|c|" ,
337+ Tail : & tree.TailParameter {
338+ Lines : & tree.Lines {
339+ TerminatedBy : & tree.Terminated {Value : "|" },
340+ },
341+ },
342+ },
343+ }, tableDef , 0 , context .Background ())
344+ require .Equal (t , float64 (2 ), stats .Rowsize )
345+ require .Equal (t , float64 (3 ), stats .Cost )
346+ requireLoadByteHint (t , stats , 6 )
347+
348+ rowSize := GetRowSizeFromTableDef (tableDef , true ) * 0.8
349+ stats = makeLoadExternalStats (& tree.ExternParam {
350+ ExParamConst : tree.ExParamConst {FileSize : int64 (float64 (options .DefaultBlockMaxRows ) * rowSize )},
351+ }, tableDef , 0 , context .Background ())
352+ require .Equal (t , int32 (1 ), stats .BlockNum )
318353}
319354
320355func TestMakeLoadExternalStatsKeepsLargeLoadMultiCN (t * testing.T ) {
@@ -327,7 +362,7 @@ func TestMakeLoadExternalStatsKeepsLargeLoadMultiCN(t *testing.T) {
327362 inputSize := int64 (float64 (options .DefaultBlockMaxRows ) * GetRowSizeFromTableDef (tableDef , true ) * 0.8 * float64 (BlockThresholdForOneCN + 1 ))
328363 stats := makeLoadExternalStats (& tree.ExternParam {
329364 ExParamConst : tree.ExParamConst {FileSize : inputSize },
330- }, tableDef , 0 )
365+ }, tableDef , 0 , context . Background () )
331366 require .Greater (t , stats .BlockNum , int32 (BlockThresholdForOneCN ))
332367 require .Greater (t , stats .Cost , float64 (costThresholdForOneCN ))
333368 require .Equal (t , ExecTypeAP_MULTICN , GetExecType (& Query {
@@ -339,6 +374,135 @@ func TestMakeLoadExternalStatsKeepsLargeLoadMultiCN(t *testing.T) {
339374 }, false , false ))
340375}
341376
377+ func TestMakeLoadExternalStatsUsesFirstLineForTextLoad (t * testing.T ) {
378+ ctx := context .Background ()
379+ fs , err := fileservice .NewMemoryFS ("memory" , fileservice .DisabledCacheConfig , nil )
380+ require .NoError (t , err )
381+ filePath := fileservice .JoinPath (fs .Name (), "wide.csv" )
382+ require .NoError (t , fs .Write (ctx , fileservice.IOVector {
383+ FilePath : filePath ,
384+ Entries : []fileservice.IOEntry {{
385+ Offset : 0 ,
386+ Size : int64 (len ("1,2\n 3,4\n " )),
387+ Data : []byte ("1,2\n 3,4\n " ),
388+ }},
389+ }))
390+
391+ tableDef := & TableDef {
392+ Cols : []* ColDef {
393+ {Name : "a" , Typ : Type {Id : int32 (types .T_varchar ), Width : 65535 }},
394+ {Name : "b" , Typ : Type {Id : int32 (types .T_varchar ), Width : 65535 }},
395+ },
396+ }
397+ inputSize := int64 (4 * options .DefaultBlockMaxRows * (BlockThresholdForOneCN + 1 ))
398+ stats := makeLoadExternalStats (& tree.ExternParam {
399+ ExParamConst : tree.ExParamConst {
400+ Filepath : filePath ,
401+ FileSize : inputSize ,
402+ Format : tree .CSV ,
403+ },
404+ ExParam : tree.ExParam {
405+ FileService : fs ,
406+ Ctx : ctx ,
407+ },
408+ }, tableDef , 0 , context .Background ())
409+
410+ require .Equal (t , float64 (4 ), stats .Rowsize )
411+ require .Greater (t , stats .BlockNum , int32 (BlockThresholdForOneCN ))
412+ require .Equal (t , ExecTypeAP_MULTICN , GetExecType (& Query {
413+ Nodes : []* Node {{
414+ NodeType : pbplan .Node_EXTERNAL_SCAN ,
415+ Stats : stats ,
416+ }},
417+ Steps : []int32 {0 },
418+ }, false , false ))
419+
420+ crlfPath := fileservice .JoinPath (fs .Name (), "crlf.csv" )
421+ require .NoError (t , fs .Write (ctx , fileservice.IOVector {
422+ FilePath : crlfPath ,
423+ Entries : []fileservice.IOEntry {{
424+ Offset : 0 ,
425+ Size : int64 (len ("1,2\r \n 3,4\r \n " )),
426+ Data : []byte ("1,2\r \n 3,4\r \n " ),
427+ }},
428+ }))
429+ stats = makeLoadExternalStats (& tree.ExternParam {
430+ ExParamConst : tree.ExParamConst {
431+ Filepath : crlfPath ,
432+ FileSize : inputSize ,
433+ Format : tree .CSV ,
434+ Tail : & tree.TailParameter {
435+ Lines : & tree.Lines {
436+ TerminatedBy : & tree.Terminated {Value : "\r \n " },
437+ },
438+ },
439+ },
440+ ExParam : tree.ExParam {
441+ FileService : fs ,
442+ Ctx : ctx ,
443+ },
444+ }, tableDef , 0 , context .Background ())
445+ require .Equal (t , float64 (5 ), stats .Rowsize )
446+
447+ ignoredPath := fileservice .JoinPath (fs .Name (), "ignored.csv" )
448+ require .NoError (t , fs .Write (ctx , fileservice.IOVector {
449+ FilePath : ignoredPath ,
450+ Entries : []fileservice.IOEntry {{
451+ Offset : 0 ,
452+ Size : int64 (len ("long_header_value\n 1,2\n 3,4\n " )),
453+ Data : []byte ("long_header_value\n 1,2\n 3,4\n " ),
454+ }},
455+ }))
456+ stats = makeLoadExternalStats (& tree.ExternParam {
457+ ExParamConst : tree.ExParamConst {
458+ Filepath : ignoredPath ,
459+ FileSize : inputSize ,
460+ Format : tree .CSV ,
461+ Tail : & tree.TailParameter {
462+ IgnoredLines : 1 ,
463+ },
464+ },
465+ ExParam : tree.ExParam {
466+ FileService : fs ,
467+ Ctx : ctx ,
468+ },
469+ }, tableDef , 0 , context .Background ())
470+ require .Equal (t , float64 (4 ), stats .Rowsize )
471+
472+ schemaRowSize := GetRowSizeFromTableDef (tableDef , true ) * 0.8
473+ stats = makeLoadExternalStats (& tree.ExternParam {
474+ ExParamConst : tree.ExParamConst {
475+ Filepath : filePath ,
476+ FileSize : inputSize ,
477+ Format : tree .CSV ,
478+ CompressType : tree .GZIP ,
479+ },
480+ ExParam : tree.ExParam {
481+ FileService : fs ,
482+ Ctx : ctx ,
483+ },
484+ }, tableDef , 0 , context .Background ())
485+ require .Equal (t , schemaRowSize , stats .Rowsize )
486+
487+ stats = makeLoadExternalStats (& tree.ExternParam {
488+ ExParamConst : tree.ExParamConst {
489+ Filepath : filePath ,
490+ FileSize : inputSize ,
491+ Format : tree .CSV ,
492+ Tail : & tree.TailParameter {
493+ Lines : & tree.Lines {
494+ TerminatedBy : & tree.Terminated {Value : "|" },
495+ },
496+ },
497+ },
498+ ExParam : tree.ExParam {
499+ FileService : fs ,
500+ Ctx : ctx ,
501+ },
502+ }, tableDef , 0 , context .Background ())
503+ require .Equal (t , schemaRowSize , stats .Rowsize )
504+ }
505+
342506func requireLoadByteHint (t * testing.T , stats * Stats , inputSize int64 ) {
343507 t .Helper ()
344508 estimatedBytes := stats .Cost * stats .Rowsize
0 commit comments