Guerrilla
Guerrilla

Reputation: 14926

Pass parameters to ExecuteSql()

I am trying to pass a table name as a parameter to the ExecuteSql() method.

This is what I have tried:

        var viewName = "search_view";

        using (var db = dbFactory.Open())
        {
            db.ExecuteSql("REFRESH MATERIALIZED VIEW @viewName;", new { viewName });
        }

It doesn't work, it creates exception with the message of:

Npgsql.PostgresException

42601: syntax error at or near "$1"

I enabled logging to try to see what SQL is generated but I think because of the exception the query isn't logged.

The query runs fine when it is all text, what am I doing wrong passing in the table name as a parameter?

Upvotes: 1

Views: 170

Answers (1)

mythz
mythz

Reputation: 143389

You can only use DB parameters as a replacement for parameters, i.e. you can't use them as a free-text substitution for SQL template generation like you're trying to do.

You would need to use include the viewName in your SQL, e.g:

db.ExecuteSql($"REFRESH MATERIALIZED VIEW {viewName};");

Although if viewName was provided by the user you would need to guard it against possible SQL injection. My recommendation is checking against a white-list of allowed viewNames, e.g:

if (!AllowedViewNames.Contains(viewName))
    throw new Exception("Invalid View");

In OrmLite you can escape a string with GetQuotedValue() API, e.g:

var quotedViewName = db.GetDialectProvider().GetQuotedValue(viewName);

To detect invalid names for symbols like view names you can use a RegEx to only allow valid characters, e.g:

if (!new Regex(@"[^A-Za-z0-9_]").IsMatch(viewName))
    throw new Exception("Invalid View");

Whilst OrmLite's SqlVerifyFragment() extension method lets you detect potentially illegal SQL injection if you wanted to accept an SQL fragment, e.g:

db.ExecuteSql($"SELECT * FROM User WHERE {userSql.SqlVerifyFragment()}");

Where OrmLite will throw an ArgumentException if it detects a potential illegal SQL violation.

Upvotes: 2

Related Questions