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

Giorgi / DuckDB.NET / 28126041613

24 Jun 2026 08:00PM UTC coverage: 89.485% (+0.1%) from 89.339%
28126041613

push

github

Giorgi
Use duckdb_appender_error_data for appender error handling

Switch the appender from duckdb_appender_error (plain string) to
duckdb_appender_error_data, which exposes both the message and the
DuckDB error type. Route all appender error sites through the existing
DuckDBErrorData.ThrowOnError extension (message prefix now optional),
so appender exceptions carry ErrorType, consistent with the Arrow paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWKN1SKSTFDyeqSrA4dfYT

1362 of 1583 branches covered (86.04%)

Branch coverage included in aggregate %.

2 of 6 new or added lines in 4 files covered. (33.33%)

1 existing line in 1 file now uncovered.

2859 of 3134 relevant lines covered (91.23%)

421690.1 hits per line

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

92.86
/DuckDB.NET.Data/DuckDBAppenderRow.cs
1
using DuckDB.NET.Data.DataChunk.Writer;
2

3
namespace DuckDB.NET.Data;
4

5
public class DuckDBAppenderRow : IDuckDBAppenderRow
6
{
7
    private int columnIndex = 0;
8
    private readonly string qualifiedTableName;
9
    private readonly VectorDataWriterBase[] vectorWriters;
10
    private readonly ulong rowIndex;
11
    private readonly DuckDBDataChunk dataChunk;
12
    private readonly Native.DuckDBAppender nativeAppender;
13

14
    internal DuckDBAppenderRow(string qualifiedTableName, VectorDataWriterBase[] vectorWriters,
436,200✔
15
                               ulong rowIndex, DuckDBDataChunk dataChunk, Native.DuckDBAppender nativeAppender)
436,200✔
16
    {
17
        this.qualifiedTableName = qualifiedTableName;
436,200✔
18
        this.vectorWriters = vectorWriters;
436,200✔
19
        this.rowIndex = rowIndex;
436,200✔
20
        this.dataChunk = dataChunk;
436,200✔
21
        this.nativeAppender = nativeAppender;
436,200✔
22
    }
436,200✔
23

24
    public void EndRow()
25
    {
26
        if (columnIndex < vectorWriters.Length)
436,182✔
27
        {
28
            throw new InvalidOperationException($"The table {qualifiedTableName} has {vectorWriters.Length} columns but you specified only {columnIndex} values");
3✔
29
        }
30
    }
436,179✔
31

32
    public IDuckDBAppenderRow AppendNullValue()
33
    {
34
        CheckColumnAccess();
81✔
35
        vectorWriters[columnIndex].WriteNull(rowIndex);
81✔
36
        columnIndex++;
81✔
37
        return this;
81✔
38
    }
39

40
    public IDuckDBAppenderRow AppendValue(bool? value) => AppendValueInternalStruct(value);
69✔
41

42
    public IDuckDBAppenderRow AppendValue(byte[]? value) => AppendSpan(value);
12✔
43

44
    public IDuckDBAppenderRow AppendValue(Span<byte> value) => AppendSpan(value);
3✔
45

46
    public IDuckDBAppenderRow AppendValue(string? value) => AppendValueInternalClass(value);
51,267✔
47

48
    public IDuckDBAppenderRow AppendValue(decimal? value) => AppendValueInternalStruct(value);
327✔
49

50
    public IDuckDBAppenderRow AppendValue(Guid? value) => AppendValueInternalStruct(value);
105,003✔
51

52
    public IDuckDBAppenderRow AppendValue(BigInteger? value) => AppendValueInternalStruct(value);
60✔
53

54
    #region Append Signed Int
55

56
    public IDuckDBAppenderRow AppendValue(sbyte? value) => AppendValueInternalStruct(value);
75,084✔
57

58
    public IDuckDBAppenderRow AppendValue(short? value) => AppendValueInternalStruct(value);
60✔
59

60
    public IDuckDBAppenderRow AppendValue(int? value) => AppendValueInternalStruct(value);
330,963✔
61

62
    public IDuckDBAppenderRow AppendValue(long? value) => AppendValueInternalStruct(value);
60✔
63

64
    #endregion
65

66
    #region Append Unsigned Int
67

68
    public IDuckDBAppenderRow AppendValue(byte? value) => AppendValueInternalStruct(value);
66✔
69

70
    public IDuckDBAppenderRow AppendValue(ushort? value) => AppendValueInternalStruct(value);
60✔
71

72
    public IDuckDBAppenderRow AppendValue(uint? value) => AppendValueInternalStruct(value);
60✔
73

74
    public IDuckDBAppenderRow AppendValue(ulong? value) => AppendValueInternalStruct(value);
60✔
75

76
    #endregion
77

78
    #region Append Enum
79

80
    public IDuckDBAppenderRow AppendValue<TEnum>(TEnum? value) where TEnum : Enum
81
    {
82
        CheckColumnAccess();
15✔
83

84
        if (value != null)
15!
85
        {
86
            vectorWriters[columnIndex].WriteValue(value, rowIndex);
15✔
87
        }
88
        else
89
        {
90
            vectorWriters[columnIndex].WriteNull(rowIndex);
×
91
        }
92

93
        columnIndex++;
12✔
94
        return this;
12✔
95
    }
96

97
    #endregion
98

99
    #region Append Float
100

101
    public IDuckDBAppenderRow AppendValue(float? value) => AppendValueInternalStruct(value);
66✔
102

103
    public IDuckDBAppenderRow AppendValue(double? value) => AppendValueInternalStruct(value);
120✔
104

105
    #endregion
106

107
    #region Append Temporal
108
    public IDuckDBAppenderRow AppendValue(DateOnly? value) => AppendValueInternalStruct(value);
×
109

110
    public IDuckDBAppenderRow AppendValue(TimeOnly? value) => AppendValueInternalStruct(value);
×
111

112
    public IDuckDBAppenderRow AppendValue(DuckDBDateOnly? value) => AppendValueInternalStruct(value);
120✔
113

114
    public IDuckDBAppenderRow AppendValue(DuckDBTimeOnly? value) => AppendValueInternalStruct(value);
60✔
115

116
    public IDuckDBAppenderRow AppendValue(DateTime? value) => AppendValueInternalStruct(value);
15,336✔
117

118
    public IDuckDBAppenderRow AppendValue(DateTimeOffset? value) => AppendValueInternalStruct(value);
120✔
119

120
    public IDuckDBAppenderRow AppendValue(TimeSpan? value) => AppendValueInternalStruct(value);
60✔
121

122
    #endregion
123

124
    #region Composite Types
125

126
    public IDuckDBAppenderRow AppendValue<T>(IEnumerable<T>? value) => AppendValueInternalClass(value);
498,006✔
127

128
    #endregion
129

130
    public IDuckDBAppenderRow AppendDefault()
131
    {
132
        CheckColumnAccess();
75,015✔
133

134
        var state = NativeMethods.Appender.DuckDBAppendDefaultToChunk(nativeAppender, dataChunk, columnIndex, rowIndex);
75,015✔
135

136
        if (state == DuckDBState.Error)
75,015!
137
        {
NEW
138
            NativeMethods.Appender.DuckDBAppenderErrorData(nativeAppender).ThrowOnError();
×
139
        }
140

141
        columnIndex++;
75,015✔
142
        return this;
75,015✔
143
    }
144

145
    private DuckDBAppenderRow AppendValueInternalStruct<T>(T? value) where T : struct
146
    {
147
        CheckColumnAccess();
527,754✔
148

149
        if (value.HasValue)
527,754✔
150
        {
151
            vectorWriters[columnIndex].WriteValue(value.Value, rowIndex);
527,751✔
152
        }
153
        else
154
        {
155
            vectorWriters[columnIndex].WriteNull(rowIndex);
3✔
156
        }
157

158
        columnIndex++;
527,751✔
159
        return this;
527,751✔
160
    }
161

162
    private DuckDBAppenderRow AppendValueInternalClass<T>(T? value) where T : class
163
    {
164
        CheckColumnAccess();
549,273✔
165

166
        vectorWriters[columnIndex].WriteValue(value, rowIndex);
549,270✔
167

168
        columnIndex++;
549,261✔
169
        return this;
549,261✔
170
    }
171

172
    private unsafe IDuckDBAppenderRow AppendSpan(Span<byte> val)
173
    {
174
        if (val == null)
15✔
175
        {
176
            return AppendNullValue();
3✔
177
        }
178

179
        CheckColumnAccess();
12✔
180

181
        fixed (byte* pSource = val)
12✔
182
        {
183
            vectorWriters[columnIndex].AppendBlob(pSource, val.Length, rowIndex);
12✔
184
        }
185

186
        columnIndex++;
12✔
187
        return this;
12✔
188
    }
189

190
    private void CheckColumnAccess()
191
    {
192
        if (columnIndex >= vectorWriters.Length)
1,152,150✔
193
        {
194
            throw new IndexOutOfRangeException($"The table {qualifiedTableName} has {vectorWriters.Length} columns but you are trying to append value for column {columnIndex + 1}");
3✔
195
        }
196
    }
1,152,147✔
197
}
198

