• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Giorgi / DuckDB.NET / 21645923868

03 Feb 2026 07:34PM UTC coverage: 89.45%. First build
21645923868

push

github

Giorgi
Merge branch 'develop'

1203 of 1395 branches covered (86.24%)

Branch coverage included in aggregate %.

125 of 154 new or added lines in 7 files covered. (81.17%)

2375 of 2605 relevant lines covered (91.17%)

566599.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.92
/DuckDB.NET.Data/DuckDBConnection.TableFunction.cs
1
using DuckDB.NET.Data.Common;
2
using DuckDB.NET.Data.Connection;
3
using DuckDB.NET.Data.DataChunk.Writer;
4
using DuckDB.NET.Data.Extensions;
5
using DuckDB.NET.Native;
6
using System;
7
using System.Collections;
8
using System.Collections.Generic;
9
using System.Diagnostics.CodeAnalysis;
10
using System.Runtime.CompilerServices;
11
using System.Runtime.InteropServices;
12

13
namespace DuckDB.NET.Data;
14

15
public record ColumnInfo(string Name, Type Type);
201✔
16

17
public record TableFunction(IReadOnlyList<ColumnInfo> Columns, IEnumerable Data);
156✔
18

19
partial class DuckDBConnection
20
{
21
#if NET8_0_OR_GREATER
22
    [Experimental("DuckDBNET001")]
23
    public void RegisterTableFunction(string name, Func<TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
24
    {
25
        RegisterTableFunctionInternal(name, (_) => resultCallback(), mapperCallback, Array.Empty<Type>());
6✔
26
    }
3✔
27

28
    [Experimental("DuckDBNET001")]
29
    public void RegisterTableFunction<T>(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
30
    {
31
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, typeof(T));
15✔
32
    }
15✔
33

34
    [Experimental("DuckDBNET001")]
35
    public void RegisterTableFunction<T1, T2>(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
36
    {
37
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, typeof(T1), typeof(T2));
9✔
38
    }
9✔
39

40
    [Experimental("DuckDBNET001")]
41
    public void RegisterTableFunction<T1, T2, T3>(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
42
    {
43
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, typeof(T1), typeof(T2), typeof(T3));
3✔
44
    }
3✔
45

46
    [Experimental("DuckDBNET001")]
47
    public void RegisterTableFunction<T1, T2, T3, T4>(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
48
    {
49
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, typeof(T1), typeof(T2), typeof(T3), typeof(T4));
3✔
50
    }
3✔
51

52
    [Experimental("DuckDBNET001")]
53
    public void RegisterTableFunction<T1, T2, T3, T4, T5>(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
54
    {
55
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5));
3✔
56
    }
3✔
57

58
    [Experimental("DuckDBNET001")]
59
    public void RegisterTableFunction<T1, T2, T3, T4, T5, T6>(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
60
    {
61
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6));
×
62
    }
×
63

64
    [Experimental("DuckDBNET001")]
65
    public void RegisterTableFunction<T1, T2, T3, T4, T5, T6, T7>(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
66
    {
67
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7));
×
68
    }
×
69

70
    [Experimental("DuckDBNET001")]
71
    public void RegisterTableFunction<T1, T2, T3, T4, T5, T6, T7, T8>(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback)
72
    {
73
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8));
×
74
    }
×
75

76
    [Experimental("DuckDBNET001")]
77
    public void RegisterTableFunction(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback, params DuckDBType[] parameterTypes)
78
    {
79
        RegisterTableFunctionInternal(name, resultCallback, mapperCallback, parameterTypes);
6✔
80
    }
6✔
81

82
    [Experimental("DuckDBNET001")]
83
    private unsafe void RegisterTableFunctionInternal(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback, params Type[] parameterTypes)
