Skip to content

Commit

Permalink
Implement savepoint API for Microsoft.Data.Sqlite
Browse files Browse the repository at this point in the history
Closes #20228
  • Loading branch information
roji committed Aug 27, 2020
1 parent 994a69c commit 86b1302
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 3 deletions.
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"tools": {
"dotnet": "5.0.100-preview.8.20417.9",
"dotnet": "5.0.100-rc.1.20427.4",
"runtimes": {
"dotnet": [
"3.1.7"
Expand All @@ -11,7 +11,7 @@
}
},
"sdk": {
"version": "5.0.100-preview.8.20417.9",
"version": "5.0.100-rc.1.20427.4",
"allowPrerelease": true,
"rollForward": "latestMajor"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Microsoft.Data.Sqlite.SqliteException
Microsoft.Data.Sqlite.SqliteFactory
Microsoft.Data.Sqlite.SqliteParameter
Microsoft.Data.Sqlite.SqliteTransaction</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
<MinClientVersion>3.6</MinClientVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<CodeAnalysisRuleSet>Microsoft.Data.Sqlite.Core.ruleset</CodeAnalysisRuleSet>
Expand Down
68 changes: 68 additions & 0 deletions src/Microsoft.Data.Sqlite.Core/SqliteTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,74 @@ public override void Rollback()
RollbackInternal();
}

#if NET5_0
/// <inheritdoc />
public override bool SupportsSavepoints => true;

/// <inheritdoc />
public override void Save(string savepointName)
{
if (savepointName == null)
{
throw new ArgumentNullException(nameof(savepointName));
}

if (string.IsNullOrWhiteSpace(savepointName))
{
throw new ArgumentException($"{nameof(savepointName)} can't be empty", nameof(savepointName));
}

if (_completed || _connection.State != ConnectionState.Open)
{
throw new InvalidOperationException(Resources.TransactionCompleted);
}

_connection.ExecuteNonQuery("SAVEPOINT " + savepointName);
}

/// <inheritdoc />
public override void Rollback(string savepointName)
{
if (savepointName == null)
{
throw new ArgumentNullException(nameof(savepointName));
}

if (string.IsNullOrWhiteSpace(savepointName))
{
throw new ArgumentException($"{nameof(savepointName)} can't be empty", nameof(savepointName));
}

if (_completed || _connection.State != ConnectionState.Open)
{
throw new InvalidOperationException(Resources.TransactionCompleted);
}

_connection.ExecuteNonQuery("ROLLBACK TO " + savepointName);
}

/// <inheritdoc />
public override void Release(string savepointName)
{
if (savepointName == null)
{
throw new ArgumentNullException(nameof(savepointName));
}

if (string.IsNullOrWhiteSpace(savepointName))
{
throw new ArgumentException($"{nameof(savepointName)} can't be empty", nameof(savepointName));
}

if (_completed || _connection.State != ConnectionState.Open)
{
throw new InvalidOperationException(Resources.TransactionCompleted);
}

_connection.ExecuteNonQuery("RELEASE SAVEPOINT " + savepointName);
}
#endif

/// <summary>
/// Releases any resources used by the transaction and rolls it back.
/// </summary>
Expand Down
20 changes: 20 additions & 0 deletions test/Microsoft.Data.Sqlite.Tests/SqliteTransactionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,26 @@ public void Dispose_can_be_called_more_than_once()
}
}

[Fact]
public void Savepoint()
{
using var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();
CreateTestTable(connection);

var transaction = connection.BeginTransaction();
transaction.Save("MySavepointName");

connection.ExecuteNonQuery("INSERT INTO TestTable (TestColumn) VALUES (8)");
Assert.Equal(1L, connection.ExecuteScalar<long>("SELECT COUNT(*) FROM TestTable;"));

transaction.Rollback("MySavepointName");
Assert.Equal(0L, connection.ExecuteScalar<long>("SELECT COUNT(*) FROM TestTable;"));

transaction.Release("MySavepointName");
Assert.Throws<SqliteException>(() => transaction.Rollback("MySavepointName"));
}

private static void CreateTestTable(SqliteConnection connection)
{
connection.ExecuteNonQuery(
Expand Down

0 comments on commit 86b1302

Please sign in to comment.