1

lately, I've seen a lot of people using the Parameters property of an SQLCommand to provide simple values to the query - like this:

var one = "one";
var two = "two";

DataTable results = new DataTable();
string cmdTxt = String.Format("select NAME from TABLE where NAME like @ONE or NAME like @TWO");
using (SqlCommand cmd = new SqlCommand(cmdTxt, Butch.connection))
{
    cmd.Parameters.Add("@ONE", SqlDbType.Char, 15).Value = "%" + one + "%";
    cmd.Parameters.Add("@TWO", SqlDbType.Char, 65).Value = "%" + two + "%";
    using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
           adapter.Fill(results);
 }

Historically, I've just embedded the values in the query string like this:

var one = "one";
var two = "two";

DataTable results = new DataTable();
string cmdTxt = String.Format($"select NAME from TABLE where NAME like '%{one}%' or NAME like '%{two}%");
using (SqlCommand cmd = new SqlCommand(cmdTxt, Butch.connection))
{
    using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
           adapter.Fill(results);
}

I know that there are situations where cmd.Parameters.Add() is specifically useful (like inserting binary data), so I'm not asking about those.

I'm specifically asking:

For a simple value, what is the advantage to using cmd.Parameters.Add() (as in the first code example) rather than embedding that value in the query string (as in the second example)?

Edit to add:

Some of the comments have referenced the fact that I declared variables one and two as hard-coded. I did that so that the example would be complete - naturally, the variables would come from somewhere else.

theGleep
  • 1,179
  • 8
  • 14
  • 1
    Try `var one = "I'd like to search for quotes"`. ("But that's not my value!" No, but wouldn't it be nice if it worked for all values?) – Jeroen Mostert Apr 30 '18 at 22:51
  • 1
    better: [`one = "'; DROP DATABASE --";`](http://bobby-tables.com/) – Dour High Arch Apr 30 '18 at 22:52
  • https://stackoverflow.com/questions/4892166/how-does-sqlparameter-prevent-sql-injection – Harsh Apr 30 '18 at 22:54
  • 2
    In cases where SQL injection is not a concern, and you actually know your values or they're semi-constants, there are circumstances where you'd prefer embedding the constants over using parameters -- but also vice versa, depending on the plans the optimizer generates. Those are advanced cases, though. Your first instinct should always be to use parameters where possible. – Jeroen Mostert Apr 30 '18 at 22:56
  • Possible duplicate of [How does SQLParameter prevent SQL Injection?](https://stackoverflow.com/questions/4892166/how-does-sqlparameter-prevent-sql-injection) – Nick.Mc Apr 30 '18 at 22:56
  • @Nick.McDermaid Not related at all when you are defining the variables/constants you are injecting. – NetMage Apr 30 '18 at 23:27
  • If it is a simple value why aren't you hardcoding the value into the query (e.g. `NAME like %one%`) instead? – NetMage Apr 30 '18 at 23:28
  • Oh I see. In the example the parameter values are never defined externally so can never suffer from SQL Injection. It's just such a weird case I never considered that. – Nick.Mc Apr 30 '18 at 23:33

2 Answers2

3

Using parameters is much better!

To process a query, SQL goes through several steps. First it parses the query text to check its syntax and create an AST representation. Then it gives the AST to the query planner to produce a plan that will be used to execute the query. Then it executes the plan and returns the result.

If you give it the same query text again, it will recognize that and skip the parsing and planning steps, just re-executing the plan. For many queries, parsing and planning take much longer than plan execution, so that can be a tremendous performance gain. When a query is parameterized, the plan itself accepts parameters, so it can be re-used. When values appear literally in the query text, the text needs to be re-parsed and re-planned every time the values change.

Protection against injection is another advantage. If you construct the query text as

command.CommandText = $"SELECT * FROM [Students] WHERE [Name] = '{name}'";

then someone who enters their name as "Robert'; DROP TABLE [Students]" can destroy your DB. But if you use parameterized, fixed query text and add the same name as a parameter,

command.CommandText = "SELECT * FROM [Students] WHERE [Name] = @name";
...
command.Paramers.Add("@name",name);

then the DB will do its job of looking for that name in the DB, without destroying it.

David Wright
  • 765
  • 6
  • 15
0

What the comments try to tell you: To counter attacks using SQL injection. And that relatively effortless for the application programmer.

The values are adequately quoted, escaped and transformed in the right way for the targeted DBMS. That hinders special symbols to be inserted in a way that can change the statement (in a malicious way). You don't have to do that yourself, you cannot forget it or do it wrong e.g. by missing one case.

Bonus: The code is easier to port to target another DBMS. As the logic of how values have to be transformed, in a way the targeted DBMS understands them, is in the driver and no longer the job of the application programmer. It's not always a 100% though.

sticky bit
  • 36,626
  • 12
  • 31
  • 42
  • 1
    This is hardly a complete answer. – Jonathan Wood Apr 30 '18 at 22:57
  • You don't need to use parameters to counter injection. But, it's all too easy (and common) to neglect or not understand how to prevent injection without using them. Without parameters, injection prevention requires the developer to tailor string values (generally by escaping quote characters) in a database-specific manor. – glenebob Apr 30 '18 at 23:06
  • In the code sample, the values are hard coded inside the code, so no chance of sql injection. – Nick.Mc Apr 30 '18 at 23:33