diff --git a/ChangeLog/7.2.0-dev.txt b/ChangeLog/7.2.0-dev.txt index e69de29bb..5bb34edb0 100644 --- a/ChangeLog/7.2.0-dev.txt +++ b/ChangeLog/7.2.0-dev.txt @@ -0,0 +1 @@ +[postgresql] Server-side statement timeout handled as TimeoutException \ No newline at end of file diff --git a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/Driver.cs b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/Driver.cs index 1c132aeea..8c590379e 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/Driver.cs +++ b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/Driver.cs @@ -82,6 +82,12 @@ private SqlExceptionType ProcessServerSideException(PostgresException serverSide return SqlExceptionType.Deadlock; case "40001": // serialization_failure return SqlExceptionType.SerializationFailure; + case "57014": { + // operation timeout due to statement_timeout setting of postgres (global or per session) + if (serverSideException.Message.Contains("statement timeout", StringComparison.OrdinalIgnoreCase)) + return SqlExceptionType.OperationTimeout; + return SqlExceptionType.Unknown; + } } return SqlExceptionType.Unknown; diff --git a/Orm/Xtensive.Orm.Tests.Sql/ExceptionTypesTest.cs b/Orm/Xtensive.Orm.Tests.Sql/ExceptionTypesTest.cs index 8f275a473..1156ccc54 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/ExceptionTypesTest.cs +++ b/Orm/Xtensive.Orm.Tests.Sql/ExceptionTypesTest.cs @@ -31,7 +31,7 @@ private class EvilThreadArgument private const string UniqueTableName = "TheUnique"; private const string CheckedTableName = "TheChecked"; - private Schema schema; + protected Schema schema; protected override void TestFixtureSetUp() { @@ -282,12 +282,12 @@ protected virtual void AssertExceptionType(SqlExceptionType expected, SqlExcepti Assert.AreEqual(expected, actual); } - private void AssertExceptionType(ISqlCompileUnit statement, SqlExceptionType expectedExceptionType) + protected void AssertExceptionType(ISqlCompileUnit statement, SqlExceptionType expectedExceptionType) { AssertExceptionType(Connection, statement, expectedExceptionType); } - private void AssertExceptionType(SqlConnection connection, ISqlCompileUnit statement, SqlExceptionType expectedExceptionType) + protected void AssertExceptionType(SqlConnection connection, ISqlCompileUnit statement, SqlExceptionType expectedExceptionType) { var commandText = Driver.Compile(statement).GetCommandText(); AssertExceptionType(connection, commandText, expectedExceptionType); @@ -305,7 +305,7 @@ private void AssertExceptionType(SqlConnection connection, string commandText, S Assert.Fail("Exception was not thrown"); } - private TableColumn CreatePrimaryKey(Table table) + protected TableColumn CreatePrimaryKey(Table table) { var column = table.CreateColumn(IdColumnName, Driver.TypeMappings[typeof (int)].MapType()); _ = table.CreatePrimaryKey("pk_" + table.Name, column); diff --git a/Orm/Xtensive.Orm.Tests.Sql/PostgreSql/ExceptionTypesTest.cs b/Orm/Xtensive.Orm.Tests.Sql/PostgreSql/ExceptionTypesTest.cs index 9af9d6623..b6b4254cb 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/PostgreSql/ExceptionTypesTest.cs +++ b/Orm/Xtensive.Orm.Tests.Sql/PostgreSql/ExceptionTypesTest.cs @@ -1,19 +1,65 @@ -// Copyright (C) 2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2010-2025 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2010.02.08 +using System.Data; using NUnit.Framework; +using Xtensive.Sql; namespace Xtensive.Orm.Tests.Sql.PostgreSql { [TestFixture] public class ExceptionTypesTest : Sql.ExceptionTypesTest { + private const string PgTimeoutTableName = "PgTheTimeout"; + private const string IdColumnName = "id"; + protected override void CheckRequirements() { Require.ProviderIs(StorageProvider.PostgreSql); } + + protected override void TestFixtureSetUp() + { + base.TestFixtureSetUp(); + Connection.BeginTransaction(); + EnsureTableNotExists(schema, PgTimeoutTableName); + Connection.Commit(); + } + + [Test] + public void PostgreSqlServerSideTimeout() + { + Connection.BeginTransaction(); + var table = schema.CreateTable(PgTimeoutTableName); + _ = CreatePrimaryKey(table); + _ = ExecuteNonQuery(SqlDdl.Create(table)); + Connection.Commit(); + + var tableRef = SqlDml.TableRef(table); + var insert = SqlDml.Insert(tableRef); + insert.AddValueRow((tableRef[IdColumnName], 1)); + + using (var connectionOne = Driver.CreateConnection()) { + connectionOne.Open(); + connectionOne.BeginTransaction(); + using (var command = connectionOne.CreateCommand()) { + command.CommandText = "SET statement_timeout = 15"; + _ = command.ExecuteNonQuery(); + } + + using (var connectionTwo = Driver.CreateConnection()) { + connectionTwo.Open(); + connectionTwo.BeginTransaction(IsolationLevel.ReadCommitted); + + using (var command = connectionTwo.CreateCommand(insert)) { + _ = command.ExecuteNonQuery(); + } + AssertExceptionType(connectionOne, insert, SqlExceptionType.OperationTimeout); + } + } + } } } \ No newline at end of file