【问题标题】:How do I parameterize a DB2 ODBC query using C#?如何使用 C# 参数化 DB2 ODBC 查询?
【发布时间】:2012-04-26 20:37:36
【问题描述】:

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

  • Win Server 2008
  • .NET 3.0
  • C#
  • DB2 9.x([IBM][CLI 驱动程序][DB2])

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

这是我编译并运行的简化代码 sn-p(请原谅我的格式不正确 - 这是我的第一个问题):

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 错误 [42601] [IBM][CLI Driver][DB2] SQL0104N 意外的标记“?”在“”之后发现。 预期的令牌可能包括:“MICROSECONDS MICROSECOND SECONDS SECOND MINUTES MINUTE HOURS”。SQLSTATE=42601 在 System.Data.Odbc.OdbcConnection.HandleError(OdbcHandle hrHandle,RetCode retcode)连接驱动程序 = {IBM DB2 ODBC 驱动程序}; .....

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

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

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

我所看到的向我表明“?”参数没有被替换。

我已经尝试过 AddWithValue() 并且我已经尝试过 Add(OdbcType.VarChar).Value = sortField(或类似的东西)。

我有点不知所措了——所有的谷歌搜索和搜索都向我表明上面的代码应该可以工作,但到目前为止,我还无法获得用变量替换的 SQL 中的参数。

提前致谢。

【问题讨论】:

  • 哦,我也试过“new OdbcParameter(...)”。
  • 我不相信你正在尝试的是真正的参数。 “字段名 = ?”是一个参数。在这种情况下,您可以将查询构建为:" ... ORDER BY " + sortField + " " + sortDirection
  • 不是 SQL 参数,而是将 C# 参数替换为 SQL 以防止 SQL 注入。我的示例进行了简化,但真正的查询包含用户可以输入的字符串。我想保护 SQL 免受将孩子命名为“Bobby Tables”(“Robert');DROP TABLE Students;--”)的父母。
  • 但是排序顺序和方向来自代码,而不是用户输入。所以 concat 是安全的。

标签: c# odbc db2


【解决方案1】:

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

使用参数的原因是为了减轻用户输入的风险。在构建查询时,如果 ORDER BY 字段和方向不是来自用户输入,您可以安全地构建连接查询。

仅在WHERE 子句中使用?

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

【讨论】:

  • 你是对的。我只是把我的例子简化得太多了。
  • 是的,一旦我使用了“FieldName = ?”在其余的查询中,它开始按预期工作。现在我需要确定是否可以子列和模式名称(两者都是可变的)。我怀疑不是,但它们不是由用户输入提供的,而且它们相对安全,因为它们是由调用代码提供的。
  • 我怀疑大多数 ORM 使用 concat 构建非用户提供的部分,然后切换到用户值的参数。我了解您想要完成的任务,但我认为 ODBC(功能实现率非常低)不会支持您。
  • 谢谢。我有一个在 Java 和 C# 中都使用过的模式,我在代码中遇到了 SQL;我通常使用字符串构建器创建一个静态字符串来创建查询的大部分静态部分,因此不必在每次调用查询时都构建它,然后我将字符串的任何剩余动态部分附加到它上面。我还想在我可以自然地使用参数 - 对于调用者提供查询的某些可变部分的那些部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
相关资源
最近更新 更多