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

Giorgi / DuckDB.NET / 14954078164

11 May 2025 08:41AM UTC coverage: 89.843% (+0.005%) from 89.838%
14954078164

Pull #265

github

web-flow
Merge e4aa5f704 into e9a64a0f9
Pull Request #265: Add overload to register parameterless scalar function

1094 of 1255 branches covered (87.17%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

9 existing lines in 1 file now uncovered.

2117 of 2319 relevant lines covered (91.29%)

754760.71 hits per line

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

75.71
/DuckDB.NET.Data/DuckDBConnection.ScalarFunction.cs
1
using DuckDB.NET.Data.Connection;
2
using DuckDB.NET.Data.DataChunk.Reader;
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.Generic;
8
using System.Diagnostics.CodeAnalysis;
9
using System.Runtime.CompilerServices;
10
using System.Runtime.InteropServices;
11

12
namespace DuckDB.NET.Data;
13

14
partial class DuckDBConnection
15
{
16
#if NET8_0_OR_GREATER
17
    [Experimental("DuckDBNET001")]
18
    public void RegisterScalarFunction<TResult>(string name, Action<IDuckDBDataWriter, ulong> action, bool isPureFunction = false)
19
    {
20
        RegisterScalarMethod(name, (_, w, index) => action(w, index), TypeExtensions.GetLogicalType<TResult>(), varargs: false, !isPureFunction);
6✔
21
    }
3✔
22

23
    [Obsolete("Prefer using RegisterScalarFunction<TResult>(string name, Action<IDuckDBDataWriter, ulong> action, bool isPureFunction = false)")]
24
    [Experimental("DuckDBNET001")]
25
#pragma warning disable DuckDBNET001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
26
    public void RegisterScalarFunction<TResult>(string name, Action<IReadOnlyList<IDuckDBDataReader>, IDuckDBDataWriter, ulong> action, bool isPureFunction = false)
27
    {
28

29
        RegisterScalarMethod(name, action, TypeExtensions.GetLogicalType<TResult>(), varargs: false, !isPureFunction);
3✔
30
    }
3✔
31
#pragma warning restore DuckDBNET001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
32

33
    [Experimental("DuckDBNET001")]
34
    public void RegisterScalarFunction<T, TResult>(string name, Action<IReadOnlyList<IDuckDBDataReader>, IDuckDBDataWriter, ulong> action, bool isPureFunction = true, bool @params = false)
35
    {
36
        RegisterScalarMethod(name, action, TypeExtensions.GetLogicalType<TResult>(), @params, !isPureFunction, TypeExtensions.GetLogicalType<T>());
9✔
37
    }
9✔
38

39
    [Experimental("DuckDBNET001")]
40
    public void RegisterScalarFunction<T1, T2, TResult>(string name, Action<IReadOnlyList<IDuckDBDataReader>, IDuckDBDataWriter, ulong> action, bool isPureFunction = true)
41
    {
42
        RegisterScalarMethod(name, action, TypeExtensions.GetLogicalType<TResult>(), varargs: false, !isPureFunction,
6✔
43
                              TypeExtensions.GetLogicalType<T1>(), 
6✔
44
                              TypeExtensions.GetLogicalType<T2>());
6✔
45
    }
6✔
46

47
    [Experimental("DuckDBNET001")]
48
    public void RegisterScalarFunction<T1, T2, T3, TResult>(string name, Action<IReadOnlyList<IDuckDBDataReader>, IDuckDBDataWriter, ulong> action, bool isPureFunction = true)
49
    {
50
        RegisterScalarMethod(name, action, TypeExtensions.GetLogicalType<TResult>(), varargs: false, !isPureFunction,
×
51
                              TypeExtensions.GetLogicalType<T1>(),
×
52
                              TypeExtensions.GetLogicalType<T2>(),
×
53
                              TypeExtensions.GetLogicalType<T3>());
×
54
    }
×
55

56
    [Experimental("DuckDBNET001")]
57
    public void RegisterScalarFunction<T1, T2, T3, T4, TResult>(string name, Action<IReadOnlyList<IDuckDBDataReader>, IDuckDBDataWriter, ulong> action, bool isPureFunction = true)
58
    {
UNCOV
59
        RegisterScalarMethod(name, action, TypeExtensions.GetLogicalType<TResult>(), varargs: false, !isPureFunction,
×
UNCOV
60
                              TypeExtensions.GetLogicalType<T1>(),
×
UNCOV
61
                              TypeExtensions.GetLogicalType<T2>(),
×
UNCOV
62
                              TypeExtensions.GetLogicalType<T3>(),
×
UNCOV
63
                              TypeExtensions.GetLogicalType<T4>());
×
UNCOV
64
    }
×
65

66
    [Experimental("DuckDBNET001")]
67
    private unsafe void RegisterScalarMethod(string name, Action<IReadOnlyList<IDuckDBDataReader>, IDuckDBDataWriter, ulong> action, DuckDBLogicalType returnType,
68
                                             bool varargs, bool @volatile, params DuckDBLogicalType[] parameterTypes)
69
    {
70
        var function = NativeMethods.ScalarFunction.DuckDBCreateScalarFunction();
21✔
71
        using (var handle = name.ToUnmanagedString())
21✔
72
        {
73
            NativeMethods.ScalarFunction.DuckDBScalarFunctionSetName(function, handle);
21✔
74
        }
21✔
75

76
        if (varargs)
21✔
77
        {
78
            if (parameterTypes.Length != 1)
3!
79
            {
UNCOV
80
                throw new InvalidOperationException("Cannot use params with multiple parameters");
×
81
            }
82

83
            NativeMethods.ScalarFunction.DuckDBScalarFunctionSetVarargs(function, parameterTypes[0]);
3✔
84
        }
85
        else
86
        {
87
            foreach (var type in parameterTypes)
72✔
88
            {
89
                NativeMethods.ScalarFunction.DuckDBScalarFunctionAddParameter(function, type);
18✔
90
                type.Dispose();
18✔
91
            }
92
        }
93

94
        if (@volatile)
21✔
95
        {
96
            NativeMethods.ScalarFunction.DuckDBScalarFunctionSetVolatile(function);
12✔
97
        }
98

99
        NativeMethods.ScalarFunction.DuckDBScalarFunctionSetReturnType(function, returnType);
21✔
100
        NativeMethods.ScalarFunction.DuckDBScalarFunctionSetFunction(function, &ScalarFunctionCallback);
21✔
101

102
        var info = new ScalarFunctionInfo(returnType, action);
21✔
103

104
        NativeMethods.ScalarFunction.DuckDBScalarFunctionSetExtraInfo(function, info.ToHandle(), &DestroyExtraInfo);
21✔
105

106
        var state = NativeMethods.ScalarFunction.DuckDBRegisterScalarFunction(NativeConnection, function);
21✔
107

108
        NativeMethods.ScalarFunction.DuckDBDestroyScalarFunction(out function);
21✔
109

110
        if (!state.IsSuccess())
21!
111
        {
UNCOV
112
            throw new InvalidOperationException($"Error registering user defined scalar function: {name}");
×
113
        }
114
    }
21✔
115

116
    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
117
    private static void ScalarFunctionCallback(IntPtr info, IntPtr chunk, IntPtr outputVector)
118
    {
119
        var dataChunk = new DuckDBDataChunk(chunk);
81✔
120

121
        var chunkSize = NativeMethods.DataChunks.DuckDBDataChunkGetSize(dataChunk);
81✔
122
        var handle = GCHandle.FromIntPtr(NativeMethods.ScalarFunction.DuckDBScalarFunctionGetExtraInfo(info));
81✔
123

124
        if (handle.Target is not ScalarFunctionInfo functionInfo)
81!
125
        {
UNCOV
126
            throw new InvalidOperationException("User defined scalar function execution failed. Function extra info is null");
×
127
        }
128

129
        var readers = new VectorDataReaderBase[NativeMethods.DataChunks.DuckDBDataChunkGetColumnCount(dataChunk)];
81✔
130

131
        for (var index = 0; index < readers.Length; index++)
360✔
132
        {
133
            var vector = NativeMethods.DataChunks.DuckDBDataChunkGetVector(dataChunk, index);
99✔
134
            readers[index] = VectorDataReaderFactory.CreateReader(vector, NativeMethods.Vectors.DuckDBVectorGetColumnType(vector));
99✔
135
        }
136

137
        var writer = VectorDataWriterFactory.CreateWriter(outputVector, functionInfo.ReturnType);
81✔
138

139
        functionInfo.Action(readers, writer, chunkSize);
81✔
140
    }
81✔
141

142
    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
143
    private static void DestroyExtraInfo(IntPtr pointer) => pointer.FreeHandle();
84✔
144
#endif
145
}
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