199
public interface IDuckDBAppenderRow
200
{
201
    void EndRow();
202
    IDuckDBAppenderRow AppendNullValue();
203
    IDuckDBAppenderRow AppendValue(bool? value);
204
    IDuckDBAppenderRow AppendValue(byte[]? value);
205
    IDuckDBAppenderRow AppendValue(Span<byte> value);
206
    IDuckDBAppenderRow AppendValue(string? value);
207
    IDuckDBAppenderRow AppendValue(decimal? value);
208
    IDuckDBAppenderRow AppendValue(Guid? value);
209
    IDuckDBAppenderRow AppendValue(BigInteger? value);
210
    IDuckDBAppenderRow AppendValue(sbyte? value);
211
    IDuckDBAppenderRow AppendValue(short? value);
212
    IDuckDBAppenderRow AppendValue(int? value);
213
    IDuckDBAppenderRow AppendValue(long? value);
214
    IDuckDBAppenderRow AppendValue(byte? value);
215
    IDuckDBAppenderRow AppendValue(ushort? value);
216
    IDuckDBAppenderRow AppendValue(uint? value);
217
    IDuckDBAppenderRow AppendValue(ulong? value);
218
    IDuckDBAppenderRow AppendValue<TEnum>(TEnum? value) where TEnum : Enum;
219
    IDuckDBAppenderRow AppendValue(float? value);
220
    IDuckDBAppenderRow AppendValue(double? value);
221
    IDuckDBAppenderRow AppendValue(DuckDBDateOnly? value);
222
    IDuckDBAppenderRow AppendValue(DuckDBTimeOnly? value);
223
    IDuckDBAppenderRow AppendValue(DateTime? value);
224
    IDuckDBAppenderRow AppendValue(DateTimeOffset? value);
225
    IDuckDBAppenderRow AppendValue(TimeSpan? value);
226
    IDuckDBAppenderRow AppendValue<T>(IEnumerable<T>? value);
227
    IDuckDBAppenderRow AppendDefault();
228
}
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