CFWheels 'request.wheels.execution' struct dump issues - coldfusion

I am running a cfwheels application on Coldfusion 9 and I need to get the native debug variables of cfhweels to store them in a db table.
I am trying to get #request.wheels.execution# which returns a struct with running times of the controller, action, request. When I dump the struct I am getting a few million milliseconds as running times and the exact same code at the bottom of my screen shows a couple of hundred milliseconds which is the correct times.
Anyone know how these numbers are translated to the numbers showing on the debug section?
This is the code that I got straight from cfwheels that outputs the running times on the bottom of my screen but when I isolate the code the numbers get all messed up again.
<cfif request.wheels.execution.total GT 0>
(<cfset loc.keys = StructSort(request.wheels.execution, "numeric", "desc")>
<cfset loc.firstDone = false>
<cfloop from="1" to="#arrayLen(loc.keys)#" index="loc.i">
<cfset loc.key = loc.keys[loc.i]>
<cfif loc.key IS NOT "total" AND request.wheels.execution[loc.key] GT 0>
<cfif loc.firstDone>
,
</cfif>
#LCase(loc.key)# ~#request.wheels.execution[loc.key]#ms<cfset loc.firstDone = true>
</cfif>
</cfloop>)
</cfif>

The values you're seeing in the debug output are the differences in milliseconds recorded by the framework as it calls getTickCount() at different times during the request.
You can demo this by reloading in design mode and adding this to the top of your layout view:
<cfset ticks = getTickCount() />
Then, as the last line in the view, add this:
<cfoutput>
this view took #getTickCount()-ticks# milliseconds to process.
</cfoutput>

Related

CF9: What is this evaluate statement evaluating?

I'm stuck and need a fresh set of eyes on this, please.
I'm working with someone else's spaghetti code who is no longer around and having a heck of a time figuring out what they were evaluating.
<cfset surveyCount = 0>
<cfloop query="surveys">
<cfif evaluate("defaultReport" & ID)>
<cfset surveyCount = surveyCount + 1>
</cfif>
</cfloop>
In the query dump, I see 9 records which is what I am expecting but because because the evaluate is failing, the surveyCount isn't being incremented. I do not see any columns for defaultReport. In my 15 years of working with CF, I've always avoided evaluate() and now when I need to analyze it, I'm at a complete loss. Can someone offer any guidance?
Added CFDump image (some columns names have been removed for privacy and security):
UPDATE I:
This file has numerous cfinclude statements and very little code formatting. As a result, I overlooked some cfinclude statements. I found the following. I'm still looking but wanted to document this as I dig.
<cfloop query="surveys">
<cfscript>
variables["defaultReport" & ID] = evaluate(thisAssociation & "Price");
</cfscript>
</cfloop>
UPDATE II:
Dumping the variable scope, I did confirm the variable I am looking for (finding the query I posted in UPDATE I helped, too). :)
What they wanted to do is to increase surveyCount but only if this thing: evaluate("defaultReport" & ID) evaluates to true.
From your query dump picture it looks like the IDs are numbers like 144, 145, etc...
In this context, you can think at evaluate("defaultReport" & ID) as something like defaultReport144, defaultReport145, etc... (these are variables set somewhere in the code).
So the code:
<cfif evaluate("defaultReport" & ID)>
<cfset surveyCount = surveyCount + 1>
</cfif>
becomes (for an ID of 144, the first one on your query loop)
<cfif defaultReport144>
<cfset surveyCount = surveyCount + 1>
</cfif>
and so on... for the other IDs
So, search your code for where variables like defaultReport144, defaultReport145, etc... are set to either true or false (0 or 1).
Something like:
<cfset defaultReport144 = true />
or maybe they use some expression that evaluates to true or false, like:
<cfset defaultReport144 = [some expression] />
If you can't find, then maybe the code was changed or removed in the place where these defaultReport... variables were set.
ColdFusion evaluate() documentation:
https://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f4e.html
You need to look for a variable outside of your query. This variable has a name of default#ID# . It may be called.
variables.default#ID#
form.default#ID#
url.default#ID#
request.default#ID#
attributes.default#ID#
etc.
Basically ColdFusion is going to go through every scope until it finds something. (No this is not a good approach)
If you have to clean this up, I would recommend not using such an ambiguous approach. In short, there is no real way to know what it is evaluating.

ColdFusion Sorting/Assignment

