Отладка запроса Coldfusion с помощью cfloop внутри

Я пытаюсь отладить запрос cf и не могу этого сделать из-за его сложной структуры. Код следующий:

<cfquery name="qQuery" datasource="#variables.datasource#">
    <cfloop index="i" from="1" to="#ArrayLen(aSQL)#" step="1">
        <cfif IsSimpleValue(aSQL[i])>
            <cfset temp = aSQL[i]>#Trim(DMPreserveSingleQuotes(temp))#
        <cfelseif IsStruct(aSQL[i])>
            <cfset aSQL[i] = queryparam(argumentCollection=aSQL[i])>
            <cfswitch expression="#aSQL[i].cfsqltype#">
                <cfcase value="CF_SQL_BIT">
                    #getBooleanSqlValue(aSQL[i].value)#
                </cfcase>
                <cfcase value="CF_SQL_DATE,CF_SQL_DATETIME">
                    #CreateODBCDateTime(aSQL[i].value)#
                </cfcase>
                <cfdefaultcase>
                    <!--- <cfif ListFindNoCase(variables.dectypes,aSQL[i].cfsqltype)>#Val(aSQL[i].value)#<cfelse> --->
                    <cfqueryparam value="#aSQL[i].value#" cfsqltype="#aSQL[i].cfsqltype#" maxlength="#aSQL[i].maxlength#" scale="#aSQL[i].scale#" null="#aSQL[i].null#" list="#aSQL[i].list#" separator="#aSQL[i].separator#">
                    <!--- </cfif> --->
                </cfdefaultcase>
            </cfswitch>
        </cfif>                     
    </cfloop>               
</cfquery>

Если я запускаю <cfdump var="#qQuery#">, он не работает, и cfoutput не работает, я получаю неопределенную ошибку qQuery. Как я могу узнать, какой запрос выполняется позади? Я не хочу использовать профайлер MS SQL.

Спасибо,


person user_1856538_    schedule 15.01.2016    source источник
comment
Вне контекста это пугающий способ построения запроса! Можете ли вы предоставить образец aSQL? Это значительно облегчило бы разбор в уме.   -  person beercodebeer    schedule 16.01.2016
comment
Согласен с @beercodebeer, но я думаю, что его проблема в том, что он не может на самом деле создать обычный SQL, который должен выполнять запрос, потому что его CFML портит синтаксис. Он пытается начать отладку, поэтому я предложил cftry ниже.   -  person TRose    schedule 16.01.2016
comment
Что именно вы пытаетесь отладить? Сбой запроса при его запуске? Он просто действует не так, как вы ожидаете? Если вы не можете сбросить запрос, это указывает на то, что что-то довольно серьезное должно идти не так.   -  person Tim Jasko    schedule 16.01.2016
comment
Запустите свою страницу с включенной отладкой. Помимо прочего, вы увидите, действительно ли выполняется запрос. Судя по вашему сообщению об ошибке, скорее всего, нет.   -  person Dan Bracuk    schedule 16.01.2016
comment
Try/catch — очень важный инструмент для устранения неполадок и отладки. -7ffe.html" rel="nofollow noreferrer">обработка ошибок в документации. Кроме того, PreserveSingleQuotes делает вашу базу данных уязвимой для SQL-инъекций. Почитайте cfqueryparam.   -  person Leigh    schedule 17.01.2016


Ответы (5)


Возьмите все внутри запроса и вместо этого оберните его в cfsavecontent. Выведите этот результат.

Если вы поместите cfsavecontent внутри тегов cfquery, вам даже не нужно будет беспокоиться о том, что теги cfqueryparam не будут работать, хотя вам потребуется повторно вывести это сохраненное содержимое внутри запроса. См. http://coldflint.blogspot.com/2016/01/debugging-queries-dirty-way.html

В принципе, у вас должно быть это:

