Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 5016868

Browse files
committed
Escape wildcards in typed SqlExpression when using StartsWith/EndsWith/Contains
1 parent eac8ab1 commit 5016868

File tree

4 files changed

+55
-10
lines changed

4 files changed

+55
-10
lines changed

src/ServiceStack.OrmLite/Expressions/SqlExpression.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,16 +1305,20 @@ protected virtual object VisitColumnAccessMethod(MethodCallExpression m)
13051305
statement = string.Format("lower({0})", quotedColName);
13061306
break;
13071307
case "StartsWith":
1308-
statement = string.Format("upper({0}) like {1} ",
1309-
quotedColName, OrmLiteConfig.DialectProvider.GetQuotedValue(args[0].ToString().ToUpper() + "%"));
1308+
statement = string.Format("upper({0}) like {1} escape '\\'",
1309+
quotedColName, OrmLiteConfig.DialectProvider.GetQuotedValue(
1310+
OrmLiteConfig.DialectProvider.EscapeWildcards(args[0].ToString()).ToUpper() + "%"));
13101311
break;
13111312
case "EndsWith":
1312-
statement = string.Format("upper({0}) like {1}",
1313-
quotedColName, OrmLiteConfig.DialectProvider.GetQuotedValue("%" + args[0].ToString().ToUpper()));
1313+
statement = string.Format("upper({0}) like {1} escape '\\'",
1314+
quotedColName, OrmLiteConfig.DialectProvider.GetQuotedValue("%" +
1315+
OrmLiteConfig.DialectProvider.EscapeWildcards(args[0].ToString()).ToUpper()));
13141316
break;
13151317
case "Contains":
1316-
statement = string.Format("upper({0}) like {1}",
1317-
quotedColName, OrmLiteConfig.DialectProvider.GetQuotedValue("%" + args[0].ToString().ToUpper() + "%"));
1318+
statement = string.Format("upper({0}) like {1} escape '\\'",
1319+
quotedColName, OrmLiteConfig.DialectProvider.GetQuotedValue("%" +
1320+
OrmLiteConfig.DialectProvider.EscapeWildcards(args[0].ToString()).ToUpper()
1321+
+ "%"));
13181322
break;
13191323
case "Substring":
13201324
var startIndex = Int32.Parse(args[0].ToString()) + 1;

src/ServiceStack.OrmLite/IOrmLiteDialectProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public interface IOrmLiteDialectProvider
2525

2626
bool UseUnicode { get; set; }
2727

28+
string EscapeWildcards(string value);
29+
2830
INamingStrategy NamingStrategy { get; set; }
2931

3032
IStringSerializer StringSerializer { get; set; }

src/ServiceStack.OrmLite/OrmLiteDialectProviderBase.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,5 +1286,15 @@ public virtual string GetQuotedValue(object value, Type fieldType)
12861286
: value.ToString();
12871287
}
12881288

1289+
public virtual string EscapeWildcards(string value)
1290+
{
1291+
if (value == null)
1292+
return null;
1293+
1294+
return value
1295+
.Replace(@"\", @"\\")
1296+
.Replace("_", @"\_")
1297+
.Replace("%", @"\%");
1298+
}
12891299
}
12901300
}

tests/ServiceStack.OrmLite.Tests/Expression/SelectExpressionTests.cs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ public void Can_select_on_Dates()
5959
};
6060

6161
var i = 0;
62-
dates.Each(x => db.Insert(new Submission {
62+
dates.Each(x => db.Insert(new Submission
63+
{
6364
Id = i++,
6465
StoryDate = x,
6566
Headline = "Headline" + i,
@@ -73,8 +74,8 @@ public void Can_select_on_Dates()
7374
Is.EqualTo(3));
7475

7576
var storyDateTime = new DateTime(2014, 1, 1);
76-
Assert.That(db.Select<Submission>(q => q.StoryDate > storyDateTime - new TimeSpan(1,0,0,0) &&
77-
q.StoryDate < storyDateTime + new TimeSpan(1,0,0,0)).Count,
77+
Assert.That(db.Select<Submission>(q => q.StoryDate > storyDateTime - new TimeSpan(1, 0, 0, 0) &&
78+
q.StoryDate < storyDateTime + new TimeSpan(1, 0, 0, 0)).Count,
7879
Is.EqualTo(3));
7980
}
8081
}
@@ -135,7 +136,35 @@ public void Can_select_Partial_SQL_Statements()
135136
Is.EquivalentTo(new[] { "555-UNICORNS", "555-PLANES" }));
136137
Assert.That(partialDto.Map(x => x.CompanyName),
137138
Is.EquivalentTo(new[] { "Planes R Us", "We do everything!" }));
138-
}
139+
}
140+
}
141+
142+
[Test]
143+
public void Can_escape_wildcards()
144+
{
145+
using (var db = OpenDbConnection())
146+
{
147+
db.DropAndCreateTable<Shipper>();
148+
149+
db.Insert(new Shipper { CompanyName = "a" });
150+
db.Insert(new Shipper { CompanyName = "ab" });
151+
db.Insert(new Shipper { CompanyName = "a_c" });
152+
db.Insert(new Shipper { CompanyName = "a_cd" });
153+
db.Insert(new Shipper { CompanyName = "abcd" });
154+
db.Insert(new Shipper { CompanyName = "a%" });
155+
db.Insert(new Shipper { CompanyName = "a%b" });
156+
db.Insert(new Shipper { CompanyName = "a%bc" });
157+
db.Insert(new Shipper { CompanyName = "a\\" });
158+
db.Insert(new Shipper { CompanyName = "a\\b" });
159+
db.Insert(new Shipper { CompanyName = "a\\bc" });
160+
161+
Assert.That(db.Count<Shipper>(q => q.CompanyName == "a_"), Is.EqualTo(0));
162+
Assert.That(db.Count<Shipper>(q => q.CompanyName.StartsWith("a_")), Is.EqualTo(2));
163+
Assert.That(db.Count<Shipper>(q => q.CompanyName.StartsWith("a%")), Is.EqualTo(3));
164+
Assert.That(db.Count<Shipper>(q => q.CompanyName.StartsWith("a_c")), Is.EqualTo(2));
165+
Assert.That(db.Count<Shipper>(q => q.CompanyName.StartsWith(@"a\")), Is.EqualTo(3));
166+
Assert.That(db.Count<Shipper>(q => q.CompanyName.StartsWith(@"a\b")), Is.EqualTo(2));
167+
}
139168
}
140169
}
141170

0 commit comments

Comments
 (0)