Skip to content

Commit

Permalink
Add async System.Data resultset and database schema APIs (#39098)
Browse files Browse the repository at this point in the history
Closes #38028
  • Loading branch information
roji authored Jul 12, 2020
1 parent 56b6964 commit 225673d
Show file tree
Hide file tree
Showing 6 changed files with 413 additions and 248 deletions.
5 changes: 5 additions & 0 deletions src/libraries/System.Data.Common/ref/System.Data.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,9 @@ public virtual void EnlistTransaction(System.Transactions.Transaction? transacti
public virtual System.Data.DataTable GetSchema() { throw null; }
public virtual System.Data.DataTable GetSchema(string collectionName) { throw null; }
public virtual System.Data.DataTable GetSchema(string collectionName, string?[] restrictionValues) { throw null; }
public virtual System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }
public virtual System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaAsync(string collectionName, System.Threading.CancellationToken cancellationToken = default) { throw null; }
public virtual System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaAsync(string collectionName, string?[] restrictionValues, System.Threading.CancellationToken cancellationToken = default) { throw null; }
protected virtual void OnStateChange(System.Data.StateChangeEventArgs stateChange) { }
public abstract void Open();
public System.Threading.Tasks.Task OpenAsync() { throw null; }
Expand Down Expand Up @@ -2111,6 +2114,8 @@ protected virtual void Dispose(bool disposing) { }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public virtual int GetProviderSpecificValues(object[] values) { throw null; }
public virtual System.Data.DataTable GetSchemaTable() { throw null; }
public virtual System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaTableAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }
public virtual System.Threading.Tasks.Task<System.Collections.ObjectModel.ReadOnlyCollection<System.Data.Common.DbColumn>> GetColumnSchemaAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }
public virtual System.IO.Stream GetStream(int ordinal) { throw null; }
public abstract string GetString(int ordinal);
public virtual System.IO.TextReader GetTextReader(int ordinal) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,21 +143,166 @@ public virtual void EnlistTransaction(System.Transactions.Transaction? transacti

// these need to be here so that GetSchema is visible when programming to a dbConnection object.
// they are overridden by the real implementations in DbConnectionBase

/// <summary>
/// Returns schema information for the data source of this <see cref="DbConnection" />.
/// </summary>
/// <returns>A <see cref="DataTable" /> that contains schema information.</returns>
/// <remarks>
/// If the connection is associated with a transaction, executing <see cref="GetSchema()" /> calls may cause
/// some providers to throw an exception.
/// </remarks>
public virtual DataTable GetSchema()
{
throw ADP.NotSupported();
}

/// <summary>
/// Returns schema information for the data source of this <see cref="DbConnection" /> using the specified
/// string for the schema name.
/// </summary>
/// <param name="collectionName">Specifies the name of the schema to return.</param>
/// <returns>A <see cref="DataTable" /> that contains schema information.</returns>
/// <exception cref="ArgumentException">
/// <paramref name="collectionName" /> is specified as <see langword="null" />.
/// </exception>
/// <remarks>
/// If the connection is associated with a transaction, executing <see cref="GetSchema(string)" /> calls may cause
/// some providers to throw an exception.
/// </remarks>
public virtual DataTable GetSchema(string collectionName)
{
throw ADP.NotSupported();
}

/// <summary>
/// Returns schema information for the data source of this <see cref="DbConnection" /> using the specified
/// string for the schema name and the specified string array for the restriction values.
/// </summary>
/// <param name="collectionName">Specifies the name of the schema to return.</param>
/// <param name="restrictionValues">Specifies a set of restriction values for the requested schema.</param>
/// <returns>A <see cref="DataTable" /> that contains schema information.</returns>
/// <exception cref="ArgumentException">
/// <paramref name="collectionName" /> is specified as <see langword="null" />.
/// </exception>
/// <remarks>
/// <para>
/// The <paramref name="restrictionValues" /> parameter can supply n depth of values, which are specified by the
/// restrictions collection for a specific collection. In order to set values on a given restriction, and not
/// set the values of other restrictions, you need to set the preceding restrictions to null and then put the
/// appropriate value in for the restriction that you would like to specify a value for.
/// </para>
/// <para>
/// An example of this is the "Tables" collection. If the "Tables" collection has three restrictions (database,
/// owner, and table name) and you want to get back only the tables associated with the owner "Carl", you must
/// pass in the following values at least: null, "Carl". If a restriction value is not passed in, the default
/// values are used for that restriction. This is the same mapping as passing in null, which is different from
/// passing in an empty string for the parameter value. In that case, the empty string ("") is considered to be
/// the value for the specified parameter.
/// </para>
/// <para>
/// If the connection is associated with a transaction, executing <see cref="GetSchema(string, string[])" />
/// calls may cause some providers to throw an exception.
/// </para>
/// </remarks>
public virtual DataTable GetSchema(string collectionName, string?[] restrictionValues)
{
throw ADP.NotSupported();
}

/// <summary>
/// This is the asynchronous version of <see cref="GetSchema()" />.
/// Providers should override with an appropriate implementation.
/// The cancellation token can optionally be honored.
/// The default implementation invokes the synchronous <see cref="GetSchema()" /> call and returns a completed
/// task.
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
/// Exceptions thrown by <see cref="GetSchema()" /> will be communicated via the returned Task Exception
/// property.
/// </summary>
/// <param name="cancellationToken">The cancellation instruction.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public virtual Task<DataTable> GetSchemaAsync(CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<DataTable>(cancellationToken);
}

