Skip to content

Commit

Permalink
Fixed case sensitivity on UPDATE statements
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMpn committed Mar 31, 2022
1 parent aeac934 commit 5983b11
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 5 deletions.
25 changes: 25 additions & 0 deletions MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,5 +393,30 @@ public void GlobalVariablesPreservedBetweenCommands()
Assert.AreEqual(1, rowCount);
}
}

[TestMethod]
public void CaseInsensitiveDml()
{
using (var con = new Sql4CdsConnection(_localDataSource))
using (var cmd = con.CreateCommand())
{
cmd.CommandText = "INSERT INTO account (Name) VALUES ('ProperCase')";
cmd.ExecuteNonQuery();

cmd.CommandText = "SELECT @@IDENTITY";
var accountId = (SqlEntityReference)cmd.ExecuteScalar();

Assert.AreEqual("ProperCase", _context.Data["account"][accountId.Id].GetAttributeValue<string>("name"));

cmd.CommandText = "UPDATE account SET NAME = 'UpperCase' WHERE AccountId = @AccountId";
var param = cmd.CreateParameter();
param.ParameterName = "@accountid";
param.Value = accountId.Id;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();

Assert.AreEqual("UpperCase", _context.Data["account"][accountId.Id].GetAttributeValue<string>("name"));
}
}
}
}
2 changes: 1 addition & 1 deletion MarkMpn.Sql4Cds.Engine.Tests/FakeXrmEasyTestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public FakeXrmEasyTestsBase()
_dataSources = new[] { _dataSource, _dataSource2 }.ToDictionary(ds => ds.Name);
_localDataSource = new Dictionary<string, DataSource>
{
["local"] = _dataSource
["local"] = new DataSource { Name = "local", Connection = _service, Metadata = _dataSource.Metadata, TableSizeCache = _dataSource.TableSizeCache }
};

SetPrimaryIdAttributes(_context);
Expand Down
2 changes: 1 addition & 1 deletion MarkMpn.Sql4Cds.Engine/ExecutionPlan/DeleteNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public override string Execute(IDictionary<string, DataSource> dataSources, IQue

// Precompile mappings with type conversions
meta = dataSource.Metadata[LogicalName];
var attributes = meta.Attributes.ToDictionary(a => a.LogicalName);
var attributes = meta.Attributes.ToDictionary(a => a.LogicalName, StringComparer.OrdinalIgnoreCase);
var dateTimeKind = options.UseLocalTimeZone ? DateTimeKind.Local : DateTimeKind.Utc;
var primaryKey = meta.PrimaryIdAttribute;
string secondaryKey = null;
Expand Down
2 changes: 1 addition & 1 deletion MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteAsNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public override string Execute(IDictionary<string, DataSource> dataSources, IQue
// Precompile mappings with type conversions
var meta = dataSource.Metadata["systemuser"];
var attributes = meta.Attributes.ToDictionary(a => a.LogicalName);
var attributeAccessors = CompileColumnMappings(meta, new Dictionary<string, string> { ["systemuserid"] = UserIdSource }, schema, attributes, DateTimeKind.Unspecified, entities);
var attributeAccessors = CompileColumnMappings(meta, new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { ["systemuserid"] = UserIdSource }, schema, attributes, DateTimeKind.Unspecified, entities);
var userIdAccessor = attributeAccessors["systemuserid"];

var userId = (Guid)userIdAccessor(entities[0]);
Expand Down
2 changes: 1 addition & 1 deletion MarkMpn.Sql4Cds.Engine/ExecutionPlan/InsertNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public override string Execute(IDictionary<string, DataSource> dataSources, IQue

// Precompile mappings with type conversions
meta = dataSource.Metadata[LogicalName];
attributes = meta.Attributes.ToDictionary(a => a.LogicalName);
attributes = meta.Attributes.ToDictionary(a => a.LogicalName, StringComparer.OrdinalIgnoreCase);
var dateTimeKind = options.UseLocalTimeZone ? DateTimeKind.Local : DateTimeKind.Utc;
attributeAccessors = CompileColumnMappings(meta, ColumnMappings, schema, attributes, dateTimeKind, entities);
attributeAccessors.TryGetValue(meta.PrimaryIdAttribute, out primaryIdAccessor);
Expand Down
2 changes: 1 addition & 1 deletion MarkMpn.Sql4Cds.Engine/ExecutionPlan/UpdateNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public override string Execute(IDictionary<string, DataSource> dataSources, IQue

// Precompile mappings with type conversions
meta = dataSource.Metadata[LogicalName];
attributes = meta.Attributes.ToDictionary(a => a.LogicalName);
attributes = meta.Attributes.ToDictionary(a => a.LogicalName, StringComparer.OrdinalIgnoreCase);
var dateTimeKind = options.UseLocalTimeZone ? DateTimeKind.Local : DateTimeKind.Utc;
var fullMappings = new Dictionary<string, string>(ColumnMappings);
fullMappings[meta.PrimaryIdAttribute] = PrimaryIdSource;
Expand Down
4 changes: 4 additions & 0 deletions MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,11 +1227,15 @@ private UpdateNode ConvertSetClause(IList<SetClause> setClauses, DataSource data
if (virtualTypeAttributes.Contains(targetAttrName))
{
targetType = typeof(SqlString);

var targetAttribute = attributes[targetAttrName.Substring(0, targetAttrName.Length - 4)];
targetAttrName = targetAttribute.LogicalName + targetAttrName.Substring(targetAttrName.Length - 4, 4).ToLower();
}
else
{
var targetAttribute = attributes[targetAttrName];
targetType = targetAttribute.GetAttributeSqlType();
targetAttrName = targetAttribute.LogicalName;

// If we're updating a lookup field, the field type will be a SqlEntityReference. Change this to
// a SqlGuid so we can accept any guid values, including from TDS endpoint where SqlEntityReference
Expand Down

0 comments on commit 5983b11

Please sign in to comment.