Skip to content

Commit 225673d

Browse files
authored
Add async System.Data resultset and database schema APIs (#39098)
Closes #38028
1 parent 56b6964 commit 225673d

File tree

6 files changed

+413
-248
lines changed

6 files changed

+413
-248
lines changed

src/libraries/System.Data.Common/ref/System.Data.Common.cs

+5
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,9 @@ public virtual void EnlistTransaction(System.Transactions.Transaction? transacti
19331933
public virtual System.Data.DataTable GetSchema() { throw null; }
19341934
public virtual System.Data.DataTable GetSchema(string collectionName) { throw null; }
19351935
public virtual System.Data.DataTable GetSchema(string collectionName, string?[] restrictionValues) { throw null; }
1936+
public virtual System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }
1937+
public virtual System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaAsync(string collectionName, System.Threading.CancellationToken cancellationToken = default) { throw null; }
1938+
public virtual System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaAsync(string collectionName, string?[] restrictionValues, System.Threading.CancellationToken cancellationToken = default) { throw null; }
19361939
protected virtual void OnStateChange(System.Data.StateChangeEventArgs stateChange) { }
19371940
public abstract void Open();
19381941
public System.Threading.Tasks.Task OpenAsync() { throw null; }
@@ -2111,6 +2114,8 @@ protected virtual void Dispose(bool disposing) { }
21112114
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
21122115
public virtual int GetProviderSpecificValues(object[] values) { throw null; }
21132116
public virtual System.Data.DataTable GetSchemaTable() { throw null; }
2117+
public virtual System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaTableAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }
2118+
public virtual System.Threading.Tasks.Task<System.Collections.ObjectModel.ReadOnlyCollection<System.Data.Common.DbColumn>> GetColumnSchemaAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }
21142119
public virtual System.IO.Stream GetStream(int ordinal) { throw null; }
21152120
public abstract string GetString(int ordinal);
21162121
public virtual System.IO.TextReader GetTextReader(int ordinal) { throw null; }

src/libraries/System.Data.Common/src/System/Data/Common/DbConnection.cs

