Skip to content

fix: prevent XML corruption and identity collisions#170

Merged
DaveRMaltby merged 1 commit into
mainfrom
fix/166-159-data-integrity
Mar 22, 2026
Merged

fix: prevent XML corruption and identity collisions#170
DaveRMaltby merged 1 commit into
mainfrom
fix/166-159-data-integrity

Conversation

@DaveRMaltby
Copy link
Copy Markdown
Contributor

Summary

Fixes two related data integrity issues under concurrent access:

  • XML file corruption during concurrent transaction commits #166 — XML corruption during concurrent transaction commits: FileInsertWriter.Execute() used stale in-memory data during transaction commit, causing data loss when multiple connections committed concurrently. The fix forces a re-read from disk during the commit path (via MarkTableToUpdate + ReadFile) and adds StopWatching/StartWatching in FileTransaction.Commit() to prevent mid-write file watcher events.

  • Bug: FileInsertWriter identity generation uses last row value + 1, causing collisions #159 — Identity collisions after deletions: Identity generation used LastOrDefault() to get the last row's value + 1, which could collide with existing rows when the maximum identity value wasn't in the last row (e.g., after deletions). The fix uses MAX(identity_column) across all rows via a new FindRowWithMaxIdentity method.

Changes

  • FileInsertWriter.cs: Re-read table from disk during commit; use MAX for identity generation
  • FileTransaction.cs: Stop/start file watching around commit writes
  • ConcurrencyTests.cs: Tightened — no longer tolerates XmlException (corruption should not occur)
  • InsertTests.cs: Added Insert_IdentityColumn_AfterDelete_UsesMaxValue test

Closes #166, Closes #159

Test plan

  • All XML/JSON/CSV concurrency tests pass (12 tests)
  • All XML/JSON/CSV insert tests pass (58 tests)
  • All XML/JSON transaction tests pass (23 tests)
  • Build succeeds with 0 errors

🤖 Generated with Claude Code

Issue #166: During transaction commit, FileInsertWriter used stale in-memory
data instead of re-reading from disk, causing data loss when multiple
connections committed concurrently. Fix: force re-read from disk during
commit (via MarkTableToUpdate + ReadFile) and stop/start file watching in
FileTransaction.Commit() to prevent mid-write file watcher events.

Issue #159: Identity generation used the last row's value + 1, which could
collide with existing rows when the maximum identity value wasn't in the
last row position (e.g., after deletions or with non-sequential ordering).
Fix: use MAX(identity_column) across all rows instead of LastOrDefault().

Closes #166, Closes #159

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@DaveRMaltby DaveRMaltby merged commit 4c4c15c into main Mar 22, 2026
1 check passed
@DaveRMaltby DaveRMaltby deleted the fix/166-159-data-integrity branch March 22, 2026 15:35
@github-actions
Copy link
Copy Markdown

Summary

Summary
Generated on: 03/22/2026 - 15:35:31
Coverage date: 03/22/2026 - 15:34:16 - 03/22/2026 - 15:35:16
Parser: MultiReport (8x Cobertura)
Assemblies: 10
Classes: 237
Files: 237
Line coverage: 80.7% (5572 of 6901)
Covered lines: 5572
Uncovered lines: 1329
Coverable lines: 6901
Total lines: 18793
Branch coverage: 66.6% (1672 of 2509)
Covered branches: 1672
Total branches: 2509
Method coverage: Feature is only available for sponsors

Coverage

