Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix some issues with PostgreSQL not running with an english locale #3616

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/CoreTests/adding_custom_schema_objects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public async Task enable_an_extension_with_multitenancy_no_tenants_upfront_does_
martenException.InnerException.ShouldNotBeNull();
martenException.InnerException.As<PostgresException>().ShouldSatisfyAllConditions(
e => e.SqlState.ShouldBe(PostgresErrorCodes.UndefinedFunction),
e => e.MessageText.ShouldBe("function unaccent(unknown) does not exist")
e => e.MessageText.ShouldContain("unaccent(unknown)")
);
}

Expand Down
10 changes: 4 additions & 6 deletions src/DocumentDbTests/Indexes/UniqueIndexTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ public class UniqueUser

public class UniqueIndexTests: OneOffConfigurationsContext
{
public const string UniqueSqlState = "23505";

public UniqueIndexTests()
{
StoreOptions(opts =>
Expand Down Expand Up @@ -90,7 +88,7 @@ public async Task
}
catch (DocumentAlreadyExistsException exception)
{
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}

Expand All @@ -116,7 +114,7 @@ public async Task
}
catch (DocumentAlreadyExistsException exception)
{
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}

Expand Down Expand Up @@ -146,7 +144,7 @@ public async Task
}
catch (MartenCommandException exception)
{
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}

Expand All @@ -173,7 +171,7 @@ public async Task
}
catch (DocumentAlreadyExistsException exception)
{
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}
}
12 changes: 5 additions & 7 deletions src/DocumentDbTests/MultiTenancy/UniqueIndexMultiTenantTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ namespace DocumentDbTests.MultiTenancy;

public class UniqueIndexMultiTenantTests: OneOffConfigurationsContext
{
public const string UniqueSqlState = "23505";

public class Project
{
public Project()
Expand Down Expand Up @@ -69,7 +67,7 @@ public async Task given_two_documents_for_different_tenants_succeeds_using_attri
}
catch (DocumentAlreadyExistsException exception)
{
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}

Expand Down Expand Up @@ -100,7 +98,7 @@ public async Task
}
catch (DocumentAlreadyExistsException exception)
{
((PostgresException)exception.InnerException).SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException).SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}

Expand All @@ -124,7 +122,7 @@ public async Task
}
catch (DocumentAlreadyExistsException exception)
{
((PostgresException)exception.InnerException).SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException).SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}
}
Expand Down Expand Up @@ -157,7 +155,7 @@ public async Task
}
catch (DocumentAlreadyExistsException exception)
{
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException)?.SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}

