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

QSqlQuery预准备语句参数数量错误问题求助

问题分析与解决方案

错误根源

  1. 硬编码加密密钥导致解析异常:你直接将加密密钥m_pw拼接进SQL语句,若密钥包含冒号(如pass:123),会被QPSQL驱动误识别为额外的命名占位符,导致预编译时预期参数数量超出实际绑定的数量。
  2. SQL注入风险:直接拼接敏感信息到SQL是严重安全漏洞,可能被攻击者利用。
  3. 逻辑隐患:即使密钥无特殊字符,拼接操作也可能导致驱动对SQL结构的解析出现异常,触发参数数量不匹配的错误。

修复步骤

1. 修改SQL占位符生成逻辑,将密钥作为参数传递

修改getPlaceholderStringForSql函数,把加密密钥改为命名占位符,避免硬编码:

QString BaseDAO::getPlaceholderStringForSql(const QVariantMap& data) const 
{
  QString fields = "(";
  
  int valueCount = data.count();
  const QList<QString> keys = data.keys();
  
  if(valueCount > 0)
  {
    // 处理第一个字段,判断是否为patient表的name字段
    if(!QString::compare(getTableName(), "patient") && !QString::compare(keys[0], "name"))
      fields += "pgp_sym_encrypt(:name, :encryption_key)";
    else
      fields += ":" + keys[0];
  }

  for(int i = 1; i < valueCount; ++i)
  {
    if(!QString::compare(getTableName(), "patient") && !QString::compare(keys[i], "name"))
      fields += ", pgp_sym_encrypt(:name, :encryption_key)";
    else
      fields += ", :" + keys[i];
  }
  fields += ")";

  return fields;
}

2. 扩展参数绑定逻辑,添加加密密钥的绑定

修改bindValuesToQuery函数,在原有绑定逻辑后,额外绑定加密密钥(仅针对patient表):

void BaseDAO::bindValuesToQuery(QSqlQuery& query, const QVariantMap& data) const
{
  const QVariantList valueList = data.values();
  const QList<QString> keys = data.keys();
  int valueCount = valueList.count();
  for (int i = 0; i < valueCount; i++)
  {
    const QVariant &val = valueList[i];
    
    switch(val.type()) {
    case QVariant::Date:
      query.bindValue(":" + keys[i], val.toDate().toString("yyyy-MM-dd"));
      break;
    case QVariant::Time:
      query.bindValue(":" + keys[i], val.toTime().toString("hh:mm:ss.zzz"));
      break;
    case QVariant::DateTime:
      query.bindValue(":" + keys[i], val.toDateTime().toString("yyyy-MM-ddThh:mm:ss.zzz"));
      break;
    default:
      query.bindValue(":" + keys[i], val);
      break;
    }
  }

  // 针对patient表绑定加密密钥参数
  if(!QString::compare(getTableName(), "patient"))
  {
    query.bindValue(":encryption_key", m_pw);
  }
}

验证与调试

修复后生成的SQL语句应为:

INSERT INTO patient ("birthDate", "isMarked", "isProtected", "isTemporary", "modificationDate", "modificationTime", "name", "patientID", "permissionGroup", "sex")
VALUES 
 (:birthDate, :isMarked, :isProtected, :isTemporary, :modificationDate, :modificationTime, pgp_sym_encrypt(:name, :encryption_key), :patientID, :permissionGroup, :sex) 
RETURNING "idx"

调试时可通过query.boundValues()查看所有绑定的参数,确认数量和值是否匹配预期。


额外注意事项

  • 所有动态值(包括敏感信息如加密密钥)必须通过参数绑定传递,禁止直接拼接进SQL,彻底避免SQL注入风险。
  • 即使密钥包含特殊字符(冒号、单引号等),参数绑定会自动处理,无需手动转义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 20:50:34