1- using System ;
2- using System . Runtime . CompilerServices ;
3- using System . Runtime . InteropServices ;
4- using DuckDB . NET . Data . Extensions ;
1+ using DuckDB . NET . Data . Extensions ;
52using DuckDB . NET . Data . Internal ;
63using DuckDB . NET . Native ;
4+ using System ;
5+ using System . Collections ;
6+ using System . Collections . Generic ;
7+ using System . Diagnostics . CodeAnalysis ;
8+ using System . Linq ;
9+ using System . Runtime . CompilerServices ;
10+ using System . Runtime . InteropServices ;
11+ using DuckDB . NET . Data . Internal . Writer ;
12+ using DuckDB . NET . Data . Writer ;
713
814namespace DuckDB . NET . Data ;
915
16+ public record ColumnInfo ( string Name , Type Type )
17+ {
18+ }
19+
20+ public record TableFunction ( IReadOnlyList < ColumnInfo > Columns , IEnumerable Data )
21+ {
22+ }
23+
1024partial class DuckDBConnection
1125{
12- public unsafe void RegisterTableFunction < T , TResult > ( string name )
26+ #if NET8_0_OR_GREATER
27+ [ Experimental ( "DuckDBNET001" ) ]
28+ public unsafe void RegisterTableFunction < T > ( string name , Func < IEnumerable < IDuckDBValueReader > , TableFunction > resultCallback , Action < object ? , IDuckDBDataWriter [ ] > mapperCallback )
1329 {
1430 var function = NativeMethods . TableFunction . DuckDBCreateTableFunction ( ) ;
1531 NativeMethods . TableFunction . DuckDBTableFunctionSetName ( function , name . ToUnmanagedString ( ) ) ;
@@ -19,20 +35,105 @@ public unsafe void RegisterTableFunction<T, TResult>(string name)
1935 NativeMethods . TableFunction . DuckDBTableFunctionAddParameter ( function , logicalType ) ;
2036 }
2137
38+ var tableFunctionInfo = new TableFunctionInfo ( resultCallback , mapperCallback ) ;
39+
2240 NativeMethods . TableFunction . DuckDBTableFunctionSetBind ( function , & Bind ) ;
41+ NativeMethods . TableFunction . DuckDBTableFunctionSetInit ( function , & Init ) ;
42+ NativeMethods . TableFunction . DuckDBTableFunctionSetFunction ( function , & TableFunction ) ;
43+ NativeMethods . TableFunction . DuckDBTableFunctionSetExtraInfo ( function , tableFunctionInfo . ToHandle ( ) , & DestroyExtraInfo ) ;
44+
45+ var state = NativeMethods . TableFunction . DuckDBRegisterTableFunction ( NativeConnection , function ) ;
46+
47+ if ( ! state . IsSuccess ( ) )
48+ {
49+ throw new InvalidOperationException ( $ "Error registering user defined table function: { name } ") ;
50+ }
51+
52+ NativeMethods . TableFunction . DuckDBDestroyTableFunction ( out function ) ;
2353 }
2454
2555 [ UnmanagedCallersOnly ( CallConvs = [ typeof ( CallConvCdecl ) ] ) ]
2656 public static unsafe void Bind ( IntPtr info )
2757 {
28- var parameters = new object [ NativeMethods . TableFunction . DuckDBBindGetParameterCount ( info ) ] ;
58+ var handle = GCHandle . FromIntPtr ( NativeMethods . TableFunction . DuckDBBindGetExtraInfo ( info ) ) ;
59+
60+ if ( handle . Target is not TableFunctionInfo functionInfo )
61+ {
62+ throw new InvalidOperationException ( "User defined table function bind failed. Bind extra info is null" ) ;
63+ }
64+
65+ var parameters = new IDuckDBValueReader [ NativeMethods . TableFunction . DuckDBBindGetParameterCount ( info ) ] ;
2966
3067 for ( var i = 0 ; i < parameters . Length ; i ++ )
3168 {
32- using var value = NativeMethods . TableFunction . DuckDBBindGetParameter ( info , ( ulong ) i ) ;
33- parameters [ i ] = NativeMethods . Value . DuckDBGetInt32 ( value ) ;
69+ var value = NativeMethods . TableFunction . DuckDBBindGetParameter ( info , ( ulong ) i ) ;
70+ parameters [ i ] = value ;
71+ }
72+
73+ var tableFunctionData = functionInfo . Bind ( parameters ) ;
74+
75+ foreach ( var parameter in parameters )
76+ {
77+ ( parameter as IDisposable ) ? . Dispose ( ) ;
78+ }
79+
80+ foreach ( var columnInfo in tableFunctionData . Columns )
81+ {
82+ using var logicalType = DuckDBTypeMap . GetLogicalType ( columnInfo . Type ) ;
83+ NativeMethods . TableFunction . DuckDBBindAddResultColumn ( info , columnInfo . Name . ToUnmanagedString ( ) , logicalType ) ;
84+ }
85+
86+ var bindData = new TableFunctionBindData ( tableFunctionData . Columns , tableFunctionData . Data . GetEnumerator ( ) ) ;
87+
88+ NativeMethods . TableFunction . DuckDBBindSetBindData ( info , bindData . ToHandle ( ) , & DestroyExtraInfo ) ;
89+ }
90+
91+ [ UnmanagedCallersOnly ( CallConvs = [ typeof ( CallConvCdecl ) ] ) ]
92+ public static unsafe void Init ( IntPtr info ) { }
93+
94+ [ UnmanagedCallersOnly ( CallConvs = [ typeof ( CallConvCdecl ) ] ) ]
95+ public static unsafe void TableFunction ( IntPtr info , IntPtr chunk )
96+ {
97+ var bindData = GCHandle . FromIntPtr ( NativeMethods . TableFunction . DuckDBFunctionGetBindData ( info ) ) ;
98+ var extraInfo = GCHandle . FromIntPtr ( NativeMethods . TableFunction . DuckDBFunctionGetExtraInfo ( info ) ) ;
99+
100+ if ( bindData . Target is not TableFunctionBindData tableFunctionBindData )
101+ {
102+ throw new InvalidOperationException ( "User defined table function failed. Function bind data is null" ) ;
103+ }
104+
105+ if ( extraInfo . Target is not TableFunctionInfo tableFunctionInfo )
106+ {
107+ throw new InvalidOperationException ( "User defined table function failed. Function extra info is null" ) ;
108+ }
109+
110+ var dataChunk = new DuckDBDataChunk ( chunk ) ;
111+
112+ var writers = new VectorDataWriterBase [ tableFunctionBindData . Columns . Count ] ;
113+ for ( var columnIndex = 0 ; columnIndex < tableFunctionBindData . Columns . Count ; columnIndex ++ )
114+ {
115+ var column = tableFunctionBindData . Columns [ columnIndex ] ;
116+ var vector = NativeMethods . DataChunks . DuckDBDataChunkGetVector ( dataChunk , columnIndex ) ;
117+
118+ using var logicalType = DuckDBTypeMap . GetLogicalType ( column . Type ) ;
119+ writers [ columnIndex ] = VectorDataWriterFactory . CreateWriter ( vector , logicalType ) ;
120+ }
121+
122+ ulong size = 0 ;
123+
124+ for ( ; size < DuckDBGlobalData . VectorSize ; size ++ )
125+ {
126+ if ( tableFunctionBindData . DataEnumerator . MoveNext ( ) )
127+ {
128+ tableFunctionInfo . Mapper ( tableFunctionBindData . DataEnumerator . Current , writers ) ;
129+ }
130+ else
131+ {
132+ break ;
133+ }
34134 }
35135
36- NativeMethods . TableFunction . DuckDBBindSetBindData ( info , parameters . ToHandle ( ) , & DestroyExtraInfo ) ;
136+ NativeMethods . DataChunks . DuckDBDataChunkSetSize ( dataChunk , size ) ;
37137 }
138+ #endif
38139}
0 commit comments