You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#使用System.Data.SQLite参数化表名查询执行失败报语法错误

问题产生原因
  • 参数化查询的设计定位是仅用于传递SQL语句中的值类型参数,无法用于传递表名、列名、SQL关键字等标识符,这是所有关系型数据库的通用规则,并非System.Data.SQLite库的Bug。
  • SQLite执行SQL时会先做预编译生成执行计划,此时必须确定表名等结构信息才能完成编译,参数是编译完成后执行阶段才会代入的内容,所以预编译阶段识别到@tablename出现在表名位置时,会直接判定为语法错误。
  • 去掉@符号后执行时,SQLite会直接把没有参数标记的tablename当做固定的表名处理,自然不会触发参数替换逻辑。
解决方案

参数化不适用于动态表名场景,需要用「白名单校验 + 安全拼接」的方案同时满足防注入和动态建表的需求:

  1. 预先定义允许操作的表名白名单,所有动态传入的表名必须先经过白名单校验,不合法直接抛出异常,从根源避免SQL注入风险。
  2. 校验通过后将表名安全拼接到SQL语句中,可使用双引号包裹表名避免特殊字符导致的语法问题。

修改后的参考代码如下:

// 预先定义允许创建的表名白名单
private static readonly HashSet<string> AllowedTableNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
    "Service",
    "Business",
    "System"
    // 补充其他允许的表名
};

public void CreateLogTable(string tableName)
{
    // 第一步:校验表名合法性
    if (!AllowedTableNames.Contains(tableName))
    {
        throw new ArgumentException($"非法的表名:{tableName}", nameof(tableName));
    }

    string connectionString = @"Datasource=C:\Users\me\source\repos\sample\bin\Debug\Logs\Log.db3";
    // 第二步:安全拼接SQL,用双引号包裹表名避免特殊字符问题
    string commandText = $"CREATE TABLE IF NOT EXISTS \"{tableName}\" (Timestamp TEXT NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), Loglevel TEXT, Callsite TEXT, Message TEXT);";

    using (SQLiteConnection conn = new SQLiteConnection(connectionString))
    {
        using (SQLiteCommand comm = conn.CreateCommand())
        {
            conn.Open();
            comm.CommandText = commandText;
            comm.ExecuteNonQuery();
        }
    }
}

如果表名是完全不可枚举的自定义场景,除白名单外还需要额外过滤掉SQL关键字、单引号、双引号、分号等特殊字符,进一步规避注入风险。


内容的提问来源于stack exchange,提问作者AngelD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 11:54:03