84
    {
85
        var function = NativeMethods.TableFunction.DuckDBCreateTableFunction();
36✔
86
        using (var handle = name.ToUnmanagedString())
36✔
87
        {
88
            NativeMethods.TableFunction.DuckDBTableFunctionSetName(function, handle);
36✔
89
        }
36✔
90

91
        foreach (var type in parameterTypes)
210✔
92
        {
93
            using var logicalType = type.GetLogicalType();
69✔
94
            NativeMethods.TableFunction.DuckDBTableFunctionAddParameter(function, logicalType);
69✔
95
        }
96

97
        var tableFunctionInfo = new TableFunctionInfo(resultCallback, mapperCallback);
36✔
98

99
        NativeMethods.TableFunction.DuckDBTableFunctionSetBind(function, &Bind);
36✔
100
        NativeMethods.TableFunction.DuckDBTableFunctionSetInit(function, &Init);
36✔
101
        NativeMethods.TableFunction.DuckDBTableFunctionSetFunction(function, &TableFunction);
36✔
102
        NativeMethods.TableFunction.DuckDBTableFunctionSetExtraInfo(function, tableFunctionInfo.ToHandle(), &DestroyExtraInfo);
36✔
103

104
        var state = NativeMethods.TableFunction.DuckDBRegisterTableFunction(NativeConnection, function);
36✔
105

106
        if (!state.IsSuccess())
36!
107
        {
108
            throw new InvalidOperationException($"Error registering user defined table function: {name}");
×
109
        }
110

111
        NativeMethods.TableFunction.DuckDBDestroyTableFunction(ref function);
36✔
112
    }
36✔
113

114
    [Experimental("DuckDBNET001")]
115
    private unsafe void RegisterTableFunctionInternal(string name, Func<IReadOnlyList<IDuckDBValueReader>, TableFunction> resultCallback, Action<object?, IDuckDBDataWriter[], ulong> mapperCallback, params DuckDBType[] parameterTypes)
116
    {
117
        var function = NativeMethods.TableFunction.DuckDBCreateTableFunction();
6✔
118
        using (var handle = name.ToUnmanagedString())
6✔
119
        {
120
            NativeMethods.TableFunction.DuckDBTableFunctionSetName(function, handle);
6✔
121
        }
6✔
122

123
        foreach (var duckDBType in parameterTypes)
42✔
124
        {
125
            using var logicalType = NativeMethods.LogicalType.DuckDBCreateLogicalType(duckDBType);
15✔
126
            NativeMethods.TableFunction.DuckDBTableFunctionAddParameter(function, logicalType);
15✔
127
        }
128

129
        var tableFunctionInfo = new TableFunctionInfo(resultCallback, mapperCallback);
6✔
130

131
        NativeMethods.TableFunction.DuckDBTableFunctionSetBind(function, &Bind);
6✔
132
        NativeMethods.TableFunction.DuckDBTableFunctionSetInit(function, &Init);
6✔
133
        NativeMethods.TableFunction.DuckDBTableFunctionSetFunction(function, &TableFunction);
6✔
134
        NativeMethods.TableFunction.DuckDBTableFunctionSetExtraInfo(function, tableFunctionInfo.ToHandle(), &DestroyExtraInfo);
6✔
135

136
        var state = NativeMethods.TableFunction.DuckDBRegisterTableFunction(NativeConnection, function);
6✔
137

138
        if (!state.IsSuccess())
6!
139
        {
NEW
140
            throw new InvalidOperationException($"Error registering user defined table function: {name}");
×
141
        }
142

143
        NativeMethods.TableFunction.DuckDBDestroyTableFunction(ref function);
6✔
144
    }
6✔
145

146
    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
147
    public static unsafe void Bind(IntPtr info)
