Here's a simple repro of the problem I'm seeing. It's a little convoluted so I'll explain.
First, this problem is set off whenever there is a failed operation with a LargeObject. This can be as simple as opening
an unfound id (as in the first example below). This manifestation of the problem is mentioned at comments *1*, *2*,
and *3*. All three of these cases happen, seemingly randomly. I sometimes have to re-run this test a number of times
to get all three failures, but eventually they happen.
---REPRO 1---
[TestMethod()]
public void NpgsqlErrorRepro1()
{
using(NpgsqlConnection connection = new NpgsqlConnection(_ConnectionString))
{
connection.Open();
using(NpgsqlTransaction transaction = connection.BeginTransaction())
{
LargeObjectManager largeObjectMgr = new LargeObjectManager(connection);
try
{
LargeObject largeObject = largeObjectMgr.Open(-1, LargeObjectManager.READWRITE);
transaction.Commit();
}
catch
{
// ignore the LO failure
}
} // *1* sometimes it throws "System.NotSupportedException: This stream does not support seek operations"
using(NpgsqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM pg_database";
using(NpgsqlDataReader reader = command.ExecuteReader())
{
Assert.IsTrue(reader.Read()); // *2* this fails if the initial connection is used
}
}
} // *3* sometimes it throws "System.NotSupportedException: This stream does not support seek operations"
}
---END REPRO 1---
After discovering this issue I tried the following work-around, which revealed more information about the issue. Again
the failure is documented at comment *1*. As it says, apparently if the "bad" connection from the failed LO
operation is retrieved from the pool for the next operation then it is not in a good state. In this case the exception
is "System.IndexOutOfRangeException: Field not found", but that's because the query is returning something
like "select testSelect" (I forget the actual text) and not my real query. Since I was using the string index
notation instead of a numerical ordinal this confused the hell out of me for a while.
My eventual fix was to add a connection.ClearPool() to the end of the main LO failure catch statement (after the
connection.Dispose() block).
---REPRO 2---
[TestMethod()]
public void NpgsqlErrorRepro2()
{
NpgsqlConnection connection = new NpgsqlConnection(_ConnectionString);
connection.Open();
NpgsqlTransaction transaction = connection.BeginTransaction();
LargeObjectManager largeObjectMgr = new LargeObjectManager(connection);
try
{
LargeObject largeObject = largeObjectMgr.Open(-1, LargeObjectManager.READWRITE);
transaction.Commit();
}
catch
{
// ignore the LO failure
try
{
transaction.Dispose();
}
catch
{
// ignore dispose failure
}
try
{
connection.Dispose();
}
catch
{
// ignore dispose failure
}
}
using(connection = new NpgsqlConnection(_ConnectionString))
{
connection.Open();
using(NpgsqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM pg_database";
using(NpgsqlDataReader reader = command.ExecuteReader())
{
Assert.IsTrue(reader.Read());
// *1* this fails if the connection for the pool happens to be the bad one from above
Assert.IsTrue(!String.IsNullOrEmpty((string)reader["datname"]));
}
}
}
}
---END REPRO 2--- |