-
Notifications
You must be signed in to change notification settings - Fork 874
Expand file tree
/
Copy pathNpgsqlCommandBuilder.cs
More file actions
314 lines (286 loc) · 13.7 KB
/
NpgsqlCommandBuilder.cs
File metadata and controls
314 lines (286 loc) · 13.7 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
using System;
using System.Data;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using NpgsqlTypes;
namespace Npgsql;
///<summary>
/// This class creates database commands for automatic insert, update and delete operations.
///</summary>
[System.ComponentModel.DesignerCategory("")]
public sealed class NpgsqlCommandBuilder : DbCommandBuilder
{
// Commented out because SetRowUpdatingHandler() is commented, and causes an "is never used" warning
// private NpgsqlRowUpdatingEventHandler rowUpdatingHandler;
/// <summary>
/// Initializes a new instance of the <see cref="NpgsqlCommandBuilder"/> class.
/// </summary>
public NpgsqlCommandBuilder()
: this(null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="NpgsqlCommandBuilder"/> class.
/// </summary>
/// <param name="adapter">The adapter.</param>
public NpgsqlCommandBuilder(NpgsqlDataAdapter? adapter)
{
DataAdapter = adapter;
QuotePrefix = "\"";
QuoteSuffix = "\"";
}
/// <summary>
/// Gets or sets the beginning character or characters to use when specifying database objects (for example, tables or columns) whose names contain characters such as spaces or reserved tokens.
/// </summary>
/// <returns>
/// The beginning character or characters to use. The default is an empty string.
/// </returns>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" PathDiscovery="*AllFiles*" />
/// </PermissionSet>
[AllowNull]
public override string QuotePrefix
{
get => base.QuotePrefix;
// TODO: Why should it be possible to remove the QuotePrefix?
set
{
if (string.IsNullOrEmpty(value))
{
base.QuotePrefix = value;
}
else
{
base.QuotePrefix = "\"";
}
}
}
/// <summary>
/// Gets or sets the ending character or characters to use when specifying database objects (for example, tables or columns) whose names contain characters such as spaces or reserved tokens.
/// </summary>
/// <returns>
/// The ending character or characters to use. The default is an empty string.
/// </returns>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" PathDiscovery="*AllFiles*" />
/// </PermissionSet>
[AllowNull]
public override string QuoteSuffix
{
get => base.QuoteSuffix;
// TODO: Why should it be possible to remove the QuoteSuffix?
set
{
if (string.IsNullOrEmpty(value))
{
base.QuoteSuffix = value;
}
else
{
base.QuoteSuffix = "\"";
}
}
}
///<summary>
///
/// This method is responsible to derive the command parameter list with values obtained from function definition.
/// It clears the Parameters collection of command. Also, if there is any parameter type which is not supported by Npgsql, an InvalidOperationException will be thrown.
/// Parameters name will be parameter1, parameter2, ... for CommandType.StoredProcedure and named after the placeholder for CommandType.Text
///</summary>
/// <param name="command">NpgsqlCommand whose function parameters will be obtained.</param>
public static void DeriveParameters(NpgsqlCommand command) => command.DeriveParameters();
/// <summary>
/// Gets the automatically generated <see cref="NpgsqlCommand"/> object required
/// to perform insertions at the data source.
/// </summary>
/// <returns>
/// The automatically generated <see cref="NpgsqlCommand"/> object required to perform insertions.
/// </returns>
public new NpgsqlCommand GetInsertCommand() => GetInsertCommand(false);
/// <summary>
/// Gets the automatically generated <see cref="NpgsqlCommand"/> object required to perform insertions
/// at the data source, optionally using columns for parameter names.
/// </summary>
/// <param name="useColumnsForParameterNames">
/// If <see langword="true"/>, generate parameter names matching column names, if possible.
/// If <see langword="false"/>, generate <c>@p1</c>, <c>@p2</c>, and so on.
/// </param>
/// <returns>
/// The automatically generated <see cref="NpgsqlCommand"/> object required to perform insertions.
/// </returns>
public new NpgsqlCommand GetInsertCommand(bool useColumnsForParameterNames)
{
var cmd = (NpgsqlCommand) base.GetInsertCommand(useColumnsForParameterNames);
cmd.UpdatedRowSource = UpdateRowSource.None;
return cmd;
}
/// <summary>
/// Gets the automatically generated System.Data.Common.DbCommand object required
/// to perform updates at the data source.
/// </summary>
/// <returns>
/// The automatically generated System.Data.Common.DbCommand object required to perform updates.
/// </returns>
public new NpgsqlCommand GetUpdateCommand() => GetUpdateCommand(false);
/// <summary>
/// Gets the automatically generated <see cref="NpgsqlCommand"/> object required to perform updates
/// at the data source, optionally using columns for parameter names.
/// </summary>
/// <param name="useColumnsForParameterNames">
/// If <see langword="true"/>, generate parameter names matching column names, if possible.
/// If <see langword="false"/>, generate <c>@p1</c>, <c>@p2</c>, and so on.
/// </param>
/// <returns>
/// The automatically generated <see cref="NpgsqlCommand"/> object required to perform updates.
/// </returns>
public new NpgsqlCommand GetUpdateCommand(bool useColumnsForParameterNames)
{
var cmd = (NpgsqlCommand)base.GetUpdateCommand(useColumnsForParameterNames);
cmd.UpdatedRowSource = UpdateRowSource.None;
return cmd;
}
/// <summary>
/// Gets the automatically generated System.Data.Common.DbCommand object required
/// to perform deletions at the data source.
/// </summary>
/// <returns>
/// The automatically generated System.Data.Common.DbCommand object required to perform deletions.
/// </returns>
public new NpgsqlCommand GetDeleteCommand() => GetDeleteCommand(false);
/// <summary>
/// Gets the automatically generated <see cref="NpgsqlCommand"/> object required to perform deletions
/// at the data source, optionally using columns for parameter names.
/// </summary>
/// <param name="useColumnsForParameterNames">
/// If <see langword="true"/>, generate parameter names matching column names, if possible.
/// If <see langword="false"/>, generate @p1, @p2, and so on.
/// </param>
/// <returns>
/// The automatically generated <see cref="NpgsqlCommand"/> object required to perform deletions.
/// </returns>
public new NpgsqlCommand GetDeleteCommand(bool useColumnsForParameterNames)
{
var cmd = (NpgsqlCommand) base.GetDeleteCommand(useColumnsForParameterNames);
cmd.UpdatedRowSource = UpdateRowSource.None;
return cmd;
}
//never used
//private string QualifiedTableName(string schema, string tableName)
//{
// if (schema == null || schema.Length == 0)
// {
// return tableName;
// }
// else
// {
// return schema + "." + tableName;
// }
//}
/*
private static void SetParameterValuesFromRow(NpgsqlCommand command, DataRow row)
{
foreach (NpgsqlParameter parameter in command.Parameters)
{
parameter.Value = row[parameter.SourceColumn, parameter.SourceVersion];
}
}
*/
/// <summary>
/// Applies the parameter information.
/// </summary>
/// <param name="p">The parameter.</param>
/// <param name="row">The row.</param>
/// <param name="statementType">Type of the statement.</param>
/// <param name="whereClause">If set to <see langword="true"/> [where clause].</param>
protected override void ApplyParameterInfo(DbParameter p, DataRow row, System.Data.StatementType statementType, bool whereClause)
{
var param = (NpgsqlParameter)p;
param.NpgsqlDbType = (NpgsqlDbType)row[SchemaTableColumn.ProviderType];
}
/// <summary>
/// Returns the name of the specified parameter in the format of @p#.
/// </summary>
/// <param name="parameterOrdinal">The number to be included as part of the parameter's name..</param>
/// <returns>
/// The name of the parameter with the specified number appended as part of the parameter name.
/// </returns>
protected override string GetParameterName(int parameterOrdinal)
=> string.Format(CultureInfo.InvariantCulture, "@p{0}", parameterOrdinal);
/// <summary>
/// Returns the full parameter name, given the partial parameter name.
/// </summary>
/// <param name="parameterName">The partial name of the parameter.</param>
/// <returns>
/// The full parameter name corresponding to the partial parameter name requested.
/// </returns>
protected override string GetParameterName(string parameterName)
=> string.Format(CultureInfo.InvariantCulture, "@{0}", parameterName);
/// <summary>
/// Returns the placeholder for the parameter in the associated SQL statement.
/// </summary>
/// <param name="parameterOrdinal">The number to be included as part of the parameter's name.</param>
/// <returns>
/// The name of the parameter with the specified number appended.
/// </returns>
protected override string GetParameterPlaceholder(int parameterOrdinal)
=> GetParameterName(parameterOrdinal);
/// <summary>
/// Registers the <see cref="NpgsqlCommandBuilder" /> to handle the <see cref="NpgsqlDataAdapter.RowUpdating"/> event for a <see cref="NpgsqlDataAdapter" />.
/// </summary>
/// <param name="adapter">The <see cref="System.Data.Common.DbDataAdapter" /> to be used for the update.</param>
protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
{
var npgsqlAdapter = adapter as NpgsqlDataAdapter;
if (npgsqlAdapter == null)
throw new ArgumentException("adapter needs to be a NpgsqlDataAdapter", nameof(adapter));
// Being called twice for the same adapter means unregister
if (adapter == DataAdapter)
npgsqlAdapter.RowUpdating -= RowUpdatingHandler;
else
npgsqlAdapter.RowUpdating += RowUpdatingHandler;
}
/// <summary>
/// Adds an event handler for the <see cref="NpgsqlDataAdapter.RowUpdating"/> event.
/// </summary>
/// <param name="sender">The sender</param>
/// <param name="e">A <see cref="NpgsqlRowUpdatingEventArgs"/> instance containing information about the event.</param>
void RowUpdatingHandler(object sender, NpgsqlRowUpdatingEventArgs e) => base.RowUpdatingHandler(e);
/// <summary>
/// Given an unquoted identifier in the correct catalog case, returns the correct quoted form of that identifier, including properly escaping any embedded quotes in the identifier.
/// </summary>
/// <param name="unquotedIdentifier">The original unquoted identifier.</param>
/// <returns>
/// The quoted version of the identifier. Embedded quotes within the identifier are properly escaped.
/// </returns>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" PathDiscovery="*AllFiles*" />
/// </PermissionSet>
/// <exception cref="System.ArgumentNullException">Unquoted identifier parameter cannot be null</exception>
public override string QuoteIdentifier(string unquotedIdentifier)
=> unquotedIdentifier == null
? throw new ArgumentNullException(nameof(unquotedIdentifier), "Unquoted identifier parameter cannot be null")
: $"{QuotePrefix}{unquotedIdentifier.Replace(QuotePrefix, QuotePrefix + QuotePrefix)}{QuoteSuffix}";
/// <summary>
/// Given a quoted identifier, returns the correct unquoted form of that identifier, including properly un-escaping any embedded quotes in the identifier.
/// </summary>
/// <param name="quotedIdentifier">The identifier that will have its embedded quotes removed.</param>
/// <returns>
/// The unquoted identifier, with embedded quotes properly un-escaped.
/// </returns>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" PathDiscovery="*AllFiles*" />
/// </PermissionSet>
/// <exception cref="System.ArgumentNullException">Quoted identifier parameter cannot be null</exception>
public override string UnquoteIdentifier(string quotedIdentifier)
{
if (quotedIdentifier == null)
throw new ArgumentNullException(nameof(quotedIdentifier), "Quoted identifier parameter cannot be null");
var unquotedIdentifier = quotedIdentifier.Trim().Replace(QuotePrefix + QuotePrefix, QuotePrefix);
if (unquotedIdentifier.StartsWith(QuotePrefix, StringComparison.Ordinal))
unquotedIdentifier = unquotedIdentifier.Remove(0, 1);
if (unquotedIdentifier.EndsWith(QuoteSuffix, StringComparison.Ordinal))
unquotedIdentifier = unquotedIdentifier.Remove(unquotedIdentifier.Length - 1, 1);
return unquotedIdentifier;
}
}