Skip to content

Commit 0d8dd34

Browse files
authored
Implementation of the ADO.NET batching API (#3860)
Closes #2317
1 parent b9b0efb commit 0d8dd34

37 files changed

Lines changed: 1867 additions & 775 deletions

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ on:
1010
pull_request:
1111

1212
env:
13-
dotnet_sdk_version: '6.0.100-preview.4.21255.9'
13+
dotnet_sdk_version: '6.0.100-preview.7.21379.14'
1414
postgis_version: 3
1515
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
1616

.github/workflows/rich-code-nav.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
- '*'
1010

1111
env:
12-
dotnet_sdk_version: '6.0.100-preview.4.21255.9'
12+
dotnet_sdk_version: '6.0.100-preview.7.21379.14'
1313
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
1414

1515
jobs:

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
3-
"version": "6.0.100-preview.5.21302.13",
3+
"version": "6.0.100-preview.7.21379.14",
44
"rollForward": "latestMajor",
55
"allowPrerelease": "true"
66
}

src/Npgsql/Internal/NpgsqlConnector.FrontendMessages.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ internal async Task WriteParse(string sql, string statementName, List<NpgsqlPara
146146
}
147147

148148
internal async Task WriteBind(
149-
List<NpgsqlParameter> inputParameters,
149+
List<NpgsqlParameter> parameters,
150150
string portal,
151151
string statement,
152152
bool allResultTypesAreUnknown,
@@ -172,20 +172,20 @@ internal async Task WriteBind(
172172

173173
var formatCodesSum = 0;
174174
var paramsLength = 0;
175-
for (var paramIndex = 0; paramIndex < inputParameters.Count; paramIndex++)
175+
for (var paramIndex = 0; paramIndex < parameters.Count; paramIndex++)
176176
{
177-
var param = inputParameters[paramIndex];
177+
var param = parameters[paramIndex];
178178
formatCodesSum += (int)param.FormatCode;
179179
param.LengthCache?.Rewind();
180180
paramsLength += param.ValidateAndGetLength();
181181
}
182182

183-
var formatCodeListLength = formatCodesSum == 0 ? 0 : formatCodesSum == inputParameters.Count ? 1 : inputParameters.Count;
183+
var formatCodeListLength = formatCodesSum == 0 ? 0 : formatCodesSum == parameters.Count ? 1 : parameters.Count;
184184

185185
var messageLength = headerLength +
186186
sizeof(short) * formatCodeListLength + // List of format codes
187187
sizeof(short) + // Number of parameters
188-
sizeof(int) * inputParameters.Count + // Parameter lengths
188+
sizeof(int) * parameters.Count + // Parameter lengths
189189
paramsLength + // Parameter values
190190
sizeof(short) + // Number of result format codes
191191
sizeof(short) * (unknownResultTypeList?.Length ?? 1); // Result format codes
@@ -207,22 +207,22 @@ internal async Task WriteBind(
207207
}
208208
else if (formatCodeListLength > 1)
209209
{
210-
for (var paramIndex = 0; paramIndex < inputParameters.Count; paramIndex++)
210+
for (var paramIndex = 0; paramIndex < parameters.Count; paramIndex++)
211211
{
212212
if (WriteBuffer.WriteSpaceLeft < 2)
213213
await Flush(async, cancellationToken);
214-
WriteBuffer.WriteInt16((short)inputParameters[paramIndex].FormatCode);
214+
WriteBuffer.WriteInt16((short)parameters[paramIndex].FormatCode);
215215
}
216216
}
217217

218218
if (WriteBuffer.WriteSpaceLeft < 2)
219219
await Flush(async, cancellationToken);
220220

221-
WriteBuffer.WriteUInt16((ushort)inputParameters.Count);
221+
WriteBuffer.WriteUInt16((ushort)parameters.Count);
222222

223-
for (var paramIndex = 0; paramIndex < inputParameters.Count; paramIndex++)
223+
for (var paramIndex = 0; paramIndex < parameters.Count; paramIndex++)
224224
{
225-
var param = inputParameters[paramIndex];
225+
var param = parameters[paramIndex];
226226
param.LengthCache?.Rewind();
227227
await param.WriteWithLength(WriteBuffer, async, cancellationToken);
228228
}

src/Npgsql/Internal/TypeHandlers/TextHandler.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ namespace Npgsql.Internal.TypeHandlers
2222
/// should be considered somewhat unstable, and may change in breaking ways, including in non-major releases.
2323
/// Use it at your own risk.
2424
/// </remarks>
25-
2625
public class TextHandlerFactory : NpgsqlTypeHandlerFactory<string>
2726
{
2827
/// <inheritdoc />

src/Npgsql/MultiplexingConnectorPool.cs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -261,24 +261,11 @@ bool WriteCommand(NpgsqlConnector connector, NpgsqlCommand command, ref Multiple
261261
// but the main thread continues to handle other commands on other connectors.
262262
if (_autoPrepare)
263263
{
264+
// TODO: Need to log based on numPrepared like in non-multiplexing mode...
264265
var numPrepared = 0;
265-
for (var statementIndex = 0; statementIndex < command._statements.Count; statementIndex++)
266-
{
267-
var statement = command._statements[statementIndex];
268-
// If this statement isn't prepared, see if it gets implicitly prepared.
269-
// Note that this may return null (not enough usages for automatic preparation).
270-
if (!statement.IsPrepared)
271-
statement.PreparedStatement = connector.PreparedStatementManager.TryGetAutoPrepared(statement);
272-
if (statement.PreparedStatement is PreparedStatement pStatement)
273-
{
266+
for (var i = 0; i < command.InternalBatchCommands.Count; i++)
267+
if (command.InternalBatchCommands[i].TryAutoPrepare(connector))
274268
numPrepared++;
275-
if (pStatement?.State == PreparedState.NotPrepared)
276-
{
277-
pStatement.State = PreparedState.BeingPrepared;
278-
statement.IsPreparing = true;
279-
}
280-
}
281-
}
282269
}
283270

284271
var written = connector.CommandsInFlightWriter!.TryWrite(command);

src/Npgsql/Netstandard20/CodeAnalysis.cs

Lines changed: 0 additions & 74 deletions
This file was deleted.

src/Npgsql/NpgsqlBatch.cs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
using System.Collections.Generic;
2+
using System.Data;
3+
using System.Data.Common;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
7+
namespace Npgsql
8+
{
9+
/// <inheritdoc />
10+
public class NpgsqlBatch : DbBatch
11+
{
12+
readonly NpgsqlCommand _command;
13+
14+
/// <inheritdoc />
15+
protected override DbBatchCommandCollection DbBatchCommands => BatchCommands;
16+
17+
/// <inheritdoc cref="DbBatch.BatchCommands"/>
18+
public new NpgsqlBatchCommandCollection BatchCommands { get; }
19+
20+
/// <inheritdoc />
21+
public override int Timeout
22+
{
23+
get => _command.CommandTimeout;
24+
set => _command.CommandTimeout = value;
25+
}
26+
27+
/// <inheritdoc cref="DbBatch.Connection"/>
28+
public new NpgsqlConnection? Connection
29+
{
30+
get => _command.Connection;
31+
set => _command.Connection = value;
32+
}
33+
34+
/// <inheritdoc />
35+
protected override DbConnection? DbConnection
36+
{
37+
get => Connection;
38+
set => Connection = (NpgsqlConnection?)value;
39+
}
40+
41+
/// <inheritdoc cref="DbBatch.Transaction"/>
42+
public new NpgsqlTransaction? Transaction
43+
{
44+
get => _command.Transaction;
45+
set => _command.Transaction = value;
46+
}
47+
48+
/// <inheritdoc />
49+
protected override DbTransaction? DbTransaction
50+
{
51+
get => Transaction;
52+
set => Transaction = (NpgsqlTransaction?)value;
53+
}
54+
55+
/// <summary>
56+
/// Initializes a new <see cref="NpgsqlBatch"/>.
57+
/// </summary>
58+
/// <param name="connection">A <see cref="NpgsqlConnection"/> that represents the connection to a PostgreSQL server.</param>
59+
/// <param name="transaction">The <see cref="NpgsqlTransaction"/> in which the <see cref="NpgsqlCommand"/> executes.</param>
60+
public NpgsqlBatch(NpgsqlConnection? connection = null, NpgsqlTransaction? transaction = null)
61+
{
62+
var batchCommands = new List<NpgsqlBatchCommand>(5);
63+
_command = new(batchCommands);
64+
BatchCommands = new NpgsqlBatchCommandCollection(batchCommands);
65+
66+
Connection = connection;
67+
Transaction = transaction;
68+
}
69+
70+
/// <inheritdoc />
71+
protected override DbBatchCommand CreateDbBatchCommand()
72+
=> new NpgsqlBatchCommand();
73+
74+
/// <inheritdoc />
75+
protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
76+
=> ExecuteReader(behavior);
77+
78+
/// <inheritdoc cref="DbBatch.ExecuteReader"/>
79+
public new NpgsqlDataReader ExecuteReader(CommandBehavior behavior = CommandBehavior.Default)
80+
=> _command.ExecuteReader();
81+
82+
/// <inheritdoc />
83+
protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(
84+
CommandBehavior behavior,
85+
CancellationToken cancellationToken)
86+
=> await ExecuteReaderAsync(cancellationToken);
87+
88+
/// <inheritdoc cref="DbBatch.ExecuteReaderAsync(CancellationToken)"/>
89+
public new Task<NpgsqlDataReader> ExecuteReaderAsync(CancellationToken cancellationToken = default)
90+
=> _command.ExecuteReaderAsync(cancellationToken);
91+
92+
/// <inheritdoc cref="DbBatch.ExecuteReaderAsync(CommandBehavior,CancellationToken)"/>
93+
public new Task<NpgsqlDataReader> ExecuteReaderAsync(
94+
CommandBehavior behavior,
95+
CancellationToken cancellationToken = default)
96+
=> _command.ExecuteReaderAsync(behavior, cancellationToken);
97+
98+
/// <inheritdoc />
99+
public override int ExecuteNonQuery()
100+
=> _command.ExecuteNonQuery();
101+
102+
/// <inheritdoc />
103+
public override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken = default)
104+
=> _command.ExecuteNonQueryAsync(cancellationToken);
105+
106+
/// <inheritdoc />
107+
public override object? ExecuteScalar()
108+
=> _command.ExecuteScalar();
109+
110+
/// <inheritdoc />
111+
public override Task<object?> ExecuteScalarAsync(CancellationToken cancellationToken = default)
112+
=> _command.ExecuteScalarAsync(cancellationToken);
113+
114+
/// <inheritdoc />
115+
public override void Prepare()
116+
=> _command.Prepare();
117+
118+
/// <inheritdoc />
119+
public override Task PrepareAsync(CancellationToken cancellationToken = default)
120+
=> _command.PrepareAsync(cancellationToken);
121+
122+
/// <inheritdoc />
123+
public override void Cancel() => _command.Cancel();
124+
}
125+
}

0 commit comments

Comments
 (0)