Skip to content

Commit

Permalink
Migrations: Generate valid SQL when escaping new lines in seed data
Browse files Browse the repository at this point in the history
Resolves #23518
Resolves #23459
  • Loading branch information
smitpatel committed Dec 9, 2020
1 parent 54903bc commit 82a07d7
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 44 deletions.
74 changes: 50 additions & 24 deletions src/EFCore.SqlServer/Storage/Internal/SqlServerStringTypeMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text;
Expand Down Expand Up @@ -171,6 +172,10 @@ protected override string GenerateNonNullSqlLiteral(object value)
int length;
var concatenated = false;
var openApostrophe = false;
var lastConcatStartPoint = 0;
var concatCount = 1;
var concatStartList = new List<int>();
var useOldBehavior = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue23518", out var enabled) && enabled;
for (i = 0; i < stringValue.Length; i++)
{
var lineFeed = stringValue[i] == '\n';
Expand All @@ -183,11 +188,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
{
if (!openApostrophe)
{
if (builder.Length != 0)
{
builder.Append(", ");
concatenated = true;
}
AddConcateOperatorIfNeeded();

if (IsUnicode)
{
Expand All @@ -209,11 +210,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
openApostrophe = false;
}

if (builder.Length != 0)
{
builder.Append(", ");
concatenated = true;
}
AddConcateOperatorIfNeeded();

if (IsUnicode)
{
Expand All @@ -229,11 +226,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
{
if (!openApostrophe)
{
if (builder.Length != 0)
{
builder.Append(", ");
concatenated = true;
}
AddConcateOperatorIfNeeded();

if (IsUnicode)
{
Expand All @@ -253,11 +246,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
{
if (!openApostrophe)
{
if (builder.Length != 0)
{
builder.Append(", ");
concatenated = true;
}
AddConcateOperatorIfNeeded();

if (IsUnicode)
{
Expand All @@ -276,11 +265,21 @@ protected override string GenerateNonNullSqlLiteral(object value)
builder.Append('\'');
}

if (concatenated)
if (useOldBehavior)
{
if (concatenated)
{
builder.Insert(0, "CONCAT(")
.Append(')');
}
}
else
{
builder
.Insert(0, "CONCAT(")
.Append(')');
for (var j = concatStartList.Count - 1; j >= 0; j--)
{
builder.Insert(concatStartList[j], "CONCAT(")
.Append(')');
}
}

if (builder.Length == 0)
Expand All @@ -294,6 +293,33 @@ protected override string GenerateNonNullSqlLiteral(object value)
}

return builder.ToString();

void AddConcateOperatorIfNeeded()
{
if (builder.Length != 0)
{
builder.Append(", ");
if (useOldBehavior)
{
concatenated = true;
}
else
{
concatCount++;

if (concatCount == 2)
{
concatStartList.Add(lastConcatStartPoint);
}

if (concatCount == 254)
{
lastConcatStartPoint = builder.Length;
concatCount = 1;
}
}
}
}
}
}
}
57 changes: 37 additions & 20 deletions src/EFCore.Sqlite.Core/Storage/Internal/SqliteStringTypeMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using JetBrains.Annotations;
Expand Down Expand Up @@ -66,6 +67,9 @@ protected override string GenerateNonNullSqlLiteral(object value)
int length;
var concatenated = false;
var openApostrophe = false;
var concatCount = 1;
var nestedBracketCount = 0;
var useOldBehavior = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue23459", out var enabled) && enabled;
for (i = 0; i < stringValue.Length; i++)
{
var lineFeed = stringValue[i] == '\n';
Expand All @@ -78,11 +82,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
{
if (!openApostrophe)
{
if (builder.Length != 0)
{
builder.Append(" || ");
concatenated = true;
}
AddConcateOperatorIfNeeded();

builder.Append('\'');
openApostrophe = true;
Expand All @@ -99,11 +99,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
openApostrophe = false;
}

if (builder.Length != 0)
{
builder.Append(" || ");
concatenated = true;
}
AddConcateOperatorIfNeeded();

builder
.Append("CHAR(")
Expand All @@ -115,11 +111,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
{
if (!openApostrophe)
{
if (builder.Length != 0)
{
builder.Append(" || ");
concatenated = true;
}
AddConcateOperatorIfNeeded();

builder.Append("'");
openApostrophe = true;
Expand All @@ -137,11 +129,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
{
if (!openApostrophe)
{
if (builder.Length != 0)
{
builder.Append(" || ");
concatenated = true;
}
AddConcateOperatorIfNeeded();

builder.Append('\'');
openApostrophe = true;
Expand All @@ -155,6 +143,15 @@ protected override string GenerateNonNullSqlLiteral(object value)
builder.Append('\'');
}

if (!useOldBehavior)
{
while (nestedBracketCount > 0)
{
builder.Append(")");
nestedBracketCount--;
}
}

if (concatenated)
{
builder
Expand All @@ -168,6 +165,26 @@ protected override string GenerateNonNullSqlLiteral(object value)
}

return builder.ToString();

void AddConcateOperatorIfNeeded()
{
if (builder.Length != 0)
{
builder.Append(" || ");
concatenated = true;

if (!useOldBehavior)
{
concatCount++;
if (concatCount == 998)
{
builder.Append("(");
concatCount = 1;
nestedBracketCount++;
}
}
}
}
}
}
}
26 changes: 26 additions & 0 deletions test/EFCore.Specification.Tests/BuiltInDataTypesTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2084,13 +2084,24 @@ public virtual void Optional_datetime_reading_null_from_database()
}
}

[ConditionalFact]
public virtual void Can_insert_query_multiline_string()
{
using var context = CreateContext();

Assert.Equal(Fixture.ReallyLargeString, Assert.Single(context.Set<StringEnclosure>()).Value);
}

public abstract class BuiltInDataTypesFixtureBase : SharedStoreFixtureBase<PoolableDbContext>
{
protected override string StoreName { get; } = "BuiltInDataTypes";

public virtual int LongStringLength
=> 9000;

public virtual string ReallyLargeString
=> string.Join("", Enumerable.Repeat(Environment.NewLine, 1001));

protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
{
modelBuilder.Entity<BinaryKeyDataType>();
Expand Down Expand Up @@ -2346,6 +2357,14 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.HasData(
new DateTimeEnclosure { Id = 1, DateTimeOffset = new DateTimeOffset(2020, 3, 12, 1, 1, 1, new TimeSpan(3, 0, 0)) },
new DateTimeEnclosure { Id = 2 });

modelBuilder.Entity<StringEnclosure>()
.HasData(
new StringEnclosure
{
Id = 1,
Value = ReallyLargeString
});
}

protected static void MakeRequired<TEntity>(ModelBuilder modelBuilder)
Expand Down Expand Up @@ -3152,5 +3171,12 @@ protected class DateTimeEnclosure
public int Id { get; set; }
public DateTimeOffset? DateTimeOffset { get; set; }
}

protected class StringEnclosure
{
public int Id { get; set; }

public string Value { get; set; }
}
}
}

0 comments on commit 82a07d7

Please sign in to comment.