@@ -471,4 +471,107 @@ public void RegisterTableFunctionWithCardinality_AppearsInQueryPlan(int cardinal
471471
472472 reported . Should ( ) . Be ( cardinality . ToString ( ) ) ;
473473 }
474+
475+ [ Fact ]
476+ public void RegisterTableFunctionWithListColumn ( )
477+ {
478+ var sourceData = new List < List < int > >
479+ {
480+ new ( ) { 1 , 2 , 3 } ,
481+ new ( ) { 4 , 5 } ,
482+ new ( ) { } ,
483+ null ,
484+ } ;
485+
486+ Connection . RegisterTableFunction ( "list_func" , ( ) =>
487+ {
488+ return new TableFunction ( new List < ColumnInfo >
489+ {
490+ new ( "numbers" , typeof ( List < int > ) ) ,
491+ } , sourceData ) ;
492+ } , ( item , writers , rowIndex ) =>
493+ {
494+ writers [ 0 ] . WriteValue ( ( List < int > ) item , rowIndex ) ;
495+ } ) ;
496+
497+ using var command = Connection . CreateCommand ( ) ;
498+ command . CommandText = "SELECT numbers FROM list_func();" ;
499+ using var reader = command . ExecuteReader ( ) ;
500+
501+ reader . Read ( ) ;
502+ reader . GetFieldValue < List < int > > ( 0 ) . Should ( ) . BeEquivalentTo ( new List < int > { 1 , 2 , 3 } ) ;
503+
504+ reader . Read ( ) ;
505+ reader . GetFieldValue < List < int > > ( 0 ) . Should ( ) . BeEquivalentTo ( new List < int > { 4 , 5 } ) ;
506+
507+ reader . Read ( ) ;
508+ reader . GetFieldValue < List < int > > ( 0 ) . Should ( ) . BeEquivalentTo ( new List < int > ( ) ) ;
509+
510+ reader . Read ( ) ;
511+ reader . IsDBNull ( 0 ) . Should ( ) . BeTrue ( ) ;
512+
513+ reader . Read ( ) . Should ( ) . BeFalse ( ) ;
514+ }
515+
516+ [ Fact ]
517+ public void RegisterTableFunctionWithListColumn_ListHasAny ( )
518+ {
519+ var sourceData = new List < List < int > >
520+ {
521+ new ( ) { 1 , 2 , 3 } ,
522+ new ( ) { 4 , 5 } ,
523+ new ( ) { 6 , 7 , 8 , 9 } ,
524+ new ( ) { } ,
525+ } ;
526+
527+ Connection . RegisterTableFunction ( "list_func_has_any" , ( ) =>
528+ {
529+ return new TableFunction ( new List < ColumnInfo >
530+ {
531+ new ( "numbers" , typeof ( List < int > ) ) ,
532+ } , sourceData ) ;
533+ } , ( item , writers , rowIndex ) =>
534+ {
535+ writers [ 0 ] . WriteValue ( ( List < int > ) item , rowIndex ) ;
536+ } ) ;
537+
538+ var data = Connection . Query < bool > ( "SELECT list_has_any(numbers, [3]) FROM list_func_has_any();" ) . ToList ( ) ;
539+ data . Should ( ) . BeEquivalentTo ( [ true , false , false , false ] ) ;
540+ }
541+
542+ [ Fact ]
543+ public void RegisterTableFunctionWithNestedListColumn ( )
544+ {
545+ var sourceData = new List < List < List < int ? > > >
546+ {
547+ new ( ) { new ( ) { 1 , 2 } , new ( ) { 3 , null , 5 } } ,
548+ new ( ) { new ( ) { 10 } , null , new ( ) { 20 , 30 } , new ( ) { 40 } } ,
549+ } ;
550+
551+ Connection . RegisterTableFunction ( "list_func_nested" , ( ) =>
552+ {
553+ return new TableFunction ( new List < ColumnInfo >
554+ {
555+ new ( "nested" , typeof ( List < List < int ? > > ) ) ,
556+ } , sourceData ) ;
557+ } , ( item , writers , rowIndex ) =>
558+ {
559+ writers [ 0 ] . WriteValue ( ( List < List < int ? > > ) item , rowIndex ) ;
560+ } ) ;
561+
562+ // flatten reduces one level of nesting
563+ using var command = Connection . CreateCommand ( ) ;
564+ command . CommandText = "SELECT flatten(nested) FROM list_func_nested();" ;
565+ using var reader = command . ExecuteReader ( ) ;
566+
567+ reader . Read ( ) ;
568+ reader . GetFieldValue < List < int ? > > ( 0 ) . Should ( ) . BeEquivalentTo ( [ 1 , 2 , 3 , ( int ? ) null , 5 ] ,
569+ options => options . WithStrictOrdering ( ) ) ;
570+
571+ reader . Read ( ) ;
572+ reader . GetFieldValue < List < int ? > > ( 0 ) . Should ( ) . BeEquivalentTo ( [ 10 , 20 , 30 , 40 ] ,
573+ options => options . WithStrictOrdering ( ) ) ;
574+
575+ reader . Read ( ) . Should ( ) . BeFalse ( ) ;
576+ }
474577}
0 commit comments