I have a two lists: One that is dynamic, based off of a recordcount of students and the other is the students..i.e., 001,002,003, etc. and 123456 (student data). I need some help being able to randomly assign students one of those numbers. For example, if I have 5 students (123456,234561, etc.), I need to be able to randomly assign 001,002, etc. to those students. So far, hitting a wall. The following is what I have so far:
<cfquery name="testjd" datasource="student">
SELECT SoonerID FROM dbo.CurrentStudentData
WHERE status = 'Student' OR status = 'JD'
</cfquery>
<cfset testList = valueList(testjd.soonerid)>
<cfset totalRecordsJd = #testjd.recordcount#>
<cfloop from="001" to="#totalRecordsJd#" index="i">
<cfset examNo = i>
<cfif len(i) is 1>
<cfset examNo = "00" & i>
<cfelseif len(i) is 2>
<cfset examNo = "0" & i>
</cfif>
<cfif not listFind(usedJDExams, examNo)>
#examNo#<!---is NOT being used!---><br/>
</cfif>
</cfloop>
CF9 makes it a little less fun than later versions. I believe this should work (except for my query mockup).
https://trycf.com/gist/3667b4a650efe702981cb934cd325b08/acf?theme=monokai
First, I create the fake query.
<!---
Simple faked up query data. This is just demo data. I think this
queryNew() syntax was first available in CF10.
--->
<cfscript>
testjd = queryNew("SoonerID", "varchar", [
["123456"],
["564798"],
["147258"],
["369741"]
]);
</cfscript>
Now that I've got a list of students who need tests, I create an array of numbers for those tests.
<!--- Create array of Available Exam Numbers --->
<cfset examNos = ArrayNew(1)>
<cfloop from=1 to=100 index="i">
<cfset examNos[i] = right('00' & i,3)>
</cfloop>
We now combine the two sets of data to get the Exam Numbers assigned to the Student.
<!--- Loop through the query and build random assignments --->
<cfloop query="#testjd#">
<!---Get random exam no.--->
<cfset examNo = examNos[randrange(1,arrayLen(examNos))]>
<!---Build struct of exam assignments--->
<cfset testAssignments[SoonerID] = examNo>
<!---Delete that num from exam array. No reuse.--->
<cfset blah = arrayDelete(examNos,examNo)>
</cfloop>
And this gives us
<cfoutput>
<cfloop collection="#testAssignments#" item="i">
For User #i#, the test is #testAssignments[i]#.<br>
</cfloop>
</cfoutput>
The unused tests are: <cfoutput>#ArrayToList(examNos)#</cfoutput>.
--------------------------------------------------------------------
For User 369741, the test is 054.
For User 147258, the test is 080.
For User 564798, the test is 066.
For User 123456, the test is 005.
The unused tests are:
001,002,003,004,006,007,008,009,010
,011,012,013,014,015,016,017,018,019,020
,021,022,023,024,025,026,027,028,029,030
,031,032,033,034,035,036,037,038,039,040
,041,042,043,044,045,046,047,048,049,050
,051,052,053,055,056,057,058,059,060
,061,062,063,064,065,067,068,069,070
,071,072,073,074,075,076,077,078,079
,081,082,083,084,085,086,087,088,089,090
,091,092,093,094,095,096,097,098,099,100.
A couple of code review notes for the OP code:
1) It's easier to work with arrays or structures than it is to work with a list.
2) cfloop from="001" to="#totalRecordsJd#": from "001" is a string that you are comparing to an integer. ColdFusion will convert "001" to a number in the background, so that it can actually start the loop. Watch out for expected data types, and make sure you use arguments as they were intended to be used.
3) cfif len(i) is 1...: First, it's less processing to build this string in one pass and them trim it - right('00' & i,3). Second (and this is a personal nitpick), is and eq do essentially the same thing, but I've always found it good practice to apply is to string-ish things and eq to number-ish things.
=====================================================================
For CF10+, I would use something like
https://trycf.com/gist/82694ff715fecd328c129b255c809183/acf2016?theme=monokai
<cfscript>
// Create array of random string assignments for ExamNo
examNos = [] ;
for(i=1; i lte 100;i++) {
arrayAppend(examNos,right('00'& i,3)) ;
}
///// Now do the work. ////
//Create a struct to hold final results
testAssignments = {} ;
// Loop through the query and build random assignments
for(row in testjd) {
// Get random exam no.
examNo = examNos[randrange(1,arrayLen(examNos))] ;
// Build struct of exam assignments
structInsert(testAssignments, row.SoonerID, examNo) ;
// Delete that num from exam array. No reuse.
arrayDelete(examNos,examNo) ;
}
</cfscript>
If it is a small query, why not just sort the records (psuedo) randomly using NEWID()? Since the records will already be randomized, you cna use query.currentRow to build the "examNo".
<cfquery name="testjd" datasource="student">
SELECT SoonerID
FROM CurrentStudentData
WHERE status IN ('Student', 'JD')
ORDER BY NewID()
</cfquery>
<cfoutput query="yourQuery">
#yourQuery.SoonerID# #NumberFormat(yourQuery.currentRow, "000000")#<br>
</cfoutput>
This is a formatted comment. After you run this query:
<cfquery name="testjd" datasource="student">
SELECT SoonerID FROM dbo.CurrentStudentData
WHERE status = 'Student' OR status = 'JD'
</cfquery>
Do this:
<cfset QueryAddColumn(testJd, "newcolumn", arrayNew(1))>
Then loop through the queries and assign values to the new column with QuerySetCell.

Is there any limitation with number queries/statements we can write inside cftransaction?

