Как вы, возможно, знаете, когда мы создаем дамп cfquery, он выгружает значения cfqueryparam в SQLPARAMETERS дампа. Было нормально заменить пару параметров вручную. Однако в последнее время я начал работать над проектом, в котором для построения сложных запросов к БД используются десятки (а иногда и больше) cfqueryparams.
есть ли способ напечатать запрос с замененными значениями cfqueryparam и отобразить на экране допустимый оператор sql?
Заранее спасибо!
Был ли какой-либо плагин или фрагмент кода, который я не могу найти или он никогда не был написан?
Мне досталось приложение, которое пришлось переписать несколько десятков запросов, потому что все таблицы и столбцы изменились. Так что я прошел через тот же процесс сброса старого запроса, чтобы увидеть возвращаемые данные. Мне пришлось вручную заменить все параметры запроса вручную в Toad for Oracle. Что я сделал, так это вручную заменил ? на переменную :paramN. Это было утомительно, но теперь работа завершена. Если бы я подумал об этом, я мог бы написать пользовательскую функцию, которая делает это автоматически.
@DanBracuk Этот процесс отлично работает, когда вы разрабатываете что-то новое. Однако иногда вы наследуете старый код, поэтому вам нужно работать в обратном направлении от старого запроса и создавать его дамп с помощью таких инструментов, как Oracle SQL Developer, Toad for Oracle и т. д. Поэтому я понимаю потребность в инструменте для автоматического выполнения этого. Как и спросил ОП, я не знаю об инструменте, но ничто не мешает ему создать его самому.
@DanBracuk Это для того, что мне нужно поддерживать для уже написанного кем-то кода. Иногда мне нужно отлаживать вещи (чаще в наши дни), когда мне по существу нужно создать исполняемый запрос для запуска вне CF (пример: используется около 20 или более переменных cfqueryparam). Спасибо!
@akashb В настоящее время ваш вопрос поиск рекомендательных плагинов или сторонних ресурсов, что немного не по теме этого сайта. Вот почему люди голосуют за его закрытие. Чтобы избежать этого, вы должны добавить информацию, которую вы предоставили в комментариях, перефразировать свой вопрос, чтобы спросить, есть ли внутренний способ сделать это в CFML, и объяснить усилия, которые вы уже приложили к этой проблеме.





Я не знаю никаких встроенных функций или фрагментов кода, которые делают это, но вы можете написать что-нибудь, что работает с простыми типами параметров самый. Причина, по которой говорят «большинство*», заключается в том, что есть несколько осложнений
Массив SQLParameters не включает исходные типы cfsqltype. Таким образом, невозможно окончательно отличить строки (которые должны быть заключены в кавычки) от числовых значений (которые не заключены в кавычки).
Один из способов обойти этот недостаток — использовать внутреннюю службу отладки, которая включает в свой вывод cfsqltypes. Очевидным недостатком является необходимость включения отладки и использование недокументированного внутреннего класса. Однако, поскольку такого рода задачи в любом случае не являются чем-то, что вы обычно выполняете в производстве, это приемлемое ограничение IMO.
К сожалению, ни одна из доступных опций не включает атрибут cfqueryparam null. Поскольку Adobe решила рассматривать нули как пустую строку в списке параметров, невозможно определить, когда значение параметра равно null, а когда на самом деле это пустая строка "". К сожалению, с этим мало что можно сделать. Вероятно, лучшее, что вы можете сделать, это выбрать то, что по умолчанию подходит для вашего приложения: null или пустую строку.
Синтаксис и поддерживаемые типы данных различаются в зависимости от поставщика, поэтому любой код, скорее всего, потребуется настроить для каждой СУБД. Особенно для менее распространенных или сложных типов, таких как 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. Спасибо, куча за это.
Да, это определенно нуждается в настройке :) Спасибо за упоминание QoQ. С ними следует обращаться так же, как с обычными запросами, потому что типы всегда одни и те же, но... этого не произошло, потому что замена "cf_sql_" была чувствительна к регистру, а CF любит использовать заглавные буквы! ;-). Во всяком случае, теперь это исправлено, поэтому он должен обрабатывать все типы данных, кроме refcursor и blob.
Если намерение состоит в том, чтобы выполнить запрос вне ColdFusion, например, Oracle SQL Developer, рассмотрите возможность изменения порядка выполнения действий. Разработайте запрос вне ColdFusion и, как только он заработает должным образом, преобразуйте его в правильный cfquery с параметрами.