Search code examples
c#sqliteservicestackormlite-servicestack

How do I escape special characters when using ServiceStack OrmLite with SQLite?


We have a piece of code where we try to match a pattern against the data in the database.

We use ServiceStack.OrmLite against our SQLite DB.

So for example, given the below records:

ColA    ColB
-----   ---------
ABC     ABC_Long
GHI     GHI_Long
GHIP    GHIP_Long

We use a predicate as:

var result = db.Select(x => x.ColA.StartsWith("GHI_")); 

Everything works fine until we have a search pattern that includes an SQL special character such as '%' or '_' so for example given the search pattern of "GHI_":

The expected row should be:

GHI     GHI_Long

However we get:

GHI     GHI_Long
GHIP    GHIP_Long

Which is due to ORMLite not escaping the special character and generating the below SQL:

SELECT * FROM myTable WHERE UPPER(colA) LIKE 'GHI_%' OR UPPER(colB) LIKE 'GHI_%';

Instead of the correctly escaped version which should be:

SELECT * FROM myTable WHERE UPPER(colA) LIKE 'GHI\_%' OR UPPER(colB) LIKE 'GHI\_%' ESCAPE '\';

Can you think of a way to address this issue?


Solution

  • I've just added implicit support for escaping wildcards in this commit which will now escape wildcards in the typed expressions that make use of LIKE, namely StartsWith, EndsWith and Contains, e.g:

    using (var db = OpenDbConnection())
    {
        db.DropAndCreateTable<Poco>();
    
        db.Insert(new Poco { Name = "a" });
        db.Insert(new Poco { Name = "ab" });
        db.Insert(new Poco { Name = "a_c" });
        db.Insert(new Poco { Name = "a_cd" });
        db.Insert(new Poco { Name = "abcd" });
        db.Insert(new Poco { Name = "a%" });
        db.Insert(new Poco { Name = "a%b" });
        db.Insert(new Poco { Name = "a%bc" });
        db.Insert(new Poco { Name = "a\\" });
        db.Insert(new Poco { Name = "a\\b" });
        db.Insert(new Poco { Name = "a\\bc" });
    
        Assert.That(db.Count<Poco>(q => q.Name == "a_"), Is.EqualTo(0));
        Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a_")), Is.EqualTo(2));
        Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a%")), Is.EqualTo(3));
        Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a_c")), Is.EqualTo(2));
        Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a\\")), Is.EqualTo(3));
        Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a\\b")), Is.EqualTo(2));
    }
    

    This will be available in v4.0.19 which is now available on MyGet.