148
    {
149
        IDuckDBValueReader[] parameters = [];
42✔
150
        try
151
        {
152
            var handle = GCHandle.FromIntPtr(NativeMethods.TableFunction.DuckDBBindGetExtraInfo(info));
42✔
153

154
            if (handle.Target is not TableFunctionInfo functionInfo)
42!
155
            {
156
                throw new InvalidOperationException("User defined table function bind failed. Bind extra info is null");
×
157
            }
158

159
            parameters = new IDuckDBValueReader[NativeMethods.TableFunction.DuckDBBindGetParameterCount(info)];
42✔
160

161
            for (var i = 0; i < parameters.Length; i++)
252✔
162
            {
163
                var value = NativeMethods.TableFunction.DuckDBBindGetParameter(info, (ulong)i);
84✔
164
                parameters[i] = value;
84✔
165
            }
166

167
            var tableFunctionData = functionInfo.Bind(parameters);
42✔
168

169
            foreach (var columnInfo in tableFunctionData.Columns)
162✔
170
            {
171
                using var logicalType = columnInfo.Type.GetLogicalType();
42✔
172
                NativeMethods.TableFunction.DuckDBBindAddResultColumn(info, columnInfo.Name.ToUnmanagedString(), logicalType);
42✔
173
            }
174

175
            var bindData = new TableFunctionBindData(tableFunctionData.Columns, tableFunctionData.Data.GetEnumerator());
39✔
176

177
            NativeMethods.TableFunction.DuckDBBindSetBindData(info, bindData.ToHandle(), &DestroyExtraInfo);
39✔
178
        }
39✔
179
        catch (Exception ex)
180
        {
181
            using var errorMessage = ex.Message.ToUnmanagedString();
3✔
182
            NativeMethods.TableFunction.DuckDBBindSetError(info, errorMessage);
3✔
183
        }
3✔
184
        finally
185
        {
186
            foreach (var parameter in parameters)
252✔
187
            {
188
                (parameter as IDisposable)?.Dispose();
84!
189
            }
190
        }
42✔
191
    }
42✔
192

193
    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
194
    public static void Init(IntPtr info) { }
39✔
195

196
    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
197
    public static void TableFunction(IntPtr info, IntPtr chunk)
198
    {
199
        try
200
        {
201
            var bindData = GCHandle.FromIntPtr(NativeMethods.TableFunction.DuckDBFunctionGetBindData(info));
69✔
202
            var extraInfo = GCHandle.FromIntPtr(NativeMethods.TableFunction.DuckDBFunctionGetExtraInfo(info));
69✔
203

204
            if (bindData.Target is not TableFunctionBindData tableFunctionBindData)
69!
205
            {
206
                throw new InvalidOperationException("User defined table function failed. Function bind data is null");
×
207
            }
208

209
            if (extraInfo.Target is not TableFunctionInfo tableFunctionInfo)
69!
210
            {
211
                throw new InvalidOperationException("User defined table function failed. Function extra info is null");
×
212
            }
213

214
            var dataChunk = new DuckDBDataChunk(chunk);
69✔
215

216
            var writers = new VectorDataWriterBase[tableFunctionBindData.Columns.Count];
69✔
217
            for (var columnIndex = 0; columnIndex < tableFunctionBindData.Columns.Count; columnIndex++)
288✔
218
            {
219
                var column = tableFunctionBindData.Columns[columnIndex];
75✔
220
                var vector = NativeMethods.DataChunks.DuckDBDataChunkGetVector(dataChunk, columnIndex);
75✔
221

222
                using var logicalType = column.Type.GetLogicalType();
75✔
223
                writers[columnIndex] = VectorDataWriterFactory.CreateWriter(vector, logicalType);
75✔
224
            }
225

226
            ulong size = 0;
69✔
227

228
            for (; size < DuckDBGlobalData.VectorSize; size++)
909✔
229
            {
230
                if (tableFunctionBindData.DataEnumerator.MoveNext())
489✔
231
                {
232
                    tableFunctionInfo.Mapper(tableFunctionBindData.DataEnumerator.Current, writers, size);
423✔
233
                }
234
                else
235
                {
236
                    break;
237
                }
238
            }
239

240
            NativeMethods.DataChunks.DuckDBDataChunkSetSize(dataChunk, size);
66✔
241
        }
66✔
242
        catch (Exception ex)
243
        {
244
            using var errorMessage = ex.Message.ToUnmanagedString();
3✔
245
            NativeMethods.TableFunction.DuckDBFunctionSetError(info, errorMessage);
3✔
246
        }
3✔
247
    }
69✔
248
#endif
249
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc