Skip to content

Commit 713f27a

Browse files
committed
fix postgresql: rollback aborted transaction before pipeline cleanup
commit_hash:eb11ea35fecd2a9dabd32bf95299754c97376160
1 parent 40c349c commit 713f27a

2 files changed

Lines changed: 41 additions & 3 deletions

File tree

postgresql/src/storages/postgres/detail/connection_impl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,9 @@ bool ConnectionImpl::Cleanup(TimeoutDuration timeout) {
763763
if (state == ConnectionState::kTranActive) {
764764
return false;
765765
}
766+
if (state > ConnectionState::kIdle) {
767+
Rollback(deadline);
768+
}
766769
// We might need more timeout here
767770
// We are no more bound with SLA, user has his exception.
768771
// We need to try and save the connection without canceling current query
@@ -781,9 +784,6 @@ bool ConnectionImpl::Cleanup(TimeoutDuration timeout) {
781784
// Reenter pipeline mode if necessary
782785
conn_wrapper_.EnterPipelineMode();
783786
}
784-
if (state > ConnectionState::kIdle) {
785-
Rollback(deadline);
786-
}
787787
return GetConnectionState() == ConnectionState::kIdle;
788788
}
789789

postgresql/src/storages/postgres/tests/connection_transaction_mode_pgtest.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ constexpr pg::CommandControl kTransactionPoolerDefaultCmdCtl{
2424
std::chrono::seconds{10},
2525
std::chrono::seconds{10},
2626
};
27+
constexpr pg::CommandControl kTransactionPoolerNoPrepareCmdCtl{
28+
kTransactionPoolerNetworkTimeout,
29+
kTransactionPoolerStatementTimeout,
30+
pg::CommandControl::PreparedStatementsOptionOverride::kDisabled,
31+
};
2732

2833
pg::ConnectionSettings MakeTransactionPoolerSettings(const pg::ConnectionSettings& base = kCachePreparedStatements) {
2934
auto settings = base;
@@ -214,6 +219,39 @@ UTEST_F(PostgreTransactionModeConnection, TransactionPoolerResendsSetConfigWhenC
214219
EXPECT_TRUE(conn->IsIdle());
215220
}
216221

222+
UTEST_F(PostgreTransactionModeConnection, DuplicatePreparedStatementDirtyConnectionIsCleanedUp) {
223+
const pg::Query query{"SELECT 42"};
224+
225+
std::string statement_name;
226+
{
227+
const auto conn = MakeConn();
228+
UEXPECT_NO_THROW(
229+
statement_name = conn->PrepareStatement(query, {}, utest::kMaxTestWaitTime).meta_statement_name
230+
);
231+
}
232+
ASSERT_FALSE(statement_name.empty());
233+
234+
const DefaultCommandControlScope begin_scope{kTransactionPoolerCmdCtl};
235+
236+
const auto conn = MakeConn();
237+
238+
UEXPECT_NO_THROW(conn->Execute("PREPARE " + statement_name + " AS SELECT 42", {}, kTransactionPoolerNoPrepareCmdCtl)
239+
);
240+
241+
UEXPECT_NO_THROW(conn->Begin({}, {}));
242+
UEXPECT_THROW(conn->Execute(query), pg::DuplicatePreparedStatement);
243+
ASSERT_EQ(pg::ConnectionState::kTranError, conn->GetState());
244+
245+
const DefaultCommandControlScope cleanup_scope{kTransactionPoolerDefaultCmdCtl};
246+
247+
UEXPECT_NO_THROW(conn->Cleanup(utest::kMaxTestWaitTime));
248+
EXPECT_EQ(pg::ConnectionState::kIdle, conn->GetState());
249+
EXPECT_FALSE(conn->IsBroken());
250+
251+
UEXPECT_NO_THROW(conn->Execute("SELECT 1"));
252+
EXPECT_FALSE(conn->IsBroken());
253+
}
254+
217255
} // namespace
218256

219257
USERVER_NAMESPACE_END

0 commit comments

Comments
 (0)