<cfquery name="qQuery" datasource="#variables.datasource#">
    <cfsavecontent variable="sqlContent">
        <cfloop index="i" from="1" to="#ArrayLen(aSQL)#" step="1">
            <cfif IsSimpleValue(aSQL[i])>
                <cfset temp = aSQL[i]>#Trim(DMPreserveSingleQuotes(temp))#
            <cfelseif IsStruct(aSQL[i])>
                <cfset aSQL[i] = queryparam(argumentCollection=aSQL[i])>
                <cfswitch expression="#aSQL[i].cfsqltype#">
                    <cfcase value="CF_SQL_BIT">
                        #getBooleanSqlValue(aSQL[i].value)#
                    </cfcase>
                    <cfcase value="CF_SQL_DATE,CF_SQL_DATETIME">
                        #CreateODBCDateTime(aSQL[i].value)#
                    </cfcase>
                    <cfdefaultcase>
                        <!--- <cfif ListFindNoCase(variables.dectypes,aSQL[i].cfsqltype)>#Val(aSQL[i].value)#<cfelse> --->
                        <cfqueryparam value="#aSQL[i].value#" cfsqltype="#aSQL[i].cfsqltype#" maxlength="#aSQL[i].maxlength#" scale="#aSQL[i].scale#" null="#aSQL[i].null#" list="#aSQL[i].list#" separator="#aSQL[i].separator#">
                        <!--- </cfif> --->
                     </cfdefaultcase>
                 </cfswitch>
             </cfif>                     
         </cfloop>               
    </cfsavecontent>
    #sqlContent#
</cfquery>

<pre>#sqlContent#</pre>

Обязательно верните все в нормальное состояние после завершения отладки.

person Tim Jasko    schedule 15.01.2016
comment
(Редактировать) Хорошая идея, но, к сожалению, CF не будет пытаться использовать cfqueryparam вне тега cfquery. Возможно, вам придется прибегнуть к таким уловкам, как замена < в <cfqueryparam на HTML-эквивалент &lt, чтобы все заработало. Очень неуклюже, но мне приходилось прибегать к этому при отладке устаревших приложений-монстров... - person Leigh; 16.01.2016
comment
Да, очень неуклюже, и это потребует небольшого ручного редактирования, но это, вероятно, самый быстрый шаг на данный момент. - person Tim Jasko; 16.01.2016
comment
Я провел небольшое расследование на основе комментария @Leigh и нашел лучший обходной путь (правда, это все обходной путь) и соответствующим образом обновил свой комментарий. - person Tim Jasko; 16.01.2016
comment
К сожалению, это тоже не вполне сработает. CF увидит любые одинарные кавычки, встроенные в строку (например, с помощью createODBCDateTime), и услужливо избежит их, тем самым нарушив SQL. Честно говоря, я бы просто скопировал и вставил код внутри cfquery, экранировал параметры запроса и вывел бы его на экран. Тогда идите оттуда. Это дублирование, но, вероятно, оно так же хорошо, как и без cfscript. Сказав все это, исходный вопрос очень неоднозначен. Пока запрашивающий не предоставит более конкретную информацию об ошибке и о том, что отлаживается, все, что мы можем сделать, это догадываться... Голосуем за закрытие. - person Leigh; 16.01.2016
comment
Просто мои 2¢, но именно поэтому динамический sql всегда кажется отличной идеей, но на самом деле не очень ;-) Трудно сделать хорошо, а устранение неполадок всегда требует больше времени потребляет больше, чем вы ожидаете. - person Leigh; 16.01.2016
comment
Пробовал и получил следующее: Сообщение: faultCode:Server.Processing faultString: «Невозможно вызвать CFC — переменная SQLCONTENT не определена». ошибкаДеталь:'' - person user_1856538_; 16.01.2016

Если этот вопрос больше о том, КАК отлаживать или получать некоторый результат, с которым вы можете работать, cftry и cfcatch ваши друзья.

<cftry>

---code logic---

<cfcatch>
<cfdump var="#cfcatch#">
</cfcatch>
</cfctry>

Это должно предоставить полный дамп всех ошибок, с которыми сталкивается ColdFusion, а также операторов SQL, которые были предприняты, если действительно есть синтаксическая ошибка, сгенерированная зацикленной логикой.

person TRose    schedule 15.01.2016
comment
Он может добиться того же результата при обычной отладке. Кроме того, в данном случае ошибка является неопределенной переменной, что меняет подход к устранению неполадок. - person Dan Bracuk; 16.01.2016
comment
Вы самый лучший человек! Уоу мне очень помог. На самом деле ‹cftry› следует помещать между ‹cfquery› и ‹cfloop›, а не вне ‹cfquery›. Большое спасибо, чувак! - person user_1856538_; 16.01.2016
comment
Ха, я уже начал думать, что со всеми остальными ответами я сильно ошибся. Рад, что смог помочь. - person TRose; 17.01.2016

Вы должны работать изнутри наружу.

Когда я смотрю на этот запрос, я замечаю, что он разбит на IsSimpleValue() и IsStruct(). Так запусти это

 <cfquery name="qQuery" datasource="#variables.datasource#">
    <cfloop index="i" from="1" to="#ArrayLen(aSQL)#" step="1">
       <cfif IsSimpleValue(aSQL[i])>
            <cfset temp = aSQL[i]>#Trim(DMPreserveSingleQuotes(temp))#
       </cfif>                     
    </cfloop>               
 </cfquery>

Обратите внимание, что temp никогда не используется.

Остальная часть кода создает <cfqueryparam>s

Заключение

Этот код не может работать. Он не может создать действительный SQL.

person James A Mohler    schedule 15.01.2016
comment
не работает :( Я тоже поставил отладчик и не понимаю, почему у меня для sql что-то вроде: [INSERT INTO [Properties_ClientCompanies] (, [property_uid], ,, [client_company_uid], ,, [company_role_uid], ,, [relationship_start], ,, [is_active], ,, [created_by], ,, [created_date], ,, [modified_by], ,, [modified_date], ), VALUES (, {NULL=нет, SEPARATOR=,, PrimaryKey= false, CFSQLTYPE=CF_SQL_IDSTAMP, AllowNulls=NO, VALUE=F812D675-AE0C-898A-3851-753EDC7853D2, MAXLENGTH=‹‹Рекурсивная ссылка — невозможно отобразить значение››... - person user_1856538_; 16.01.2016

Ваша ошибка не имеет ничего общего с sql, генерируемым кодом в блоке cfquery. Это неопределенная переменная. Если бы возникла проблема с отображаемым кодом, сообщение об ошибке было бы другим.

Устраните неполадки следующим образом. Сначала закомментируйте весь код внутри этого запроса и замените его на:

select 1 record

Это справедливо для MS SQL. Оставьте все остальное без изменений.

Запуск страницы выдаст ту же ошибку. Затем необходимо определить, почему запрос не выполняется. Скорее всего, у вас происходит что-то вроде этого:

<cfif some Condition is met>
run the query
</cfif>
dump the query

Вам нужно будет определить, почему ваше условие не было выполнено, и убедиться, что ваша страница работает правильно, если это не так.

person Dan Bracuk    schedule 16.01.2016

Решение состояло в том, чтобы поместить <cftry> вне <cfloop>, но не вне <cfquery>. Я обнаружил, что забыл отправить один параметр.

Итак, код следующий:

        <cfquery name="qQuery" datasource="#variables.datasource#">
                    <cftry>             
                        <cfloop index="i" from="1" to="#ArrayLen(aSQL)#" step="1">
                            <cfif IsSimpleValue(aSQL[i])>
                                <cfset temp = aSQL[i]>#Trim(DMPreserveSingleQuotes(temp))#                          
                            <cfelseif IsStruct(aSQL[i])>
                                <cfset aSQL[i] = queryparam(argumentCollection=aSQL[i])>
                                <cfswitch expression="#aSQL[i].cfsqltype#">
                                    <cfcase value="CF_SQL_BIT">
                                        #getBooleanSqlValue(aSQL[i].value)#
                                    </cfcase>
                                    <cfcase value="CF_SQL_DATE,CF_SQL_DATETIME">
                                        #CreateODBCDateTime(aSQL[i].value)#
                                    </cfcase>
                                    <cfdefaultcase>                                     
                                        <cfqueryparam value="#aSQL[i].value#" cfsqltype="#aSQL[i].cfsqltype#" maxlength="#aSQL[i].maxlength#" scale="#aSQL[i].scale#" null="#aSQL[i].null#" list="#aSQL[i].list#" separator="#aSQL[i].separator#">                                      
                                    </cfdefaultcase>
                                </cfswitch>
                            </cfif>                 
                        </cfloop>
                        <cfcatch>
                            <cfdump var="#cfcatch#" >
                        </cfcatch>
                    </cftry>                            
                </cfquery
person user_1856538_    schedule 16.01.2016