在变量中使用语句时,Coldfusion更新查询引发错误

时间:2019-01-31 21:10:44

标签: sql-server coldfusion

尝试使用包含逗号分隔的一组列更新的变量。该变量最终包含有效的SQL(或更准确地说是有效的Coldfusion语法),但是查询引发错误:[Macromedia] [SQLServer JDBC Driver] [SQLServer]'<'附近的语法不正确。

我首先要进行更新:

<cfset sqlString = myColumn & ' = <cfqueryparam value="#myValue#" cfsqltype="#myDataType#" null="#NOT len(trim(myValue))#">'>

然后循环遍历某些表单元素:

<cfset sqlString = sqlString & ', ' & myColumn & ' = <cfqueryparam value="#myValue#" cfsqltype="#myDataType#" null="#NOT len(trim(myValue))#">'>

我最终在sqlString中得到一个完整的字符串,但是出于可读性考虑,它包含以下内容:

id = <cfqueryparam value="123" cfsqltype="cf_sql_integer">,
csp = <cfqueryparam value="5" cfsqltype="cf_sql_integer">,
Q185 = <cfqueryparam value="" cfsqltype="cf_sql_integer" null="YES">,
Q3 = <cfqueryparam value="" cfsqltype="cf_sql_integer" null="YES">,
Q177 = <cfqueryparam value="" cfsqltype="cf_sql_date" null="YES">

所以我尝试在更新查询中使用它:

<cfquery name="update_answers" datasource="#application.datasource#">
   UPDATE answers
   SET    #PreserveSingleQuotes(sqlString)#                                                     
   WHERE  rec_id = #id#
</cfquery>

无论是否使用PreserveSingleQuotes函数,我都尝试过这种方法。

如果我输出sqlString的内容并将其直接粘贴到查询中,则效果很好:

<cfquery name="update_answers" datasource="#application.datasource#">
   UPDATE answers
          id = <cfqueryparam value="123" cfsqltype="cf_sql_integer">,
          csp = <cfqueryparam value="5" cfsqltype="cf_sql_integer">,
          Q185 = <cfqueryparam value="" cfsqltype="cf_sql_integer" null="YES">,
          Q3 = <cfqueryparam value="" cfsqltype="cf_sql_integer" null="YES">,
          Q177 = <cfqueryparam value="" cfsqltype="cf_sql_date" null="YES">                                                    
   WHERE  rec_id = #id#
</cfquery>

同样,我在这里显示换行符是为了提高可读性,但是我是否将sqlString内容粘贴到有或没有换行符的查询中都没有关系;它会工作。

有什么想法吗?

2 个答案:

答案 0 :(得分:5)

tldr;

CFQueryparam不能嵌套在字符串中。必须直接在<cfquery>标签内使用。要使用动态参数构建sql语句,请查看cfscript equivalent of cfqueryparam

安全问题

尽管您可能只是出于绝望而尝试了PreserveSingleQuotes(),但除非您了解其影响,否则从不永远不要使用该函数,因为它基本上会在您的应用程序中造成很大的sql注入漏洞。

  

<cfset sqlString = sqlString & ', ' & myColumn

此外,使用这种动态sql语句要非常小心。即使使用cfqueryparam保护所有参数,该查询仍然容易受到sql注入的攻击,因为myColumn是用户提供的值。不幸的是,cfqueryparam无法保护对象名称(表名称,列名称等),只能保护文字(字符串,日期等)。因此,如果您绝对必须在原始sql中使用动态列名,请确保根据白名单对其进行验证,并在检测到无效列时拒绝该请求。

答案 1 :(得分:0)

您可以使用以下方法。几年前,当我需要动态地构建cfquerparams数组时,我编写了此例程。

我还添加了“ ReadQuery”功能,以防万一将来需要使用它。

它已经在Lucee 4.5(Windows 2008R2)和ACF11(Windows 10)上进行了全面测试。

如果您需要有关调用sysntax的进一步说明,请告诉我,但是我在底部添加了一个示例,以帮助您入门。

这些功能实际上是CFC服务的一部分,但是您可以以独立方式使用它们:

  // 0.0 - default ratio, since "HEC2" is not found
  var multiplier = measurementUnits
    .FirstOrDefault(item => item.Display.Contains("HEC2"))   
   ?.Ratio ?? 0 /* Default Ratio Value Here */;