+145
Original file line numberDiff line numberDiff line change
@@ -143,21 +143,166 @@ public virtual void EnlistTransaction(System.Transactions.Transaction? transacti
143143

144144
// these need to be here so that GetSchema is visible when programming to a dbConnection object.
145145
// they are overridden by the real implementations in DbConnectionBase
146+
147+
/// <summary>
148+
/// Returns schema information for the data source of this <see cref="DbConnection" />.
149+
/// </summary>
150+
/// <returns>A <see cref="DataTable" /> that contains schema information.</returns>
151+
/// <remarks>
152+
/// If the connection is associated with a transaction, executing <see cref="GetSchema()" /> calls may cause
153+
/// some providers to throw an exception.
154+
/// </remarks>
146155
public virtual DataTable GetSchema()
147156
{
148157
throw ADP.NotSupported();
149158
}
150159

160+
/// <summary>
161+
/// Returns schema information for the data source of this <see cref="DbConnection" /> using the specified
162+
/// string for the schema name.
163+
/// </summary>
164+
/// <param name="collectionName">Specifies the name of the schema to return.</param>
165+
/// <returns>A <see cref="DataTable" /> that contains schema information.</returns>
166+
/// <exception cref="ArgumentException">
167+
/// <paramref name="collectionName" /> is specified as <see langword="null" />.
168+
/// </exception>
169+
/// <remarks>
170+
/// If the connection is associated with a transaction, executing <see cref="GetSchema(string)" /> calls may cause
171+
/// some providers to throw an exception.
172+
/// </remarks>
151173
public virtual DataTable GetSchema(string collectionName)
152174
{
153175
throw ADP.NotSupported();
154176
}
155177

178+
/// <summary>
179+
/// Returns schema information for the data source of this <see cref="DbConnection" /> using the specified
180+
/// string for the schema name and the specified string array for the restriction values.
181+
/// </summary>
182+
/// <param name="collectionName">Specifies the name of the schema to return.</param>
183+
/// <param name="restrictionValues">Specifies a set of restriction values for the requested schema.</param>
184+
/// <returns>A <see cref="DataTable" /> that contains schema information.</returns>
185+
/// <exception cref="ArgumentException">
186+
/// <paramref name="collectionName" /> is specified as <see langword="null" />.
187+
/// </exception>
188+
/// <remarks>
189+
/// <para>
190+
/// The <paramref name="restrictionValues" /> parameter can supply n depth of values, which are specified by the
191+
/// restrictions collection for a specific collection. In order to set values on a given restriction, and not
192+
/// set the values of other restrictions, you need to set the preceding restrictions to null and then put the
193+
/// appropriate value in for the restriction that you would like to specify a value for.
194+
/// </para>
195+
/// <para>
196+
/// An example of this is the "Tables" collection. If the "Tables" collection has three restrictions (database,
197+
/// owner, and table name) and you want to get back only the tables associated with the owner "Carl", you must
198+
/// pass in the following values at least: null, "Carl". If a restriction value is not passed in, the default
199+
/// values are used for that restriction. This is the same mapping as passing in null, which is different from
200+
/// passing in an empty string for the parameter value. In that case, the empty string ("") is considered to be
201+
/// the value for the specified parameter.
202+
/// </para>
203+
/// <para>
204+
/// If the connection is associated with a transaction, executing <see cref="GetSchema(string, string[])" />
205+
/// calls may cause some providers to throw an exception.
206+
/// </para>
207+
/// </remarks>
156208
public virtual DataTable GetSchema(string collectionName, string?[] restrictionValues)
157209
{
158210
throw ADP.NotSupported();
159211
}
160212

213+
/// <summary>
214+
/// This is the asynchronous version of <see cref="GetSchema()" />.
215+
/// Providers should override with an appropriate implementation.
216+
/// The cancellation token can optionally be honored.
217+
/// The default implementation invokes the synchronous <see cref="GetSchema()" /> call and returns a completed
218+
/// task.
219+
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
220+
/// Exceptions thrown by <see cref="GetSchema()" /> will be communicated via the returned Task Exception
221+
/// property.
222+
/// </summary>
223+
/// <param name="cancellationToken">The cancellation instruction.</param>
224+
/// <returns>A task representing the asynchronous operation.</returns>
225+
public virtual Task<DataTable> GetSchemaAsync(CancellationToken cancellationToken = default)
226+
{
227+
if (cancellationToken.IsCancellationRequested)
228+
{
229+
return Task.FromCanceled<DataTable>(cancellationToken);
230+
}
231+
232+
try
233+
{
234+
return Task.FromResult(GetSchema());
235+
}
236+
catch (Exception e)
237+
{
238+
return Task.FromException<DataTable>(e);
239+
}
240+
}
241+
242+
/// <summary>
243+
/// This is the asynchronous version of <see cref="GetSchema(string)" />.
244+
/// Providers should override with an appropriate implementation.
245+
/// The cancellation token can optionally be honored.
246+
/// The default implementation invokes the synchronous <see cref="GetSchema(string)" /> call and returns a
247+
/// completed task.
248+
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
249+
/// Exceptions thrown by <see cref="GetSchema(string)" /> will be communicated via the returned Task Exception
250+
/// property.
251+
/// </summary>
252+
/// <param name="collectionName">Specifies the name of the schema to return.</param>
253+
/// <param name="cancellationToken">The cancellation instruction.</param>
254+
/// <returns>A task representing the asynchronous operation.</returns>
255+
public virtual Task<DataTable> GetSchemaAsync(
256+
string collectionName,
257+
CancellationToken cancellationToken = default)
258+
{
259+
if (cancellationToken.IsCancellationRequested)
260+
{
261+
return Task.FromCanceled<DataTable>(cancellationToken);
262+
}
263+
264+
try
265+
{
266+
return Task.FromResult(GetSchema(collectionName));
267+
}
268+
catch (Exception e)
269+
{
270+
return Task.FromException<DataTable>(e);
271+
}
272+
}
273+
274+
/// <summary>
275+
/// This is the asynchronous version of <see cref="GetSchema(string, string[])" />.
276+
/// Providers should override with an appropriate implementation.
277+
/// The cancellation token can optionally be honored.
278+
/// The default implementation invokes the synchronous <see cref="GetSchema(string, string[])" /> call and
279+
/// returns a completed task.
280+
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
281+
/// Exceptions thrown by <see cref="GetSchema(string, string[])" /> will be communicated via the returned Task
282+
/// Exception property.
283+
/// </summary>
284+
/// <param name="collectionName">Specifies the name of the schema to return.</param>
285+
/// <param name="restrictionValues">Specifies a set of restriction values for the requested schema.</param>
286+
/// <param name="cancellationToken">The cancellation instruction.</param>
287+
/// <returns>A task representing the asynchronous operation.</returns>
288+
public virtual Task<DataTable> GetSchemaAsync(string collectionName, string?[] restrictionValues,
289+
CancellationToken cancellationToken = default)
290+
{
291+
if (cancellationToken.IsCancellationRequested)
292+
{
293+
return Task.FromCanceled<DataTable>(cancellationToken);
294+
}
295+
296+
try
297+
{
298+
return Task.FromResult(GetSchema(collectionName, restrictionValues));
299+
}
300+
catch (Exception e)
301+
{
302+
return Task.FromException<DataTable>(e);
303+
}
304+
}
305+
161306
protected virtual void OnStateChange(StateChangeEventArgs stateChange)
162307
{
163308
if (_suppressStateChangeForReconnection)

src/libraries/System.Data.Common/src/System/Data/Common/DbDataReader.cs

+67
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#nullable enable
55
using System.Collections;
6+
using System.Collections.ObjectModel;
67
using System.ComponentModel;
78
using System.IO;
89
using System.Threading.Tasks;
@@ -73,11 +74,77 @@ public virtual ValueTask DisposeAsync()
7374

7475
public abstract int GetOrdinal(string name);
7576

77+
/// <summary>
78+
/// Returns a <see cref="DataTable" /> that describes the column metadata of the ><see cref="DbDataReader" />.
79+
/// </summary>
80+
/// <returns>A <see cref="DataTable" /> that describes the column metadata.</returns>
81+
/// <exception cref="InvalidOperationException">The <see cref="DbDataReader" /> is closed.</exception>
82+
/// <exception cref="IndexOutOfRangeException">The column index is out of range.</exception>
83+
/// <exception cref="NotSupportedException">.NET Core only: This member is not supported.</exception>
7684
public virtual DataTable GetSchemaTable()
7785
{
7886
throw new NotSupportedException();
7987
}
8088

89+
/// <summary>
90+
/// This is the asynchronous version of <see cref="GetSchemaTable()" />.
91+
/// Providers should override with an appropriate implementation.
92+
/// The cancellation token can optionally be honored.
93+
/// The default implementation invokes the synchronous <see cref="GetSchemaTable()" /> call and
94+
/// returns a completed task.
95+
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
96+
/// Exceptions thrown by <see cref="GetSchemaTable()" /> will be communicated via the returned Task
97+
/// Exception property.
98+
/// </summary>
99+
/// <param name="cancellationToken">The cancellation instruction.</param>
100+
/// <returns>A task representing the asynchronous operation.</returns>
101+
public virtual Task<DataTable> GetSchemaTableAsync(CancellationToken cancellationToken = default)
102+
{
103+
if (cancellationToken.IsCancellationRequested)
104+
{
105+
return Task.FromCanceled<DataTable>(cancellationToken);
106+
}
107+
108+
try
109+
{
110+
return Task.FromResult(GetSchemaTable());
111+
}
112+
catch (Exception e)
113+
{
114+
return Task.FromException<DataTable>(e);
115+
}
116+
}
117+
118+
/// <summary>
119+
/// This is the asynchronous version of <see cref="DbDataReaderExtensions.GetColumnSchema(DbDataReader)" />.
120+
/// Providers should override with an appropriate implementation.
121+
/// The cancellation token can optionally be honored.
122+
/// The default implementation invokes the synchronous
123+
/// <see cref="DbDataReaderExtensions.GetColumnSchema(DbDataReader)" /> call and returns a completed task.
124+
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
125+
/// Exceptions thrown by <see cref="DbDataReaderExtensions.GetColumnSchema(DbDataReader)" /> will be
126+
/// communicated via the returned Task Exception property.
127+
/// </summary>
128+
/// <param name="cancellationToken">The cancellation instruction.</param>
129+
/// <returns>A task representing the asynchronous operation.</returns>
130+
public virtual Task<ReadOnlyCollection<DbColumn>> GetColumnSchemaAsync(
131+
CancellationToken cancellationToken = default)
132+
{
133+
if (cancellationToken.IsCancellationRequested)
134+
{
135+
return Task.FromCanceled<ReadOnlyCollection<DbColumn>>(cancellationToken);
136+
}
137+
138+
try
139+
{
140+
return Task.FromResult(this.GetColumnSchema());
141+
}
142+
catch (Exception e)
143+
{
144+
return Task.FromException<ReadOnlyCollection<DbColumn>>(e);
145+
}
146+
}
147+
81148
public abstract bool GetBoolean(int ordinal);
82149

83150
public abstract byte GetByte(int ordinal);

0 commit comments

Comments
 (0)