coldfusion - 如何打印/显示替换了 cfqueryparam 值的 cfquery?

标签 coldfusion cfml cfquery cfqueryparam

您可能知道,当我们转储 cfquery 时,它将 cfqueryparam 值转储到转储的 SQLPARAMETERS 中。手动替换几个参数就可以了。然而,最近我开始从事一个项目,其中有数十个(有时甚至更多)cfqueryparams 用于构建复杂的数据库查询。

是否有办法实际打印替换了 cfqueryparam 值的查询并在屏幕上显示有效的 sql 语句?

提前致谢!

是否有任何插件或一段代码我无法找到或从未编写过?

最佳答案

我不知道有任何内置函数或代码片段可以执行此操作,但您可以编写一些适用于大多数简单参数类型的内容。之所以说“大多数*”是因为有一些复杂的情况

  1. SQLParameters 数组不包含原始 cfsqltypes。因此不可能明确区分字符串(必须加引号)和数值(不加引号)。

    解决该缺陷的一种方法是使用内部调试服务,该服务在其输出中包含 cfsqltypes。一个明显的缺点是它需要启用调试,并使用未记录的内部类。但是,由于这种任务通常不会在生产中运行,因此在我看来这是一个可以接受的限制。

  2. 不幸的是,所有可用选项都不包含 cfqueryparam 的 null 属性。由于 Adob​​e 选择将 null 视为参数列表中的空字符串,因此无法确定参数值何时为 null 以及何时实际上为空字符串 "" 。遗憾的是,对此您无能为力。也许您能做的最好的事情就是选择适合您的应用程序的任何默认值:null 或空字符串。

  3. 语法和支持的数据类型因供应商而异,因此可能需要针对每个 dbms 调整任何代码。特别是对于不太常见或复杂的类型,例如 refcursorblob

    还存在处理字符串参数值中嵌入的单引号的问题。使用replace()来转义单引号应该可以解决问题,但可能会出现边缘情况。


