A while ago I received an email from a client who is also a ColdFusion developer. He was trying to get an report to display correctly, but kept running into what appeared to be a bug in ColdFusion. The behavior was consistent in all the versions of ColdFusion he tested, namely versions 5, 7, and 8.
The problem was described like this: Suppose that you run a query which returns a set of data that can be grouped in a cfoutput by, for example, a field named monthYear. You want to loop over the query and, each time monthYear value changes, you want to print totals, etc. The problem was that outside of the inner cfoutput the currentRow of the query was not returning what he expected.
Take a look at this example code:
<!--- create some random data ---> <cfset query=QueryNew("monthYear,min,max")/> <cfset startDate=createDate(year(now()), month(now())-3, day(now()))/><br/> <cfset endDate=now()/> <cfloop from="#startDate#" index="date" step="5" to="#endDate#"><br/> <cfset QueryAddRow(query)/><br/> <cfset QuerySetCell(query, "monthYear", dateFormat(date, "mm/yy"))/><br/> <cfset QuerySetCell(query, "min", randRange(1, 100))/><br/> <cfset QuerySetCell(query, "max", randRange(101, 200))/><br/> </cfloop> <!--- loop over the data and output the data and summarise at the end of the month ---> <br/> <table><br/> <tr><br/> <th>Month Year</th><br/> <th>Min</th><br/> <th>Max</th><br/> </tr><br/> <cfoutput group="monthYear" query="query"><br/> <br/> <cfoutput><br/> <tr><br/> <td>#monthYear#</td><br/> <td>#min#</td><br/> <td>#max#</td><br/> </tr><br/> </cfoutput><br/> <!--- output the current row ---> <br/> <tr><br/> <td colspan="2">Current Row:</td><br/> <td>#currentRow#</td><br/> </tr><br/> </cfoutput><br/> </table>
If you run this code, which generates some fake data to group on, it results in this output:
What seems weird about this? Well, to me, not much. However, my client though it was strange that the current row was reported to be the row before we output the data in the inner cfoutput tag. So, it’s like this in pseudo code:
- Run a query
- Start output and group on monthYear.
- Start an inner output and show 4 or so rows of data and end the inner output.
- Now, output the current row.
Would you expect the current row to show 1? My client’s argument was that the current row should be 4, not 1.
My take on this is that it should show 1, not 4. Why do I say this? Because of where we are in our code. If cut out the inner cfoutput and ran it you’d end up with this:
As you can see, this is the same as what we have above, except that we only showed the current row. To me, this is consistent.
The counter argument is that the inner cfoutput is modifying the state of the query and that a modified value should stay modified. I can see this point too.
Meanwhile, the client decided to end the argument and emailed Ben Forta directly and asked him what he thought. The answer was fairly simple: This was a bug that was introduced early in CF history that was not caught before it was released into the wild and now, to maintain backwards compatibility, it needs to stay as it is.
What do you think?