2012-04-26 87 views
1

我在尝试参数化ASP应用程序使用的现有C#类中的某些“动态”SQL构建时遇到了问题。环境是:如何使用C#参数化DB2 ODBC查询?

  • 赢服务器2008
  • .NET 3.0
  • C#
  • DB2 9.x的([IBM] [CLI驱动程序] [DB2])

现有代码只是将SQL与参数字符串串联在一个长的SQL字符串中 - 这当然有SQL注入的风险。正如我的做法,每当我看到这一点时,我倾向于更改代码以使用参数。但是,这个代码我失败了。我尝试过“@”,我尝试过“?” - 后者是我所理解的ODBC所必需的。

下面是一个简单的代码片段(原谅我,如果我不格式化正确的 - 这是我的第一个问题),我已经编译和运行:

private DataSet test(String schemaName) 
{ 
     String sortField = "TABLE_NAME.COLUMN_NAME"; 
     String sortDirection = "ASC"; 
     OdbcConnection conn = new OdbcConnection(); 
     DataSet ds = new DataSet(); 

     string connStr = ConfigurationManager.AppSettings[schemaName] + dbUser; 
     try 
     { 
      conn.ConnectionString = connStr; 
      OdbcCommand cmd = new OdbcCommand("SELECT * FROM TABLE_NAME ORDER BY ? ? "); 
      cmd.Connection = conn; 
      cmd.CommandType = CommandType.Text; 
      cmd.Parameters.Add(sortField); 
      cmd.Parameters.Add(sortDirection);        
      logger.log("cmd SQL = \t" + cmd.CommandText); 

      OdbcDataAdapter da = new OdbcDataAdapter(cmd); 
      da.Fill(ds); 

      return ds; 
     } 
     catch (Exception ex) 
     { 
      ex.Data.Add("Location:", "test()"); 
      ex.Data.Add("Connection", conn.ConnectionString); 
      logger.logException(ex); 
      throw ex; 
     } 
     finally 
     { 
      conn.Close(); 
     } 
    } 

日志打印:

CMD SQL = SELECT * FROM TABLE_NAME ORDER BY? ?

其中TABLE_NAME当然是我查询的表格。

我得到的回报是这样(一些专有信息删除:

异常出现在2012年4月26日下午12时29分41秒ERROR [42601] [IBM] [CLI 驱动程序] [ DB2] SQL0104N在“”之后发现了一个意外的令牌“?” 预期令牌可能包括:“MICROSECONDS MICROSECOND SECONDS SECOND MINUTES MINUTE HOURS”SQLSTATE = 42601 at System.Data.Odbc.OdbcConnection.HandleError(OdbcHandle hrHandle, RetCode retcode)连接驱动程序= {IBM DB2 ODBC DRIVER}; .....

不允许将其更改为存储过程。

不允许升级到更高版本的.NET。

不允许更改/升级ODBC驱动程序。

我所看到的告诉我,“?”参数未被替换。

我已经尝试过AddWithValue(),我试过添加(OdbcType.VarChar).Value = sortField(或者那个效果)。

我很善于处理我的问题 - 所有的搜索和搜索都表明我上面的代码应该可以工作,但到目前为止我还没有能够用SQL中的参数替换变量。

在此先感谢。

+0

哦,我已经尝试了 “新OdbcParameter(......)” 太。 – 2012-04-26 20:45:28

+0

我不相信你正在尝试的是真实的参数。 “FieldName =?”是一个参数。在这种情况下,您将构建查询为:“... ORDER BY”+ sortField +“”+ sortDirection – Quintium 2012-04-26 20:46:10

+0

不是SQL参数,而是将C#参数替换为SQL以防止SQL注入。我的例子是简化的,但真正的查询包含用户可以输入的字符串。我想保护SQL,防止父母给孩子起名为“Bobby Tables”(“Robert”); DROP TABLE Students; - “)。 – 2012-04-26 20:49:37

回答

1

?是一个意外标记的原因是因为你在ORDER BY子句中使用它(我认为这是不允许的)。

使用参数的原因是为了减轻用户输入的风险。在构建查询时,如果ORDER BY字段和方向不是通过用户输入发出的,则可以安全地构建具有串联的查询。

只有WHERE子句中使用?

OdbcCommand cmd = new OdbcCommand("SELECT * FROM TABLE_NAME WHERE ID = ? ORDER BY " + sortField + " " + sortDirection); 
+0

你说得对。我刚刚简化了我的例子,太多了。 – 2012-04-26 21:11:31

+0

是的,一旦我使用“FieldName =?”在查询的其余部分,它开始按预期工作。现在我需要了解是否可以将列和模式名称(两者都是可变的)分开。我怀疑不是,但它们不是由用户输入提供的,并且它们是通过调用代码提供的相对安全的。 – 2012-04-26 21:17:23

+0

我怀疑大多数ORM使用concat构建非用户提供的部件,但是然后切换到用户值的参数。我明白你想完成什么,但我不认为ODBC(它具有非常低的功能执行速度)将会支持你。 – mgnoonan 2012-04-26 21:21:20