-
Notifications
You must be signed in to change notification settings - Fork 874
Expand file tree
/
Copy pathNpgsqlParameter`.cs
More file actions
150 lines (131 loc) · 4.66 KB
/
NpgsqlParameter`.cs
File metadata and controls
150 lines (131 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Data;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Npgsql.Internal;
using NpgsqlTypes;
namespace Npgsql;
/// <summary>
/// A generic version of <see cref="NpgsqlParameter"/> which provides more type safety and
/// avoids boxing of value types. Use <see cref="TypedValue"/> instead of <see cref="NpgsqlParameter.Value"/>.
/// </summary>
/// <typeparam name="T">The type of the value that will be stored in the parameter.</typeparam>
public sealed class NpgsqlParameter<T> : NpgsqlParameter
{
T? _typedValue;
/// <summary>
/// Gets or sets the strongly-typed value of the parameter.
/// </summary>
public T? TypedValue
{
get => _typedValue;
set
{
if (typeof(T) == typeof(object) && (value is null || _typedValue?.GetType() != value.GetType()))
ResetTypeInfo();
else
ResetBindingInfo();
_typedValue = value;
}
}
/// <summary>
/// Gets or sets the value of the parameter. This delegates to <see cref="TypedValue"/>.
/// </summary>
public override object? Value
{
get => TypedValue;
set => TypedValue = (T)value!;
}
private protected override Type StaticValueType => typeof(T);
#region Constructors
/// <summary>
/// Initializes a new instance of <see cref="NpgsqlParameter{T}" />.
/// </summary>
public NpgsqlParameter() { }
/// <summary>
/// Initializes a new instance of <see cref="NpgsqlParameter{T}" /> with a parameter name and value.
/// </summary>
public NpgsqlParameter(string parameterName, T value)
{
ParameterName = parameterName;
TypedValue = value;
}
/// <summary>
/// Initializes a new instance of <see cref="NpgsqlParameter{T}" /> with a parameter name and type.
/// </summary>
public NpgsqlParameter(string parameterName, NpgsqlDbType npgsqlDbType)
{
ParameterName = parameterName;
NpgsqlDbType = npgsqlDbType;
}
/// <summary>
/// Initializes a new instance of <see cref="NpgsqlParameter{T}" /> with a parameter name and type.
/// </summary>
public NpgsqlParameter(string parameterName, DbType dbType)
{
ParameterName = parameterName;
DbType = dbType;
}
#endregion Constructors
private protected override PgConverterResolution ResolveConverter(PgTypeInfo typeInfo)
{
if (typeof(T) == typeof(object) || TypeInfo!.IsBoxing)
return base.ResolveConverter(typeInfo);
_asObject = false;
return typeInfo.GetResolution(TypedValue);
}
// We ignore allowNullReference, it's just there to control the base implementation.
private protected override void BindCore(bool allowNullReference = false)
{
if (_asObject)
{
// If we're object typed we should not support null.
base.BindCore(typeof(T) != typeof(object));
return;
}
var value = TypedValue;
Debug.Assert(Converter is PgConverter<T>);
if (TypeInfo!.Bind(Unsafe.As<PgConverter<T>>(Converter), value, out var size, out _writeState, out var dataFormat) is { } info)
{
WriteSize = size;
_bufferRequirement = info.BufferRequirement;
}
else
{
WriteSize = -1;
_bufferRequirement = default;
}
Format = dataFormat;
}
private protected override ValueTask WriteValue(bool async, PgWriter writer, CancellationToken cancellationToken)
{
if (_asObject)
return base.WriteValue(async, writer, cancellationToken);
Debug.Assert(Converter is PgConverter<T>);
if (async)
return Unsafe.As<PgConverter<T>>(Converter!).WriteAsync(writer, TypedValue!, cancellationToken);
Unsafe.As<PgConverter<T>>(Converter!).Write(writer, TypedValue!);
return new();
}
private protected override NpgsqlParameter CloneCore() =>
// use fields instead of properties
// to avoid auto-initializing something like type_info
new NpgsqlParameter<T>
{
_precision = _precision,
_scale = _scale,
_size = _size,
_npgsqlDbType = _npgsqlDbType,
_dataTypeName = _dataTypeName,
Direction = Direction,
IsNullable = IsNullable,
_name = _name,
TrimmedName = TrimmedName,
SourceColumn = SourceColumn,
SourceVersion = SourceVersion,
TypedValue = TypedValue,
SourceColumnNullMapping = SourceColumnNullMapping,
};
}