Как распечатать/отобразить cfquery с замененными значениями cfqueryparam?

Как вы, возможно, знаете, когда мы создаем дамп cfquery, он выгружает значения cfqueryparam в SQLPARAMETERS дампа. Было нормально заменить пару параметров вручную. Однако в последнее время я начал работать над проектом, в котором для построения сложных запросов к БД используются десятки (а иногда и больше) cfqueryparams.

есть ли способ напечатать запрос с замененными значениями cfqueryparam и отобразить на экране допустимый оператор sql?

Заранее спасибо!

Был ли какой-либо плагин или фрагмент кода, который я не могу найти или он никогда не был написан?

Если намерение состоит в том, чтобы выполнить запрос вне ColdFusion, например, Oracle SQL Developer, рассмотрите возможность изменения порядка выполнения действий. Разработайте запрос вне ColdFusion и, как только он заработает должным образом, преобразуйте его в правильный cfquery с параметрами.

Dan Bracuk 04.04.2022 14:49

Мне досталось приложение, которое пришлось переписать несколько десятков запросов, потому что все таблицы и столбцы изменились. Так что я прошел через тот же процесс сброса старого запроса, чтобы увидеть возвращаемые данные. Мне пришлось вручную заменить все параметры запроса вручную в Toad for Oracle. Что я сделал, так это вручную заменил ? на переменную :paramN. Это было утомительно, но теперь работа завершена. Если бы я подумал об этом, я мог бы написать пользовательскую функцию, которая делает это автоматически.

user12031119 04.04.2022 15:20

@DanBracuk Этот процесс отлично работает, когда вы разрабатываете что-то новое. Однако иногда вы наследуете старый код, поэтому вам нужно работать в обратном направлении от старого запроса и создавать его дамп с помощью таких инструментов, как Oracle SQL Developer, Toad for Oracle и т. д. Поэтому я понимаю потребность в инструменте для автоматического выполнения этого. Как и спросил ОП, я не знаю об инструменте, но ничто не мешает ему создать его самому.

user12031119 04.04.2022 15:29

@DanBracuk Это для того, что мне нужно поддерживать для уже написанного кем-то кода. Иногда мне нужно отлаживать вещи (чаще в наши дни), когда мне по существу нужно создать исполняемый запрос для запуска вне CF (пример: используется около 20 или более переменных cfqueryparam). Спасибо!

akashb 05.04.2022 00:58

@akashb В настоящее время ваш вопрос поиск рекомендательных плагинов или сторонних ресурсов, что немного не по теме этого сайта. Вот почему люди голосуют за его закрытие. Чтобы избежать этого, вы должны добавить информацию, которую вы предоставили в комментариях, перефразировать свой вопрос, чтобы спросить, есть ли внутренний способ сделать это в CFML, и объяснить усилия, которые вы уже приложили к этой проблеме.

Sebastian Zartner 05.04.2022 11:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не знаю никаких встроенных функций или фрагментов кода, которые делают это, но вы можете написать что-нибудь, что работает с простыми типами параметров самый. Причина, по которой говорят «большинство*», заключается в том, что есть несколько осложнений

  1. Массив SQLParameters не включает исходные типы cfsqltype. Таким образом, невозможно окончательно отличить строки (которые должны быть заключены в кавычки) от числовых значений (которые не заключены в кавычки).

    Один из способов обойти этот недостаток — использовать внутреннюю службу отладки, которая включает в свой вывод cfsqltypes. Очевидным недостатком является необходимость включения отладки и использование недокументированного внутреннего класса. Однако, поскольку такого рода задачи в любом случае не являются чем-то, что вы обычно выполняете в производстве, это приемлемое ограничение IMO.

  2. К сожалению, ни одна из доступных опций не включает атрибут cfqueryparam null. Поскольку Adobe решила рассматривать нули как пустую строку в списке параметров, невозможно определить, когда значение параметра равно null, а когда на самом деле это пустая строка "". К сожалению, с этим мало что можно сделать. Вероятно, лучшее, что вы можете сделать, это выбрать то, что по умолчанию подходит для вашего приложения: null или пустую строку.

  3. Синтаксис и поддерживаемые типы данных различаются в зависимости от поставщика, поэтому любой код, скорее всего, потребуется настроить для каждой СУБД. Особенно для менее распространенных или сложных типов, таких как refcursor или blob.

    Существует также проблема обработки одинарных кавычек, встроенных в значения строковых параметров. Использование 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;
}  

Потрясающий! Я не против включить отладку. {{unhandled_type_(typeName)}} — это то, что я могу улучшить или вообще игнорировать в случае QoQ. Спасибо, куча за это.

akashb 06.04.2022 07:05

Да, это определенно нуждается в настройке :) Спасибо за упоминание QoQ. С ними следует обращаться так же, как с обычными запросами, потому что типы всегда одни и те же, но... этого не произошло, потому что замена "cf_sql_" была чувствительна к регистру, а CF любит использовать заглавные буквы! ;-). Во всяком случае, теперь это исправлено, поэтому он должен обрабатывать все типы данных, кроме refcursor и blob.

SOS 06.04.2022 10:38

Другие вопросы по теме