13

Im trying to perform a parameterized query in SQLite from C#, and the method im using is along the lines of creating a static command with

        SQLiteCommand cmd = new SQLiteCommand(
        "SELECT [ID]" +
            ",[email]" +
            ",[serializedata]" +
            ",[restrictions]" +
        " FROM " + UserTable +
        " WHERE @search = @searchparam", SQLConnection);

        cmd.Parameters.Add(new SQLiteParameter("@searchparam"));
        cmd.Parameters.Add(new SQLiteParameter("@search"));

and calling it like this:

        Command.Parameters["@searchparam"].Value = searchdata;
        Command.Parameters["@search"].Value = search;
        SQLiteDataAdapter slda = new SQLiteDataAdapter(UserSelectUsernameCommand);
        DataSet ds = new DataSet();
        slda.Fill(ds);
        User[] array = new User[ds.Tables[0].Rows.Count];
        int index = 0;
        foreach (DataRow row in ds.Tables[0].Rows)
        {
            array[index] = new User(this, row);
            index++;
        }
        return array;

but im getting an error along the line of " '@search' is not a correct column name " or something like that. if i use a constant column name, and only use the data for parameters it works, but i dont want to create 10 different commands for when i need to search by different column names.

What is the issue here?

IvanP
  • 263
  • 7
  • 21
caesay
  • 16,932
  • 15
  • 95
  • 160
  • If you are avoiding creating 10 different commands because of the inefficiency of tying each one to a SqliteConnection and building up their parameters and CommandText over and over, I'm just making sure that readers know that there is an alternative. SqliteCommand has a parameterless constructor of just new SqliteCommand(); and its Connection property is assignable at run time. So you can create and initialize many commands just once and then assign their Connection property to a SqliteConnection object that is repeatedly created and disposed at run time. – Gary Z Jun 06 '18 at 18:53

2 Answers2

14

Generally things like column names (or table names) can not be parameterised - and the fact that there are different indices means that it will have to be a different plan internally. So you will have to use concatenation - but be careful to white-list the known column names to prevent sql injection:

    SQLiteCommand cmd = new SQLiteCommand(@"
    SELECT [ID],[email],[serializedata],[restrictions]
    FROM " + whiteListedUserTable + @"
    WHERE [" + whiteListedColumnName + @"] = @searchparam", SQLConnection);

    cmd.Parameters.Add(new SQLiteParameter("@searchparam"));
    ...
    Command.Parameters["@searchparam"].Value = searchdata;
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
2

You cannot use a query parameter in that fashion -- to indicate a column name. You can only use it to supply values.

Consider something like this instead:

    SQLiteCommand cmd = new SQLiteCommand(
    "SELECT [ID]" +
        ",[email]" +
        ",[serializedata]" +
        ",[restrictions]" +
    " FROM " + UserTable +
    " WHERE [" + search + "] = @searchparam", SQLConnection);

    cmd.Parameters.Add(new SQLiteParameter("@searchparam"));

If you control all of the input to this function and none if it can be supplied by someone other than you, this should be safe. But if search comes from an untrusted third party, be sure to make the appropriate security checks on the value.

cdhowie
  • 158,093
  • 24
  • 286
  • 300