Data.Common - 77.5%
Name Line Branch
Data.Common 77.5% 67%
Data.Common.DataSource.DataSourceEventArgs 0% 0%
Data.Common.DataSource.FileSystemDataSource 88.5% 68.1%
Data.Common.DataSource.StreamedDataSource 89.4% 50%
Data.Common.DataSource.TableStreamedDataSource 80% 50%
Data.Common.Extension.FileConnectionExtensions 90.9% 87.5%
Data.Common.Extension.FileConnectionStringTestsExtensions 91.6% 80%
Data.Common.Extension.FloatingPointDataTypeExtensions 66.6% 60%
Data.Common.Extension.IEnumerableExtensions 0% 0%
Data.Common.Extension.ObjectExtensions 50%
Data.Common.Extension.StringExtensions 0% 0%
Data.Common.Extension.VirtualDataTableExtensions 0% 0%
Data.Common.FileException.ColumnNotFoundException 0%
Data.Common.FileException.InvalidConnectionStringException 100%
Data.Common.FileException.InvalidFileException 0%
Data.Common.FileException.QueryNotSupportedException 0%
Data.Common.FileException.QuerySyntaxException 0%
Data.Common.FileException.TableNotFoundException 0%
Data.Common.FileException.ThrowHelper 60% 100%
Data.Common.FileIO.Delete.FileDeleteWriter 100% 85.7%
Data.Common.FileIO.FileWriter 100% 83.3%
Data.Common.FileIO.Read.FileEnumerator 90.6% 71.4%
Data.Common.FileIO.Read.FileReader 90.8% 84%
Data.Common.FileIO.SchemaAltering.FileAddColumnWriter 95.4% 60%
Data.Common.FileIO.SchemaAltering.FileCreateTableWriter 93.9% 71.4%
Data.Common.FileIO.SchemaAltering.FileDropColumnWriter 94.1% 66.6%
Data.Common.FileIO.SchemaAltering.FileDropTableWriter 77.2% 58.3%
Data.Common.FileIO.Write.FileInsertWriter 85.4% 80.6%
Data.Common.FileIO.Write.FileUpdateWriter 93.1% 68.1%
Data.Common.FileStatements.Field 0%
Data.Common.FileStatements.FileAddColumn 100%
Data.Common.FileStatements.FileAdminStatement`1 84.6% 71.4%
Data.Common.FileStatements.FileCreateDatabase`1 88.2% 80%
Data.Common.FileStatements.FileCreateTable 87.5% 50%
Data.Common.FileStatements.FileDelete 90.9% 66.6%
Data.Common.FileStatements.FileDropColumn 100%
Data.Common.FileStatements.FileDropDatabase`1 87.5% 81.2%
Data.Common.FileStatements.FileDropTable 83.3% 50%
Data.Common.FileStatements.FileInsert 83.3% 60%
Data.Common.FileStatements.FileSelect 85.7% 100%
Data.Common.FileStatements.FileStatement 100% 100%
Data.Common.FileStatements.FileStatementCreator 86.4% 75%
Data.Common.FileStatements.FileUpdate 92.3% 66.6%
Data.Common.Parsing.AdminGrammar 100%
Data.Common.Parsing.SqlGrammar 100%
Data.Common.Utils.BufferedResetStream 82.8% 76.7%
Data.Common.Utils.BuiltinFunctionProvider 53.3% 40%
Data.Common.Utils.ConcatStream 70.9% 61.9%
Data.Common.Utils.ConnectionString.AliasAttribute 100%
Data.Common.Utils.ConnectionString.FileConnectionString 82.4% 69.7%
Data.Common.Utils.ConnectionString.FileConnectionStringBuilder 31.8% 19.2%
Data.Common.Utils.DatabaseConnectionProvider 100%
Data.Common.Utils.LoggerServices 83.3% 46.1%
Data.Common.Utils.Result 87.1% 73.9%
Data.Common.Utils.StreamedTableManager 73.1% 61.7%
Data.Common.Utils.StreamHolder 100%
Data.Common.Utils.SubStream 70.2% 62.5%
Data.Common.Utils.SubStreamReader 100% 80%
Data.Common.Utils.TransactionLevelData 95% 78.5%
System.Data.FileClient.CloseConnectionDataReader 27.4% 66.6%
System.Data.FileClient.FileCommand`1 82% 82.2%
System.Data.FileClient.FileCommandBuilder`1 94.4% 100%
System.Data.FileClient.FileConnection`1 75.7% 84.3%
System.Data.FileClient.FileDataAdapter`1 83.1% 72.6%
System.Data.FileClient.FileDataReader 69.7% 40.4%
System.Data.FileClient.FileParameter`1 58% 25%
System.Data.FileClient.FileParameterCollection`1 15.9% 13.6%
System.Data.FileClient.FileTransaction`1 86.6% 62.5%
Data.Csv - 90.7%
Name Line Branch
Data.Csv 90.7% 87%
CsvTransformStream 88.1% 86.1%
Data.Csv.CsvIO.CsvDataSetWriter 87.1% 88.8%
Data.Csv.CsvIO.Delete.CsvDelete 100%
Data.Csv.CsvIO.Read.CsvReader 92.5% 100%
Data.Csv.CsvIO.SchemaAltering.CsvAddColumn 100%
Data.Csv.CsvIO.SchemaAltering.CsvCreateTable 100%
Data.Csv.CsvIO.SchemaAltering.CsvDropColumn 100%
Data.Csv.CsvIO.SchemaAltering.CsvDropTable 0%
Data.Csv.CsvIO.Write.CsvInsert 92.8% 91.6%
Data.Csv.CsvIO.Write.CsvUpdate 100%
Data.Csv.Utils.CsvSeparatorDetector 95.8% 71.4%
Data.Csv.Utils.CsvVirtualDataTable 95.3% 85.2%
Data.Csv.Utils.TypeGuesser 100% 94.4%
System.Data.CsvClient.CsvClientFactory 80%
System.Data.CsvClient.CsvCommand 85.7% 83.3%
System.Data.CsvClient.CsvCommandBuilder 100%
System.Data.CsvClient.CsvConnection 85.1% 75%
System.Data.CsvClient.CsvDataAdapter 94.1% 83.3%
System.Data.CsvClient.CsvDataReader 100%
System.Data.CsvClient.CsvParameter 60%
System.Data.CsvClient.CsvTransaction 100%
Data.Json - 81.5%
Name Line Branch
Data.Json 81.5% 71.6%
Data.Json.Extension.JsonElementExtensions 0% 0%
Data.Json.Extension.JsonValueKindExtensions 0% 0%
Data.Json.JsonException.InvalidJsonFileException 0%
Data.Json.JsonException.ThrowHelper 0% 0%
Data.Json.JsonIO.Delete.JsonDelete 100%
Data.Json.JsonIO.JsonDataSetWriter 87.5% 66%
Data.Json.JsonIO.Read.JsonReader 100% 75%
Data.Json.JsonIO.SchemaAltering.JsonAddColumn 100%
Data.Json.JsonIO.SchemaAltering.JsonCreateTable 100%
Data.Json.JsonIO.SchemaAltering.JsonDropColumn 100%
Data.Json.JsonIO.SchemaAltering.JsonDropTable 100%
Data.Json.JsonIO.Write.JsonInsert 87.5% 83.3%
Data.Json.JsonIO.Write.JsonUpdate 100%
Data.Json.Utils.BOMHandlingStream 80.6% 82.3%
Data.Json.Utils.JsonConnectionStringBuilder 83.3% 50%
Data.Json.Utils.JsonDatabaseStreamSplitter 92.6% 81.8%
Data.Json.Utils.JsonDatabaseVirtualDataSet 81.2% 90%
Data.Json.Utils.JsonVirtualDataTable 89.6% 81.3%
Data.Json.Utils.StreamJsonReader 78.9% 73.2%
System.Data.JsonClient.JsonClientFactory 80%
System.Data.JsonClient.JsonCommand 90.9% 88.8%
System.Data.JsonClient.JsonCommandBuilder 100%
System.Data.JsonClient.JsonConnection 87.5%
System.Data.JsonClient.JsonDataAdapter 72.7% 50%
System.Data.JsonClient.JsonDataReader 100%
System.Data.JsonClient.JsonParameter 66.6%
System.Data.JsonClient.JsonTransaction 100%
Data.Tests.Common - 88.4%
Name Line Branch
Data.Tests.Common 88.4% 69.8%
AutoGeneratedProgram 0%
Data.Tests.Common.AlterTableTests 100% 50%
Data.Tests.Common.AsyncTests 100% 100%
Data.Tests.Common.BufferedResetStreamTests 0% 0%
Data.Tests.Common.ClientFactoryTests 100%
Data.Tests.Common.CommandBuilderTests 100%
Data.Tests.Common.CommandTests 100% 100%
Data.Tests.Common.ConcurrencyTests 86.4% 66.6%
Data.Tests.Common.ConnectionStringBuilderTests 100%
Data.Tests.Common.ConnectionTests 100% 66.6%
Data.Tests.Common.CreateTableTests 100%
Data.Tests.Common.DeleteTests 100%
Data.Tests.Common.Extensions.FileConnectionExtensions 42.8% 33.3%
Data.Tests.Common.FileAsDatabase.DataAdapterTests 100% 80%
Data.Tests.Common.FileAsDatabase.DataReaderTests 100% 84.2%
Data.Tests.Common.FileSystemDataSourceTests 0%
Data.Tests.Common.InsertTests 84.8% 50%
Data.Tests.Common.POCOs.TestRecord 100%
Data.Tests.Common.SelectTests 0%
Data.Tests.Common.TransactionTests 97.5%
Data.Tests.Common.UpdateTests 100%
Data.Tests.Common.Utils.ConcatStreamTests 0%
Data.Tests.Common.Utils.ConnectionStringsBase 94.7%
Data.Tests.Common.Utils.CustomDataSourceFactory 100% 100%
Data.Tests.Common.Utils.DatabaseFullPaths 100% 50%
Data.Tests.Common.Utils.FileUtils 90% 83.3%
Data.Tests.Common.Utils.FormFileUtils 100%
Data.Tests.Common.Utils.GrammarParser 0% 0%
Data.Tests.Common.Utils.NonSeekableStream 0% 0%
Data.Tests.Common.Utils.UnendingStream 58.6% 76.9%
Data.Xls - 66.1%
Name Line Branch
Data.Xls 66.1% 49.3%
Data.Xls.DataSource.XlsStreamedDataSource 100% 100%
Data.Xls.Utils.CellExtensions 88.8% 66.6%
Data.Xls.Utils.CsvUtils 100% 100%
Data.Xls.Utils.TypeGuesser 0% 0%
Data.Xls.Utils.WorkbookExtensions 95.6% 75%
Data.Xls.Utils.XlsDatabaseStreamSplitter 100% 83.3%
Data.Xls.Utils.XlsSheetStream 73% 75%
Data.Xls.XlsIO.Read.XlsReader 63.6% 25%
System.Data.XlsClient.XlsClientFactory 50%
System.Data.XlsClient.XlsCommand 15% 5.5%
System.Data.XlsClient.XlsCommandBuilder 66.6%
System.Data.XlsClient.XlsConnection 86.2% 90%
System.Data.XlsClient.XlsDataReader 100%
System.Data.XlsClient.XlsParameter 0%
Data.Xml - 88.2%
Name Line Branch
Data.Xml 88.2% 86.8%
Data.Xml.XmlIO.Delete.XmlDelete 100%
Data.Xml.XmlIO.Read.XmlReader 100% 100%
Data.Xml.XmlIO.SchemaAltering.XmlAddColumn 100%
Data.Xml.XmlIO.SchemaAltering.XmlCreateTable 100%
Data.Xml.XmlIO.SchemaAltering.XmlDropColumn 100%
Data.Xml.XmlIO.SchemaAltering.XmlDropTable 0%
Data.Xml.XmlIO.Write.XmlInsert 75%
Data.Xml.XmlIO.Write.XmlUpdate 100%
Data.Xml.XmlIO.XmlDataSetWriter 84.6% 100%
System.Data.XmlClient.XmlClientFactory 70%
System.Data.XmlClient.XmlCommand 86.3% 88.8%
System.Data.XmlClient.XmlCommandBuilder 100%
System.Data.XmlClient.XmlConnection 100%
System.Data.XmlClient.XmlDataAdapter 72.7% 50%
System.Data.XmlClient.XmlDataReader 100%
System.Data.XmlClient.XmlParameter 60%
System.Data.XmlClient.XmlTransaction 100%
EFCore.Common - 68.5%
Name Line Branch
EFCore.Common 68.5% 53%
EFCore.Common.Design.Internal.FileDesignTimeServices 100%
EFCore.Common.Infrastructure.Internal.FileOptionsExtensionInfo 92.3% 75%
EFCore.Common.Infrastructure.Internal.FileRelationalConnection 100% 100%
EFCore.Common.Query.Internal.FileMathMethodCallTranslator 8.1% 0%
EFCore.Common.Query.Internal.FileMemberTranslator 10.3% 0%
EFCore.Common.Query.Internal.FileMemberTranslatorProvider 100%
EFCore.Common.Query.Internal.FileMethodCallTranslatorProvider 100%
EFCore.Common.Query.Internal.FileStringMethodCallTranslator 60.9% 55.8%
EFCore.Common.Scaffolding.Internal.FileDatabaseModelFactory 100% 83.3%
EFCore.Common.Scaffolding.Internal.FileScaffoldingModelFactory 0%
EFCore.Common.Storage.Internal.FileDatabaseCreator 47.2% 16.6%
EFCore.Common.Storage.Internal.FileTypeMappingSource 96.6% 75%
EFCore.Common.Update.Internal.FileUpdateSqlGeneratorBase 98% 78.5%
EFCore.Common.Utils.OptionsExtensionsHelper 100% 100%
EFCore.Common.Utils.SharedTypeExtensions 100% 50%
EFCore.Csv.Infrastructure.Internal.FileOptionsExtension 85.1% 60%
EFCore.Csv - 68.2%
Name Line Branch
EFCore.Csv 68.2% 46.2%
EFCore.Csv.Design.Internal.CsvDesignTimeServices 100%
EFCore.Csv.Infrastructure.Internal.CsvOptionsExtension 88.8% 100%
EFCore.Csv.Infrastructure.Internal.CsvOptionsExtensionInfo 75%
EFCore.Csv.Metadata.Conventions.CsvConventionSetBuilder 100%
EFCore.Csv.Query.Internal.CsvQuerySqlGenerator 22.2% 20%
EFCore.Csv.Query.Internal.CsvQuerySqlGeneratorFactory 100%
EFCore.Csv.Scaffolding.Internal.CsvCodeGenerator 100% 50%
EFCore.Csv.Scaffolding.Internal.CsvDatabaseModelFactory 100%
EFCore.Csv.Storage.Internal.CsvDatabaseCreator 0% 0%
EFCore.Csv.Storage.Internal.CsvRelationalConnection 100% 100%
EFCore.Csv.Storage.Internal.CsvTypeMappingSource 64.2% 60.5%
EFCore.Csv.Update.Internal.CsvModificationCommandBatchFactory 100%
EFCore.Csv.Update.Internal.CsvUpdateSqlGenerator 100%
Microsoft.EntityFrameworkCore.CsvDbContextOptionsExtensions 43.3% 35.7%
Microsoft.Extensions.DependencyInjection.CsvServiceCollectionExtensions 96.4%
EFCore.Json - 71.8%
Name Line Branch
EFCore.Json 71.8% 57.5%
EFCore.Json.Design.Internal.JsonDesignTimeServices 100%
EFCore.Json.Infrastructure.Internal.JsonOptionsExtension 90% 100%
EFCore.Json.Infrastructure.Internal.JsonOptionsExtensionInfo 75%
EFCore.Json.Metadata.Conventions.JsonConventionSetBuilder 100%
EFCore.Json.Query.Internal.JsonQuerySqlGenerator 0% 0%
EFCore.Json.Query.Internal.JsonQuerySqlGeneratorFactory 60%
EFCore.Json.Scaffolding.Internal.JsonCodeGenerator 100% 50%
EFCore.Json.Scaffolding.Internal.JsonDatabaseModelFactory 100%
EFCore.Json.Storage.Internal.JsonDatabaseCreator 60% 50%
EFCore.Json.Storage.Internal.JsonRelationalConnection 100% 100%
EFCore.Json.Storage.Internal.JsonTypeMappingSource 92.6% 92.1%
EFCore.Json.Update.Internal.JsonModificationCommandBatchFactory 100%
EFCore.Json.Update.Internal.JsonUpdateSqlGenerator 100%
Microsoft.EntityFrameworkCore.JsonDbContextOptionsExtensions 43.3% 35.7%
Microsoft.Extensions.DependencyInjection.JsonServiceCollectionExtensions 96.4%
EFCore.Xml - 73%
Name Line Branch
EFCore.Xml 73% 51.2%
EFCore.Xml.Design.Internal.XmlDesignTimeServices 100%
EFCore.Xml.Infrastructure.Internal.XmlOptionsExtension 90% 100%
EFCore.Xml.Infrastructure.Internal.XmlOptionsExtensionInfo 75%
EFCore.Xml.Metadata.Conventions.XmlConventionSetBuilder 100%
EFCore.Xml.Query.Internal.XmlQuerySqlGenerator 44.4% 35%
EFCore.Xml.Query.Internal.XmlQuerySqlGeneratorFactory 100%
EFCore.Xml.Scaffolding.Internal.XmlCodeGenerator 100% 50%
EFCore.Xml.Scaffolding.Internal.XmlDatabaseModelFactory 100%
EFCore.Xml.Storage.Internal.XmlDatabaseCreator 60% 50%
EFCore.Xml.Storage.Internal.XmlRelationalConnection 100% 100%
EFCore.Xml.Storage.Internal.XmlTypeMappingSource 64.2% 60.5%
EFCore.Xml.Update.Internal.XmlModificationCommandBatchFactory 100%
EFCore.Xml.Update.Internal.XmlUpdateSqlGenerator 100%
Microsoft.EntityFrameworkCore.XmlDbContextOptionsExtensions 43.3% 35.7%
Microsoft.Extensions.DependencyInjection.XmlServiceCollectionExtensions 96.4%

@DaveRMaltby DaveRMaltby restored the fix/166-159-data-integrity branch March 22, 2026 15:36
@DaveRMaltby DaveRMaltby deleted the fix/166-159-data-integrity branch April 5, 2026 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XML file corruption during concurrent transaction commits Bug: FileInsertWriter identity generation uses last row value + 1, causing collisions

1 participant