try
{
return Task.FromResult(GetSchema());
}
catch (Exception e)
{
return Task.FromException<DataTable>(e);
}
}

/// <summary>
/// This is the asynchronous version of <see cref="GetSchema(string)" />.
/// Providers should override with an appropriate implementation.
/// The cancellation token can optionally be honored.
/// The default implementation invokes the synchronous <see cref="GetSchema(string)" /> call and returns a
/// completed task.
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
/// Exceptions thrown by <see cref="GetSchema(string)" /> will be communicated via the returned Task Exception
/// property.
/// </summary>
/// <param name="collectionName">Specifies the name of the schema to return.</param>
/// <param name="cancellationToken">The cancellation instruction.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public virtual Task<DataTable> GetSchemaAsync(
string collectionName,
CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<DataTable>(cancellationToken);
}

try
{
return Task.FromResult(GetSchema(collectionName));
}
catch (Exception e)
{
return Task.FromException<DataTable>(e);
}
}

/// <summary>
/// This is the asynchronous version of <see cref="GetSchema(string, string[])" />.
/// Providers should override with an appropriate implementation.
/// The cancellation token can optionally be honored.
/// The default implementation invokes the synchronous <see cref="GetSchema(string, string[])" /> call and
/// returns a completed task.
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
/// Exceptions thrown by <see cref="GetSchema(string, string[])" /> will be communicated via the returned Task
/// Exception property.
/// </summary>
/// <param name="collectionName">Specifies the name of the schema to return.</param>
/// <param name="restrictionValues">Specifies a set of restriction values for the requested schema.</param>
/// <param name="cancellationToken">The cancellation instruction.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public virtual Task<DataTable> GetSchemaAsync(string collectionName, string?[] restrictionValues,
CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<DataTable>(cancellationToken);
}

try
{
return Task.FromResult(GetSchema(collectionName, restrictionValues));
}
catch (Exception e)
{
return Task.FromException<DataTable>(e);
}
}

protected virtual void OnStateChange(StateChangeEventArgs stateChange)
{
if (_suppressStateChangeForReconnection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#nullable enable
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
Expand Down Expand Up @@ -73,11 +74,77 @@ public virtual ValueTask DisposeAsync()

public abstract int GetOrdinal(string name);

/// <summary>
/// Returns a <see cref="DataTable" /> that describes the column metadata of the ><see cref="DbDataReader" />.
/// </summary>
/// <returns>A <see cref="DataTable" /> that describes the column metadata.</returns>
/// <exception cref="InvalidOperationException">The <see cref="DbDataReader" /> is closed.</exception>
/// <exception cref="IndexOutOfRangeException">The column index is out of range.</exception>
/// <exception cref="NotSupportedException">.NET Core only: This member is not supported.</exception>
public virtual DataTable GetSchemaTable()
{
throw new NotSupportedException();
}

/// <summary>
/// This is the asynchronous version of <see cref="GetSchemaTable()" />.
/// Providers should override with an appropriate implementation.
/// The cancellation token can optionally be honored.
/// The default implementation invokes the synchronous <see cref="GetSchemaTable()" /> call and
/// returns a completed task.
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
/// Exceptions thrown by <see cref="GetSchemaTable()" /> will be communicated via the returned Task
/// Exception property.
/// </summary>
/// <param name="cancellationToken">The cancellation instruction.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public virtual Task<DataTable> GetSchemaTableAsync(CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<DataTable>(cancellationToken);
}

try
{
return Task.FromResult(GetSchemaTable());
}
catch (Exception e)
{
return Task.FromException<DataTable>(e);
}
}

/// <summary>
/// This is the asynchronous version of <see cref="DbDataReaderExtensions.GetColumnSchema(DbDataReader)" />.
/// Providers should override with an appropriate implementation.
/// The cancellation token can optionally be honored.
/// The default implementation invokes the synchronous
/// <see cref="DbDataReaderExtensions.GetColumnSchema(DbDataReader)" /> call and returns a completed task.
/// The default implementation will return a cancelled task if passed an already cancelled cancellationToken.
/// Exceptions thrown by <see cref="DbDataReaderExtensions.GetColumnSchema(DbDataReader)" /> will be
/// communicated via the returned Task Exception property.
/// </summary>
/// <param name="cancellationToken">The cancellation instruction.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public virtual Task<ReadOnlyCollection<DbColumn>> GetColumnSchemaAsync(
CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<ReadOnlyCollection<DbColumn>>(cancellationToken);
}

try
{
return Task.FromResult(this.GetColumnSchema());
}
catch (Exception e)
{
return Task.FromException<ReadOnlyCollection<DbColumn>>(e);
}
}

public abstract bool GetBoolean(int ordinal);

public abstract byte GetByte(int ordinal);
Expand Down
Loading

0 comments on commit 225673d

Please sign in to comment.