Today while fixing bugs in some existing code I found a strange error.
Branch target offset too large for short
After searching I found that it is something to do with Java byte code conversion. Here are the links I found:
Branch target offset too large for short
Branch Target Offset Error
Why does a long cfc file work in CF8, but not CF9? Getting "Branch target offset too large for short" error
In my case cftransaction contains around 870 statements and it's working fine. But I need to add 2 more queries to this transaction. Now I am getting this error when I am adding even one line of code inside cftransaction. Currently I can not move any of the existing cfquery out of the cftransaction.
Here is the overall structure of the code:
<cftransaction action="begin">
<cfif URL.action eq 'add'>
Around 200 lines of queries/statements
<cfelseif URL.action eq 'edit'>
Around 200 lines of queries/statements
</cfif>
<cfif URL.action eq 'add' or URL.action 'edit'>
Around 450 lines of queries/statements
</cfif>
</cftransaction>
Is there any workaround to fix this problem?
Branch offset has to do with the size of the module/function. It can also be caused due to a large conditional code block of cfif/cfelse or cfswitch.
Technically, I am not sure if there is any cap on the no. of queries you can put inside the cftransaciton block. It has nothing to do with the code migration from CF8 to CF9 but the length of your code inside conditional blocks.
I would want to split the function and try to put the each of the big sized conditional blocks as a separate function inside the cfc:
<cffunction name="myFunc1">
<cftransaction action="begin">
<cfif URL.action eq 'add'>
<!--- function call with your xxx lines of queries/statements --->
<cfinvoke component="MyCfc" method="firstQueryBlock" result="result1">
<cfelseif URL.action eq 'edit'>
<!--- second function call with your yyy lines of queries/statements --->
<cfinvoke component="MyCfc" method="secondQueryBlock" result="result2">
</cfif>
<cfif URL.action eq 'add' or URL.action 'edit'>
<!--- third function call with your zzz lines of queries/statements --->
<cfinvoke component="MyCfc" method="thirdQueryBlock" result="result3">
</cfif>
</cftransaction>
</cffunction>

can I limit records retrieved in ColdFusion cffile action = read?

I have a file which I want to retrieve with a cffile action = read command. However, I would like to give the user the option of only retrieving a small number of lines. The file could be quite large, and might take a very long time to load. Meanwhile the user may only need to know whether he wants to delete it, and a page or two may be quite enough. Does ColdFusion offer any way to limit the output of this command? Or can anyone suggest another approach to this problem?
Sounds like it's a text file? If so, use the <cfloop file="" and line=""> like so and read line-by-line in a loop and stop after some number of lines.
<cfset lineCount = 0>
<cfloop file="c:\temp\simplefile.txt" index="line">
<cfoutput>#line#</cfoutput><br>
<cfset lineCount++>
<cfif lineCount EQ 10>
<cfbreak>
</cfif>
</cfloop>
OR:
To read a specified number of characters from a text file during each
iteration of the loop, use the tag as follows:
<cfloop file="c:\temp\simplefile.txt" index="chars" characters="12">
<cfoutput>#chars#</cfoutput><br>
</cfloop>
Quote from: http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-71a7.html

Limiting number of pages on a paging list

I am working on revamping a sites' paging system, and I have run into something simple I can't seem to solve. I am trying to show pages (1 2 3 4 5) at a time, and when the user gets to page 5, the list changes to something like (4 5 6 7 8). How could I do this using a cfloop? Here is a sample of my code:
<cfloop from="1" to="#totalPages#" index="i">
<cfoutput><a class="paging" href="?start=#(i*25)-24#">#i#</a></cfoutput>
</cfloop>
At the moment it shows pages 1 - 54 all at once. Any tips?
Heres my code
<cfset curPage = Int(start / 25) + 1>
<cfloop from="1" to="#totalPages#" index="i">
<cfif i is curPage>
<div class="page current">#i#</div>
<cfelse>
<cfif totalPages lte 5 or i is 1 or i is totalPages or (i gt curPage - 3 and i lt curPage + 3) or ((curPage is 1 or curPage is 2) and i lt 6) >
<div class="page">#i#</div>
<cfelse>
<cfif i is 2 or i is totalPages - 1>
<div class="more">...</div>
</cfif>
</cfif>
</cfif>
</cfloop>
What this code does is it shows the first 5 pages, then an ellipsis, then the last page. As you page through it, it will always show the link to the first and last page, plus 2 page before and after the current page.
Screenshots: Page 1 and page 10
You should be able to easily modify this to work exactly how you want it. (I happen to not like when all of the links change at once the way you described)
There is a great open source pagination library that will solve your problem. I can't say enough good things about it because I wrote it. Shameless, I know. Anyways:
http://www.dopefly.com/projects/pagination/
Check out the docs, they are very complete and helpful. In your code, printing the page numbers are as simple as calling #pagination.getRenderedHTML()#. It is pretty customizable so that you can change the numbers that are printed and you can style the output however you like.
How about:
<cfloop from="#url.startpage#" to="#url.startpage+4#" index="i">
<cfif i LE totalpages>
<cfoutput><a class="paging" href="?start=#(i*25)-24#">#i#</a></cfoutput>
</cfif>
</cfloop>
Of course you would need to add "startpage" to your url and manipulate it appropriately. So your first link would be startpage=1 but your last would be startpage=4 (if I understand your question correctly).