Fix global variable placeholder handling.

Reactivate @@ROWCOUNT in INSERT/UPDATE generation.
pull/48/head
Lau 6 years ago
parent e0db14ee1f
commit 7aa5892184

@ -1,8 +1,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
using System.Text;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Update;
using Microsoft.Extensions.DependencyInjection;
namespace EntityFrameworkCore.Jet.Update.Internal
{
@ -49,23 +52,9 @@ namespace EntityFrameworkCore.Jet.Update.Internal
/// </summary>
protected override void AppendRowsAffectedWhereCondition(StringBuilder commandStringBuilder, int expectedRowsAffected)
{
// TODO: Implement translation of @@ROWCOUNT related queries into System.Data.Jet.
// Every the AffectedRecords of every NonQueryExecution needs to be saved per connection,
// so it can be replaced in later queries if needed.
// Other executions should set this saved value just to 0.
// Jet does not support ROWCOUNT
// Here we really hope that ROWCOUNT is not required
// Actually, RecordsAffected is handled by JetModificationCommandBatch
commandStringBuilder
.Append("1 = 1");
/*
commandStringBuilder
.Append("@@ROWCOUNT = ")
.Append(expectedRowsAffected.ToString(CultureInfo.InvariantCulture));
*/
}
/// <summary>

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Data.Common;
using System.Data.Jet.JetStoreSchemaDefinition;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
@ -204,9 +205,7 @@ namespace System.Data.Jet
if ((dataReader = TryGetDataReaderForSelectRowCount(InnerCommand.CommandText)) == null)
{
InnerCommand.CommandText = ParseIdentity(InnerCommand.CommandText);
InnerCommand.CommandText = ParseGuid(InnerCommand.CommandText);
FixupGlobalVariables();
InlineTopParameters();
FixParameters();
@ -263,9 +262,8 @@ namespace System.Data.Jet
return _connection.RowCount;
}
InnerCommand.CommandText = ParseIdentity(InnerCommand.CommandText);
InnerCommand.CommandText = ParseGuid(InnerCommand.CommandText);
FixupGlobalVariables();
if (!CheckExists(InnerCommand.CommandText, out var newCommandText))
return 0;
@ -451,25 +449,36 @@ namespace System.Data.Jet
}
}
private string ParseIdentity(string commandText)
protected virtual void FixupGlobalVariables()
{
// TODO: Fix the following code, that does work only for common scenarios. Use state machine instead.
if (commandText.ToLower()
.Contains("@@identity"))
{
DbCommand command;
command = (DbCommand) ((ICloneable) InnerCommand).Clone();
command.CommandText = "Select @@identity";
var identity = command.ExecuteScalar();
var iIdentity = Convert.ToInt32(identity);
LogHelper.ShowInfo("@@identity = {0}", iIdentity);
return Regex.Replace(commandText, "@@identity", iIdentity.ToString(Globalization.CultureInfo.InvariantCulture), RegexOptions.IgnoreCase);
}
var commandText = InnerCommand.CommandText;
commandText = FixupIdentity(commandText);
commandText = FixupRowCount(commandText);
commandText = FixupGuid(commandText);
return commandText;
InnerCommand.CommandText = commandText;
}
protected virtual string FixupIdentity(string commandText)
=> FixupGlobalVariablePlaceholder(
commandText, "@@identity", (outerCommand, placeholder) =>
{
var command = (DbCommand) ((ICloneable) outerCommand.InnerCommand).Clone();
command.CommandText = $"SELECT {placeholder}";
command.Parameters.Clear();
var identityValue = Convert.ToInt32(command.ExecuteScalar());
LogHelper.ShowInfo($"{placeholder} = {identityValue}");
return identityValue;
});
private string ParseGuid(string commandText)
protected virtual string FixupRowCount(string commandText)
=> FixupGlobalVariablePlaceholder(commandText, "@@rowcount", (outerCommand, placeholder) => outerCommand._connection.RowCount);
protected virtual string FixupGuid(string commandText)
{
// TODO: Fix the following code, that does work only for common scenarios. Use state machine instead.
while (commandText.ToLower()
@ -489,6 +498,26 @@ namespace System.Data.Jet
return commandText;
}
protected virtual string FixupGlobalVariablePlaceholder<T>(string commandText, string placeholder, Func<JetCommand, string, T> valueFactory)
where T : struct
{
var parser = new JetCommandParser(commandText);
var globalVariableIndices = parser.GetStateIndices('$');
var placeholderValue = new Lazy<T>(() => valueFactory(this, placeholder));
var newCommandText = new StringBuilder(commandText);
foreach (var globalVariableIndex in globalVariableIndices)
{
if (commandText.IndexOf(placeholder, globalVariableIndex, placeholder.Length, StringComparison.OrdinalIgnoreCase) > -1)
{
newCommandText.Remove(globalVariableIndex, placeholder.Length);
newCommandText.Insert(globalVariableIndex, placeholderValue.Value);
}
}
return newCommandText.ToString();
}
private void InlineTopParameters()
{
// We inline all TOP clause parameters of all SELECT statements, because Jet does not support parameters
@ -518,11 +547,7 @@ namespace System.Data.Jet
InnerCommand.Parameters.AddRange(parameters.ToArray());
}
}
protected virtual bool IsParameter(string fragment)
=> fragment.StartsWith("@") ||
fragment.Equals("?");
protected virtual DbParameter ExtractParameter(string commandText, int count, List<DbParameter> parameters)
{
var indices = GetParameterIndices(commandText.Substring(0, count));

Loading…
Cancel
Save