Expand All @@ -181,7 +179,7 @@ public async Task
}
catch (DocumentAlreadyExistsException exception)
{
((PostgresException)exception.InnerException).SqlState.ShouldBe(UniqueSqlState);
((PostgresException)exception.InnerException).SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public EventStreamUnexpectedMaxEventIdExceptionTransformTest(DefaultStoreFixture
{
}

//[Fact] -- TODO -- too unreliable on CI
[Fact(Skip = "TODO -- too unreliable on CI")]
public async Task throw_transformed_exception_with_details_redacted()
{
await theStore.Storage.ApplyAllConfiguredChangesToDatabaseAsync();
Expand All @@ -38,10 +38,10 @@ await Parallel.ForEachAsync(Enumerable.Range(1, 10), async (_, token) =>
};

(await Should.ThrowAsync<EventStreamUnexpectedMaxEventIdException>(forceEventStreamUnexpectedMaxEventIdException))
.Message.ShouldBe("duplicate key value violates unique constraint \"pk_mt_events_stream_and_version\"");
.Message.ShouldContain("pk_mt_events_stream_and_version");
}

//[Fact] -- TODO -- too unreliable on CI
[Fact(Skip = "TODO -- too unreliable on CI")]
public async Task throw_transformed_exception_with_details_available()
{
await theStore.Storage.ApplyAllConfiguredChangesToDatabaseAsync();
Expand Down
12 changes: 10 additions & 2 deletions src/Marten/Events/EventStore.ConcurrentAppends.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading.Tasks;
using Marten.Exceptions;
using Marten.Storage;
using Npgsql;
using Weasel.Postgresql;

namespace Marten.Events;
Expand Down Expand Up @@ -99,7 +100,10 @@ public async Task AppendExclusive(string streamKey, CancellationToken token, par
}
catch (Exception e)
{
if (e.Message.Contains(MartenCommandException.MaybeLockedRowsMessage) || e.Message.Contains("current transaction is aborted"))
if (e.Message.Contains(MartenCommandException.MaybeLockedRowsMessage) || e.InnerException is NpgsqlException
{
SqlState: PostgresErrorCodes.InFailedSqlTransaction
})
{
throw new StreamLockedException(streamKey, e.InnerException);
}
Expand Down Expand Up @@ -129,10 +133,14 @@ public async Task AppendExclusive(Guid streamId, CancellationToken token, params
}
catch (Exception e)
{
if (e.Message.Contains(MartenCommandException.MaybeLockedRowsMessage) || e.Message.Contains("current transaction is aborted"))
if (e.Message.Contains(MartenCommandException.MaybeLockedRowsMessage) || e.InnerException is NpgsqlException
{
SqlState: PostgresErrorCodes.InFailedSqlTransaction
})
{
throw new StreamLockedException(streamId, e.InnerException);
}

throw;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Marten/Events/Fetching/FetchAsyncPlan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public async Task<IEventStream<TDoc>> FetchForWriting(DocumentSessionBase sessio
}
catch (Exception e)
{
if (e.InnerException is NpgsqlException inner && inner.Message.Contains("current transaction is aborted"))
if (e.InnerException is NpgsqlException { SqlState: PostgresErrorCodes.InFailedSqlTransaction })
{
throw new StreamLockedException(id, e.InnerException);
}
Expand Down Expand Up @@ -256,7 +256,7 @@ public async Task<IEventStream<TDoc>> FetchForWriting(DocumentSessionBase sessio
}
catch (Exception e)
{
if (e.InnerException is NpgsqlException inner && inner.Message.Contains("current transaction is aborted"))
if (e.InnerException is NpgsqlException { SqlState: PostgresErrorCodes.InFailedSqlTransaction })
{
throw new StreamLockedException(id, e.InnerException);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Marten/Events/Fetching/FetchInlinedPlan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public async Task<IEventStream<TDoc>> FetchForWriting(DocumentSessionBase sessio
}
catch (Exception e)
{
if (e.InnerException is NpgsqlException inner && inner.Message.Contains("current transaction is aborted"))
if (e.InnerException is NpgsqlException { SqlState: PostgresErrorCodes.InFailedSqlTransaction })
{
throw new StreamLockedException(id, e.InnerException);
}
Expand Down Expand Up @@ -154,7 +154,7 @@ public async Task<IEventStream<TDoc>> FetchForWriting(DocumentSessionBase sessio
}
catch (Exception e)
{
if (e.InnerException is NpgsqlException inner && inner.Message.Contains("current transaction is aborted"))
if (e.InnerException is NpgsqlException { SqlState: PostgresErrorCodes.InFailedSqlTransaction })
{
throw new StreamLockedException(id, e.InnerException);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Marten/Events/Fetching/FetchLivePlan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public async Task<IEventStream<TDoc>> FetchForWriting(DocumentSessionBase sessio
}
catch (Exception e)
{
if (e.InnerException is NpgsqlException inner && inner.Message.Contains("current transaction is aborted"))
if (e.InnerException is NpgsqlException { SqlState: PostgresErrorCodes.InFailedSqlTransaction })
{
throw new StreamLockedException(id, e.InnerException);
}
Expand Down Expand Up @@ -142,7 +142,7 @@ public async Task<IEventStream<TDoc>> FetchForWriting(DocumentSessionBase sessio
}
catch (Exception e)
{
if (e.InnerException is NpgsqlException inner && inner.Message.Contains("current transaction is aborted"))
if (e.InnerException is NpgsqlException { SqlState: PostgresErrorCodes.InFailedSqlTransaction })
{
throw new StreamLockedException(id, e.InnerException);
}
Expand Down
9 changes: 7 additions & 2 deletions src/Marten/Events/Operations/InsertStreamBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
using System.Threading;
using System.Threading.Tasks;
using JasperFx.Core.Exceptions;
using Marten.Events.Schema;
using Marten.Exceptions;
using Marten.Internal;
using Marten.Internal.Operations;
using Marten.Services;
using Npgsql;
using Weasel.Postgresql;

namespace Marten.Events.Operations;
Expand Down Expand Up @@ -47,8 +49,11 @@ public override string ToString()

private static bool matches(Exception e)
{
return e.Message.Contains("23505: duplicate key value violates unique constraint") &&
e.Message.Contains("streams");
return e is PostgresException
{
SqlState: PostgresErrorCodes.UniqueViolation,
TableName: StreamsTable.TableName
};
}

public bool TryTransform(Exception original, out Exception transformed)
Expand Down
16 changes: 4 additions & 12 deletions src/Marten/Internal/Operations/StorageOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ public interface IRevisionedOperation

public abstract class StorageOperation<T, TId>: IDocumentStorageOperation, IExceptionTransform, IRevisionedOperation
{
private const string ExpectedMessage = "23505: duplicate key value violates unique constraint";


private readonly T _document;
protected readonly TId _id;
private readonly string _tableName;
Expand Down Expand Up @@ -249,16 +246,11 @@ public bool TryTransform(Exception original, out Exception transformed)
original = m.InnerException;
}

if (original.Message.Contains(ExpectedMessage))
if (original is PostgresException { SqlState: PostgresErrorCodes.UniqueViolation } postgresException &&
postgresException.TableName == _tableName)
{
if (original is PostgresException e)
{
if (e.TableName == _tableName)
{
transformed = new DocumentAlreadyExistsException(original, typeof(T), _id);
return true;
}
}
transformed = new DocumentAlreadyExistsException(original, typeof(T), _id);
return true;
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion src/Marten/Internal/ProviderGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ internal DocumentProvider<T> CreateDocumentProvider<T>() where T : notnull
}
catch (Exception e)
{
if (e.Message.Contains("is inaccessible due to its protection level"))
if (e is InvalidOperationException && !mapping.DocumentType.IsPublic)
{
throw new InvalidOperationException(
$"Requested document type '{mapping.DocumentType.FullNameInCode()}' must be scoped as 'public' in order to be used as a document type inside of Marten",
Expand Down
4 changes: 2 additions & 2 deletions src/Marten/Internal/Storage/DocumentStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public void TruncateDocumentStorage(IMartenDatabase database)
}
catch (PostgresException e)
{
if (!e.Message.Contains("does not exist"))
if (e.SqlState != PostgresErrorCodes.UndefinedTable)
{
throw;
}
Expand All @@ -178,7 +178,7 @@ public async Task TruncateDocumentStorageAsync(IMartenDatabase database, Cancell
}
catch (PostgresException e)
{
if (!e.Message.Contains("does not exist"))
if (e.SqlState != PostgresErrorCodes.UndefinedTable)
{
throw;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Marten/Schema/InsertExceptionTransform.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System;
using JasperFx.Core.Exceptions;
using Marten.Exceptions;
using Npgsql;

namespace Marten.Schema;

public sealed class InsertExceptionTransform<T>: IExceptionTransform
{
private const string ExpectedMessage = "23505: duplicate key value violates unique constraint";
private readonly object id;
private readonly string tableName;

Expand All @@ -20,8 +20,8 @@ public bool TryTransform(Exception original, out Exception transformed)
{
transformed = null;

if (original.Message?.IndexOf(ExpectedMessage, StringComparison.OrdinalIgnoreCase) > -1 &&
original.Message?.IndexOf(tableName, StringComparison.Ordinal) > -1)
if (original is PostgresException { SqlState: PostgresErrorCodes.UniqueViolation } postgresException &&
postgresException.TableName == tableName)
{
transformed = new DocumentAlreadyExistsException(original, typeof(T), id);
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,14 @@ namespace Marten.Services;

internal class EventStreamUnexpectedMaxEventIdExceptionTransform: IExceptionTransform
{
private const string ExpectedMessage =
"duplicate key value violates unique constraint \"pk_mt_events_stream_and_version\"";

private const string ExpectedMessageForArchivedStreamParitioning =
"duplicate key value violates unique constraint \"mt_events_default_stream_id_version_is_archived_idx\"";

private const string DetailsRedactedMessage = "Detail redacted as it may contain sensitive data. " +
"Specify 'Include Error Detail' in the connection string to include this information.";

private const string StreamId = "streamid";
private const string Version = "version";

private static readonly Regex EventStreamUniqueExceptionDetailsRegex =
new(@"^Key \(stream_id, version\)=\((?<streamid>.*?), (?<version>\w+)\)");
new(@"\(stream_id, version\)=\((?<streamid>.*?), (?<version>\w+)\)");

public bool TryTransform(Exception original, out Exception transformed)
{
Expand Down Expand Up @@ -73,6 +67,6 @@ private static bool Matches(Exception e)
{
return e is PostgresException pe
&& pe.SqlState == PostgresErrorCodes.UniqueViolation
&& (pe.Message.Contains(ExpectedMessage) || pe.Message.Contains(ExpectedMessageForArchivedStreamParitioning));
&& (pe.ConstraintName == "pk_mt_events_stream_and_version" || pe.ConstraintName == "mt_events_default_stream_id_version_is_archived_idx");
}
}
Loading