Skip to content
Permalink
Browse files

Properly deal with command failure on auto-prepare

Fixes #2178
  • Loading branch information...
roji committed Jul 8, 2019
1 parent 8d3daed commit 34f11a1dd9d94b83dacd0deb10acc6b6d6786b65
Showing with 52 additions and 11 deletions.
  1. +13 −7 src/Npgsql/NpgsqlDataReader.cs
  2. +3 −4 src/Npgsql/PreparedStatement.cs
  3. +36 −0 test/Npgsql.Tests/BugTests.cs
@@ -413,7 +413,19 @@ async Task<bool> NextResult(bool async, bool isConsuming=false)
}
}

Expect<ParseCompleteMessage>(await Connector.ReadMessage(async));
try
{
Expect<ParseCompleteMessage>(await Connector.ReadMessage(async));
}
catch
{
// An exception occurred. Check if any statements we being prepared and revert our bookkeeping.
pStatement?.CompleteUnprepare();
throw;
}

pStatement?.CompletePrepare();

Expect<BindCompleteMessage>(await Connector.ReadMessage(async));
msg = await Connector.ReadMessage(async);
switch (msg.Code)
@@ -428,12 +440,6 @@ async Task<bool> NextResult(bool async, bool isConsuming=false)
default:
throw Connector.UnexpectedMessageReceived(msg.Code);
}

if (pStatement != null)
{
Debug.Assert(!pStatement.IsPrepared);
pStatement.CompletePrepare();
}
}

if (RowDescription == null)
@@ -140,15 +140,14 @@ enum PreparedState

/// <summary>
/// The statement has been selected for preparation, but the preparation hasn't started yet.
/// This is a temporary state that only occurs during preparation.
/// Specifically, no protocol message (Parse) has been sent yet. Specifically, it means that
/// a Parse message for the statement has already been written to the write buffer.
/// This is a temporary state that only occurs during preparation, and indicates that no
/// no protocol message (Parse) has been sent yet.
/// </summary>
ToBePrepared,

/// <summary>
/// The statement is in the process of being prepared. This is a temporary state that only occurs during
/// preparation. Specifically, it means that a Parse message for the statement has already been written
/// preparation, and indicates that a Parse protocol message for the statement has already been written
/// to the write buffer.
/// </summary>
BeingPrepared,
@@ -403,6 +403,42 @@ enum Bug2278EnumType
Right
}


[Test]
[IssueLink("https://github.com/npgsql/npgsql/issues/2178")]
public void Bug2178()
{
var builder = new NpgsqlConnectionStringBuilder(ConnectionString);
builder.AutoPrepareMinUsages = 2;
builder.MaxAutoPrepare = 2;
using (var conn = new NpgsqlConnection(builder.ConnectionString))
using (var cmd = new NpgsqlCommand())
{
conn.Open();
cmd.Connection = conn;

cmd.CommandText = "SELECT 1";
cmd.ExecuteScalar();
cmd.ExecuteScalar();
Assert.That(cmd.IsPrepared);

// Now executing a faulty command multiple times
cmd.CommandText = "SELECT * FROM public.dummy_table_name";
for (var i = 0; i < 3; ++i)
{
try
{
cmd.ExecuteScalar();
}
catch { }
}

cmd.CommandText = "SELECT 1";
cmd.ExecuteScalar();
Assert.That(cmd.IsPrepared);
}
}

[Test]
public void Bug2296()
{

0 comments on commit 34f11a1

Please sign in to comment.
You can’t perform that action at this time.