Warning for multiple delete (#931)

* Fix for multiple delete bug

* minor space removal

* removed catch error in RowDelete

* small optimizations

* space adding

* WIP on creating test

* Some cleanup

* removed spaces

* Fix for verifytext

* Added check for command format correctness.

* tidying up

* added working test for command exception

* simplification of TestDbDataReader getint

* Corrections made

* spacing and naming issues

* minor space

* one more space issue
This commit is contained in:
Alex Ma
2020-08-06 13:18:24 -07:00
committed by Karl Burtram
parent 839acf67cd
commit 81b4bb7753
4 changed files with 144 additions and 6 deletions

View File

@@ -5,6 +5,7 @@
using System;
using System.Data.Common;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
@@ -15,6 +16,26 @@ using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
{
/// <summary>
/// An error indicating that a delete action will delete multiple rows.
/// </summary>
public class EditDataDeleteException : Exception
{
public EditDataDeleteException()
{
}
public EditDataDeleteException(string message)
: base(message)
{
}
public EditDataDeleteException(string message, Exception inner)
: base(message, inner)
{
}
}
/// <summary>
/// Represents a row that should be deleted. This will generate a DELETE statement
/// </summary>
@@ -22,6 +43,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
{
private const string DeleteStatement = "DELETE FROM {0} {1}";
private const string DeleteMemoryOptimizedStatement = "DELETE FROM {0} WITH(SNAPSHOT) {1}";
private const string VerifyStatement = "SELECT COUNT (*) FROM ";
/// <summary>
/// Constructs a new RowDelete object
@@ -66,6 +88,11 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
// Return a SqlCommand with formatted with the parameters from the where clause
WhereClause where = GetWhereClause(true);
string commandText = GetCommandText(where.CommandText);
string verifyText = GetVerifyText(where.CommandText);
if (!CheckForDuplicateDeleteRows(where, verifyText, connection))
{
throw new EditDataDeleteException("This action will delete more than one row!");
}
DbCommand command = connection.CreateCommand();
command.CommandText = commandText;
@@ -74,6 +101,38 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
return command;
}
/// <summary>
/// Runs a query using the where clause to determine if duplicates are found (causes issues when deleting).
/// If no duplicates are found, the check passes, else it returns false;
/// </summary>
private bool CheckForDuplicateDeleteRows(WhereClause where, string input, DbConnection connection)
{
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = input;
command.Parameters.AddRange(where.Parameters.ToArray());
using (DbDataReader reader = command.ExecuteReader())
{
try
{
while (reader.Read())
{
//If the count of the row is
if (reader.GetInt32(0) != 1)
{
return false;
}
}
}
catch (Exception ex)
{
Logger.Write(TraceEventType.Error, ex.ToString());
}
}
}
return true;
}
/// <summary>
/// Generates a edit row that represents a row pending deletion. All the original cells are
/// intact but the state is dirty.
@@ -101,6 +160,15 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
return GetCommandText(GetWhereClause(false).CommandText);
}
/// <summary>
/// Generates a WHERE statement to verify the row delete is unique.
/// </summary>
/// <returns>String of the WHERE statement</returns>
public string GetVerifyScript()
{
return GetVerifyText(GetWhereClause(false).CommandText);
}
/// <summary>
/// This method should not be called. A cell cannot be reverted on a row that is pending
/// deletion.
@@ -131,6 +199,11 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
return RowId.CompareTo(rowEdit.RowId) * -1;
}
private string GetVerifyText(string whereText)
{
return $"{VerifyStatement}{AssociatedObjectMetadata.EscapedMultipartName} {whereText}";
}
private string GetCommandText(string whereText)
{
string formatString = AssociatedObjectMetadata.IsMemoryOptimized