你没有提到你的数据库管理系统,但这里有一个非常粗略的 SQL Server 入门示例。您必须决定如何/是否处理不太常见的类型,例如 refcursor and blob`(当前返回“{{unhandled_type_(typeName)}}”。

演示:

queries = unParameterizeQueries();
for (qry in unParameterizeQueries()) {
   writeOutput("<pre>"& encodeForHTML(qry) &"</pre>");
}

原始查询

<!--- deliberately embed single quotes in string values --->
<cfquery ...>
   SELECT 
         <cfqueryparam value="1234567890" cfsqltype="idstamp"> AS idstampCol
        , <cfqueryparam value="100.50" cfsqltype="money"> AS moneyCol
        , <cfqueryparam value="6789.876423" cfsqltype="float"> AS floatCol
        , <cfqueryparam value="abc '1,2,3'" cfsqltype="char"> AS charCol
        , <cfqueryparam value="10.52" cfsqltype="decimal" scale="2"> AS decimalCol
        , <cfqueryparam value="abc '1,2,3'" cfsqltype="nchar"> AS ncharCol
        , <cfqueryparam value="abc '1,2,3'" cfsqltype="nvarchar"> AS nvarcharCol
        , <cfqueryparam value="#now()#" cfsqltype="timestamp"> AS timestampCol
        , <cfqueryparam value="123.964" cfsqltype="double"> AS doubleCol
        , <cfqueryparam value="123" cfsqltype="cf_sql_tinyint"> AS tinyintCol
        , <cfqueryparam value="123" cfsqltype="integer"> AS integerCol
        , <cfqueryparam value="12345.75" cfsqltype="numeric" scale="2"> AS numericCol
        , <cfqueryparam value="abc '1,2,3'" cfsqltype="longvarchar"> AS longvarcharCol
        , <cfqueryparam value="123" cfsqltype="bigint"> AS bigintCol
        , <cfqueryparam value="#now()#" cfsqltype="time"> AS timeCol
        , <cfqueryparam value="123" cfsqltype="bit"> AS bitCol
        , <cfqueryparam value="#now()#" cfsqltype="date"> AS dateCol
        , <cfqueryparam value='<AdventureWorks2012.Person.Person LastName="Achong" />' cfsqltype="sqlxml"> AS sqlxmlCol
        , <cfqueryparam value="123" cfsqltype="smallint"> AS smallintCol
        , <cfqueryparam value="123" cfsqltype="real"> AS realCol
        , <cfqueryparam value="abc '1,2,3'" cfsqltype="varchar"> AS varcharCol
        , <cfqueryparam cfsqltype="varchar" null="true"> AS NullVarcharCol
</cfquery>

输出

SELECT 

         '1234567890' AS idstampCol
        , 100.5 AS moneyCol
        , 6789.876423 AS floatCol
        , 'abc ''1,2,3''' AS charCol
        , 10.52 AS decimalCol
        , N'abc ''1,2,3''' AS ncharCol
        , N'abc ''1,2,3''' AS nvarcharCol
        , '2022-04-06 02:33:16.59' AS timestampCol
        , 123.964 AS doubleCol
        , 123 AS tinyintCol
        , 123 AS integerCol
        , 12345.75 AS numericCol
        , 'abc ''1,2,3''' AS longvarcharCol
        , 123 AS bigintCol
        , '02:33:16' AS timeCol
        , 1 AS bitCol
        , '2022-04-06' AS dateCol
        , '<AdventureWorks2012.Person.Person LastName="Achong" />' AS sqlxmlCol
        , 123 AS smallintCol
        , 123.0 AS realCol
        , 'abc ''1,2,3''' AS varcharCol
        , NULL AS NullVarcharCol

UDF

public array function unParameterizeQueries() {
    
    // store results 
    local.results = [];
    
    // get debugging service 
    local.svc = createObject("java", "coldfusion.server.ServiceFactory").getDebuggingService().getDebugger();
    local.qry = local.svc.getData();

    // get all queries for request 
    local.allQueries = queryExecute(
        "   SELECT  Attributes AS SQLParameters, Body AS SQLString 
            FROM   qry
            WHERE  Type = :type 
        "
        ,  { type   : "SqlQuery" }
        ,  { dbtype : "query" }
    );
    
    // for each query, replace parameters and output sql 
    local.allQueries.each( function(row, currentRow, qry) {
    
        local.sql = row.SQLString;
        
        row.SQLParameters.each(function(param, index) {
            sql = sql.replace( "?"
                , formatSQLParam( param.value, param.sqlType, true )
                , "one"
            );
        });
        
        results.append( sql );
    });

    return local.results;
}

public string function formatSQLParam( 
        required string paramValue 
        , required string sqlType
        , boolean emptyStringAsNull = true 
){

  local.handleAsString = "char,varchar,longvarchar,date,idstamp,time,timestamp,sqlxml,clob";
  local.handleAsNumeric = "bigint,decimal,double,float,integer,money,money4,numeric,smallint,real,tinyint";
  local.handleAsUnicodeString = "longnvarchar,nchar,nvarchar,nclob";
  local.handleAsBoolean = "bit";
  
  // remove used in old versions "cf_sql_" prefix used in old versions 
  local.typeName = arguments.sqlType.replaceNoCase("cf_sql_", "");
  
  if ( emptyStringAsNull && isSimpleValue(arguments.paramValue) && arguments.paramValue == "" ) {
      local.result = "NULL";
  }
  else if ( local.handleAsString.listFindNoCase(local.typeName) ) {
     local.result = "'"& replace( arguments.paramValue, "'", "''", "all" ) &"'";
  }
  //For sql server, prefix unicode columns with "N"
  else if ( local.handleAsUnicodeString.listFindNoCase(local.typeName) ) {
     local.result = "N'"& replace( arguments.paramValue, "'", "''", "all" ) &"'";
  }
  else if ( local.handleAsNumeric.listFindNoCase(local.typeName) ) {
     local.result = arguments.paramValue ;
  }
  else if ( local.handleAsBoolean.listFindNoCase(local.typeName) ) {
     local.result = arguments.paramValue ? 1 : 0;
  }
  // Otherwise, indicate the type isn't currently handled 
  else {
     local.result = " {{unhandled_type_"& arguments.sqlType &"}}";
  }
  
  return local.result;
}  

关于coldfusion - 如何打印/显示替换了 cfqueryparam 值的 cfquery?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71731941/

相关文章:

cookies - 如何检查 ColdFusion 2016 中是否存在 cookie?

coldfusion - 找不到 CFSCRIPT 例程

coldfusion - 如何处理来自 ColdFusion 查询的空值?

amazon-web-services - AWS 和 Railo 设置

coldfusion - 空白空间/Coldfusion

coldfusion - 从查询查询中选择行范围

mysql - CFQuery where 子句与查询结果的比较

apache - 如何使 cfimage 在 Apache 上与 ColdFusion 10 一起工作?

types - CF9 中的 QueryNew() 数据类型

pdf - Coldfusion/DDX PDF 单页书签