-
-
Notifications
You must be signed in to change notification settings - Fork 96
mssql improvements, code clean up and fix issue 428 #431
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
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
41308b3
feat(mssql): Minor SQL changes; no functional changes
nealmummau 0f1e5f6
feat(mssql): Minor SQL changes; no functional changes
nealmummau fcb0b01
feat(mssql): Minor SQL changes; no functional changes
nealmummau dedcfeb
feat(mssql): Minor SQL changes; no functional changes
nealmummau 0427f04
feat(mssql): Minor SQL changes; no functional changes
nealmummau f5cc536
feat(mssql): Minor SQL changes; no functional changes
nealmummau 44d86e7
feat(mssql): Minor SQL changes; no functional changes
nealmummau 9e2b609
feat(mssql): Minor SQL updates
nealmummau 70df88e
fix(mssql): Messages.Created NOT NULL
nmummau 7539557
feat(mssql): json is not null
nealmummau df2a662
feat(mssql): DATETIME2 is actually a DATETIME2(7) so explicitly say t…
nealmummau b4fb0c5
feat(mssql): ORDER BY StreamPosition per bito-code-review, and and re…
nealmummau 596563e
feat(postgresql): ORDER BY stream_position per bito-code-review
nealmummau 7b38d67
refactor(mssql): remove square brackets to satisfy 'inconsistent tabl…
nealmummau 2a37166
feat(mssql): append_events improve
nealmummau f84fbc4
perf(mssql): enable OPTIMIZE_FOR_SEQUENTIAL_KEY on primary keys for S…
nealmummau 1599c02
chore(mssql): enable XACT_ABORT for all stored procedures used by Eve…
nealmummau 6718606
fix(mssql): truncate_stream wasn't properly formatting and and sendin…
nealmummau 1dbaf93
refactor(mssql): use SCOPE_IDENTITY() to get new StreamId rather than…
nealmummau 73c56ce
fix(mssql): correct backwards read bounds check
nealmummau aec84c8
fix(mssql): moved stream version update inside TRY block
nealmummau File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 95 additions & 34 deletions
129
src/SqlServer/src/Eventuous.SqlServer/Scripts/2_AppendEvents.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,50 +1,111 @@ | ||
| CREATE OR ALTER PROCEDURE __schema__.append_events | ||
| @stream_name VARCHAR(850), | ||
| @stream_name NVARCHAR(850), | ||
| @expected_version INT, | ||
| @created DATETIME2 NULL, | ||
| @created DATETIME2(7) NULL, | ||
| @messages __schema__.StreamMessage READONLY | ||
| AS | ||
| BEGIN | ||
| DECLARE @current_version INT, | ||
| SET NOCOUNT ON; | ||
| SET XACT_ABORT ON; | ||
|
|
||
| -- Note: This procedure is wrapped in a transaction by the caller. This explains why there is no explicit transaction here within the procedure. | ||
|
|
||
| DECLARE | ||
| @current_version INT, | ||
| @stream_id INT, | ||
| @position BIGINT, | ||
| @customErrorMessage NVARCHAR(200), | ||
| @newMessagesCount INT, | ||
| @expected_StreamVersionAfterUpdate INT, | ||
| @actual_StreamVersionAfterUpdate INT | ||
| @count_messages INT, | ||
| @new_version INT; | ||
|
|
||
| if @created is null | ||
| BEGIN | ||
| SET @created = SYSUTCDATETIME() | ||
| END | ||
| -- capture inserted rows to compute final position | ||
| DECLARE @inserted TABLE ( | ||
| GlobalPosition BIGINT | ||
| ); | ||
|
|
||
| EXEC [__schema__].[check_stream] @stream_name, @expected_version, @current_version = @current_version OUTPUT, @stream_id = @stream_id OUTPUT | ||
| SELECT @count_messages = COUNT(1) FROM @messages; | ||
|
|
||
| EXEC __schema__.check_stream | ||
| @stream_name = @stream_name, | ||
| @expected_version = @expected_version, | ||
| @current_version = @current_version OUTPUT, | ||
| @stream_id = @stream_id OUTPUT; | ||
|
|
||
| SET @new_version = @current_version + @count_messages; | ||
|
|
||
| BEGIN TRY | ||
| INSERT INTO __schema__.Messages (MessageId, MessageType, StreamId, StreamPosition, JsonData, JsonMetadata, Created) | ||
| SELECT message_id, message_type, @stream_id, @current_version + (ROW_NUMBER() OVER(ORDER BY (SELECT NULL))), json_data, json_metadata, @created | ||
| FROM @messages | ||
|
|
||
| /* | ||
| If another writer raced us, the unique constraint (StreamId,StreamPosition) will throw here. | ||
| Translate to WrongExpectedVersion in the CATCH below. | ||
| */ | ||
| INSERT INTO __schema__.Messages ( | ||
| MessageId, | ||
| MessageType, | ||
| StreamId, | ||
| StreamPosition, | ||
| JsonData, | ||
| JsonMetadata, | ||
| Created | ||
| ) | ||
| OUTPUT inserted.GlobalPosition | ||
| INTO @inserted (GlobalPosition) | ||
| SELECT | ||
| message_id, | ||
| message_type, | ||
| @stream_id, | ||
| @current_version + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS INT), | ||
alexeyzimarev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| json_data, | ||
| json_metadata, | ||
| ISNULL(@created, SYSUTCDATETIME()) | ||
| FROM @messages; | ||
|
|
||
| UPDATE s | ||
| SET [Version] = @new_version | ||
| FROM __schema__.Streams s | ||
| WHERE s.StreamId = @stream_id | ||
| AND s.[Version] = @current_version; | ||
|
|
||
| IF @@ROWCOUNT = 0 | ||
| BEGIN | ||
| DECLARE @streamUpdateErrorMessage NVARCHAR(4000) = CONCAT( | ||
| N'WrongExpectedVersion: concurrent update detected for stream ', | ||
| CAST(@stream_id AS NVARCHAR(20)) | ||
| ); | ||
| ;THROW 50000, @streamUpdateErrorMessage, 1; | ||
| END | ||
|
|
||
| END TRY | ||
| BEGIN CATCH | ||
| IF (ERROR_NUMBER() = 2627 OR ERROR_NUMBER() = 2601) AND (SELECT CHARINDEX(N'UQ_StreamIdAndStreamPosition', ERROR_MESSAGE())) > 0 | ||
| DECLARE @errmsg NVARCHAR(2048) = ERROR_MESSAGE(); | ||
|
|
||
| IF ERROR_NUMBER() IN ( | ||
| 2627, -- Violation of PRIMARY KEY or UNIQUE constraint | ||
| 2601 -- Cannot insert duplicate key row in object with unique index | ||
| ) | ||
| AND (@errmsg LIKE N'%UQ_StreamIdAndStreamPosition%') | ||
| BEGIN | ||
| DECLARE @streamIdFromError nvarchar(20) = SUBSTRING(ERROR_MESSAGE(), PATINDEX(N'%[0-9]%,%', ERROR_MESSAGE()), PATINDEX(N'%, [0-9]%).', ERROR_MESSAGE()) - PATINDEX(N'%[0-9]%,%', ERROR_MESSAGE())) | ||
| DECLARE @streamPositionFromError nvarchar(20) = SUBSTRING(ERROR_MESSAGE(), (PATINDEX(N'%, [0-9]%).', ERROR_MESSAGE())) + 2, PATINDEX(N'%).', ERROR_MESSAGE()) - (PATINDEX(N'%, [0-9]%).', ERROR_MESSAGE()) + 2)) | ||
| -- Must BEGIN with "WrongExpectedVersion" for the client detection of OptimisticConcurrencyException | ||
| DECLARE @clientMsg NVARCHAR(4000) = | ||
| N'WrongExpectedVersion: duplicate append for stream ' | ||
| + CAST(@stream_id AS NVARCHAR(20)) | ||
| + N' with expected_version=' + CAST(@expected_version AS NVARCHAR(20)) | ||
| + N'. SQL: ' + @errmsg; | ||
|
|
||
| -- TODO: There are multiple causes of OptimisticConcurrencyExceptions, but current client code is hard-coded to check for 'WrongExpectedVersion' in message and 50000 as error number. | ||
| SELECT @customErrorMessage = FORMATMESSAGE(N'WrongExpectedVersion, another message has already been written at stream position %s on stream %s.', @streamIdFromError, @streamPositionFromError); | ||
| THROW 50000, @customErrorMessage, 1; | ||
| END | ||
| THROW 50000, @clientMsg, 1; | ||
| END; | ||
| ELSE | ||
| THROW | ||
| END CATCH | ||
|
|
||
| SELECT TOP 1 @current_version = StreamPosition, @position = GlobalPosition | ||
| FROM __schema__.Messages | ||
| WHERE StreamId = @stream_id | ||
| ORDER BY GlobalPosition DESC | ||
|
|
||
| UPDATE __schema__.Streams SET Version = @current_version WHERE StreamId = @stream_id | ||
|
|
||
| SELECT @current_version AS current_version, @position AS position | ||
| END | ||
| BEGIN | ||
| ;THROW; | ||
| END; | ||
| END CATCH; | ||
|
|
||
| -- final GlobalPosition value to return | ||
| SELECT @position = ( | ||
| SELECT MAX(GlobalPosition) | ||
| FROM @inserted | ||
| ); | ||
alexeyzimarev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| SELECT | ||
| @new_version current_version, | ||
| @position position; | ||
| END; | ||
58 changes: 38 additions & 20 deletions
58
src/SqlServer/src/Eventuous.SqlServer/Scripts/3_CheckStream.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,43 +1,61 @@ | ||
| CREATE OR ALTER PROCEDURE __schema__.check_stream @stream_name NVARCHAR(850), | ||
| @expected_version int, | ||
| @current_version INT OUTPUT, | ||
| @stream_id INT OUTPUT | ||
| CREATE OR ALTER PROCEDURE __schema__.check_stream | ||
| @stream_name NVARCHAR(850), | ||
| @expected_version INT, | ||
| @current_version INT OUTPUT, | ||
| @stream_id INT OUTPUT | ||
| AS | ||
| BEGIN | ||
| DECLARE @customErrorMessage NVARCHAR(200) | ||
| SET NOCOUNT ON; | ||
| SET XACT_ABORT ON; | ||
|
|
||
| SELECT @current_version = [Version], @stream_id = StreamId | ||
| DECLARE @customErrorMessage NVARCHAR(200); | ||
|
|
||
| SELECT | ||
| @current_version = [Version], | ||
| @stream_id = StreamId | ||
| FROM [__schema__].Streams | ||
| WHERE StreamName = @stream_name | ||
| WHERE StreamName = @stream_name; | ||
|
|
||
| IF @stream_id is null | ||
| IF @stream_id IS NULL | ||
| BEGIN | ||
| IF @expected_version = -2 -- Any | ||
| OR @expected_version = -1 -- NoStream | ||
| BEGIN | ||
| BEGIN TRY | ||
| INSERT INTO [__schema__].Streams (StreamName, Version) VALUES (@stream_name, -1); | ||
| SELECT @current_version = Version, @stream_id = StreamId | ||
| FROM [__schema__].Streams | ||
| WHERE StreamName = @stream_name | ||
| SET @current_version = -1 | ||
| INSERT INTO [__schema__].Streams ( | ||
| StreamName, | ||
| [Version] | ||
| ) VALUES ( | ||
| @stream_name, | ||
| @current_version | ||
| ); | ||
|
|
||
| SET @stream_id = SCOPE_IDENTITY(); | ||
| END TRY | ||
| BEGIN CATCH | ||
| IF (ERROR_NUMBER() = 2627 OR ERROR_NUMBER() = 2601) AND (SELECT CHARINDEX(N'UQ_StreamName', ERROR_MESSAGE())) > 0 | ||
| BEGIN | ||
| SELECT @customErrorMessage = FORMATMESSAGE(N'WrongExpectedVersion %i, stream already exists', @expected_version); | ||
| THROW 50000, @customErrorMessage, 1; | ||
| END | ||
| END; | ||
| ELSE | ||
| THROW | ||
| END CATCH | ||
| END | ||
| BEGIN | ||
| ;THROW; | ||
| END; | ||
| END CATCH; | ||
| END; | ||
| ELSE | ||
| THROW 50001, N'StreamNotFound', 1; | ||
| BEGIN | ||
| ;THROW 50001, N'StreamNotFound', 1; | ||
| END; | ||
| END | ||
| ELSE | ||
| IF @expected_version != -2 and @expected_version != @current_version | ||
| BEGIN | ||
| IF @expected_version != -2 AND @expected_version != @current_version | ||
| BEGIN | ||
| SELECT @customErrorMessage = FORMATMESSAGE(N'WrongExpectedVersion %i, current version %i', @expected_version, @current_version); | ||
| THROW 50000, @customErrorMessage, 1; | ||
| END | ||
| END | ||
| END; | ||
| END; | ||
| END; |
31 changes: 19 additions & 12 deletions
31
src/SqlServer/src/Eventuous.SqlServer/Scripts/4_ReadAllForwards.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,22 @@ | ||
| CREATE OR ALTER PROCEDURE __schema__.read_all_forwards | ||
| @from_position bigint, | ||
| @count int | ||
| AS | ||
| @from_position BIGINT, | ||
alexeyzimarev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @count INT | ||
| AS | ||
| BEGIN | ||
|
|
||
| SELECT TOP (@count) | ||
| MessageId, MessageType, StreamPosition, GlobalPosition, | ||
| JsonData, JsonMetadata, Created, StreamName | ||
| FROM __schema__.Messages | ||
| INNER JOIN __schema__.Streams ON Messages.StreamId = Streams.StreamId | ||
| WHERE Messages.GlobalPosition >= @from_position | ||
| ORDER BY Messages.GlobalPosition | ||
| SET NOCOUNT ON; | ||
| SET XACT_ABORT ON; | ||
|
|
||
| END | ||
| SELECT TOP (@count) | ||
| m.MessageId, | ||
| m.MessageType, | ||
| m.StreamPosition, | ||
| m.GlobalPosition, | ||
| m.JsonData, | ||
| m.JsonMetadata, | ||
| m.Created, | ||
| s.StreamName | ||
| FROM __schema__.Messages m | ||
| JOIN __schema__.Streams s ON m.StreamId = s.StreamId | ||
| WHERE m.GlobalPosition >= @from_position | ||
| ORDER BY m.GlobalPosition; | ||
| END; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.