Copy link to clipboard
Copied
Hi, I have a function that stopped working when I upgraded to 2016, I can't for the life of me see why. What happens is the second time the query runs it overwrites the first one and stops. It does not run the full first query. What am I missing?!
<cffunction name="doThis" access="public" returntype="string">
<cfargument name="parent" type="numeric" default="0">
<cfscript>
var LOCAL = {};
</cfscript>
<cfquery name="LOCAL.q">
SELECT parentID, title
FROM thetable
WHERE parentID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.parent#">
ORDER BY priority;
</cfquery>
<cfsavecontent variable="LOCAL.html">
<ul>
<cfoutput query="LOCAL.q">
<li>
<span>#LOCAL.q.title#</span>
#doThis(parent=LOCAL.q.sitePageID)#
</li>
</cfoutput>
</ul>
</cfsavecontent>
<cfreturn LOCAL.html>
</cffunction>
<cfoutput>#doThis()#</cfoutput>
It looks like this might indeed be a bug with ColdFusion 2016: Bug#4126393 - cfloop over a function local scope query ends iteration early‌
The good news is that it is purportedly fixed. The bad news is the fix hasn't been released yet. You might go vote it up. I'm adding a vote and a comment that other users are affected.
Copy link to clipboard
Copied
Hi Kevin,
Can you share a sample code to repro the behaviour?
Regards,
Anit Kumar
Copy link to clipboard
Copied
Interesting. I pasted it in there... Hopefully it stays this time....
<cffunction name="doThis" access="public" returntype="string">
<cfargument name="parent" type="numeric" default="0">
<cfscript>
var LOCAL = {};
</cfscript>
<cfquery name="LOCAL.q">
SELECT parentID, title
FROM thetable
WHERE parentID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.parent#">
ORDER BY priority;
</cfquery>
<cfsavecontent variable="LOCAL.html">
<ul>
<cfoutput query="LOCAL.q">
<li>
<span>#LOCAL.q.title#</span>
#doThis(parent=LOCAL.q.sitePageID)#
</li>
</cfoutput>
</ul>
</cfsavecontent>
<cfreturn LOCAL.html>
</cffunction>
<cfoutput>#doThis()#</cfoutput>
Copy link to clipboard
Copied
What's interesting is it seems to run until the query returns no results.
Copy link to clipboard
Copied
dbldutch21‌ Probably doesn't have anything to do with the problem at hand, but you can eliminate the <cfscript>var LOCAL = {}</cfscript> block entirely. LOCAL is a defined scope within functions since CF9, so you can just use it like you have throughout your function without explicitly declaring it. What you are doing, in fact, is creating a LOCAL.LOCAL variable.
If I understand your function's logic, you are selecting records from the "thetable" table, starting possibly with parentID=0 (or some other value initially passed to the function), and then recursively running the function to select "descendant" records. Is that correct?
Can you clarify what you meant by "until the query returns no results"? Do you mean that the final output from the initial call to doThis() is empty (no html is returned)? Or do you mean that the function runs until it has found the last descendant record and stops?
Copy link to clipboard
Copied
Hey Carl, I'm just used to putting that in there from the old days, I did try to remove it just in case something changed in 2016.
2016 Output:
<ul>
<li>
<span>Item 1</span>
</li>
</ul>
Coldfusion 2011 Output:
<ul>
<li>
<span>Item 1</span>
</li>
<li>
<span>Item 2</span>
<ul>
<li>
<span>Sub 1</span>
</li>
<li>
<span>Sub 2</span>
</li>
</ul>
</li>
<li>
<span>Item 3</span>
</li>
<li>
<span>Item 4</span>
</li>
</ul>
Copy link to clipboard
Copied
Sorry for restating the obvious in my previous response - I flashed right past the title of your post which clearly stated "recursive".
Anyway, do you have debugging output turned on so you can see all of the queries that are being executed? Is the query only run once?
You might want to add a check around the <cfsavecontent> block to verify the query returns rows before doing anything else. Here's a slightly revised version of your function that might help:
<cffunction name="doThis" access="public" returntype="string">
<cfargument name="parent" type="numeric" default="0">
<cfset var q = ''>
<cfset var html = ''>
<cfquery name="q">
SELECT parentID, title
FROM thetable
WHERE parentID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.parent#">
ORDER BY priority;
</cfquery>
<cfif q.RecordCount>
<cfsavecontent variable="html">
<ul>
<cfoutput query="q">
<li>
<span>#q.title#</span>
#doThis(parent=q.sitePageID)#
</li>
</cfoutput>
</ul>
</cfsavecontent>
</cfif>
<cfreturn html>
</cffunction>
<cfoutput>#doThis()#</cfoutput>
Does that help?
Copy link to clipboard
Copied
Carl, thanks for the help, sorry that did not work though. I've created a test that you can copy and paste into a file to save. You can run it on Coldfusion 11 and Coldfusion 2016 and get 2 different results. I'm honestly not sure what is happening, I'd love to hear that it is a simple setting in the admin!
Code to Paste into new file:
<cfscript>
db = QueryNew("ID,parentID,title,priority", "Integer,Integer,VarChar,Integer");
queryAddRow(db, [
{ID=1, parentID=0, title="Main 1", priority=1},
{ID=2, parentID=1, title="Main 2 - Sub 1", priority=1},
{ID=3, parentID=1, title="Main 2 - Sub 2", priority=2},
{ID=4, parentID=3, title="Main 2 - Sub 2 - Deep 1", priority=1},
{ID=5, parentID=3, title="Main 2 - Sub 2 - Deep 2", priority=2},
{ID=6, parentID=1, title="Main 2 - Sub 3", priority=3},
{ID=7, parentID=0, title="Main 2", priority=2},
{ID=8, parentID=0, title="Main 3", priority=3},
{ID=9, parentID=0, title="Main 4", priority=4},
{ID=10, parentID=0, title="Main 5", priority=5}
]);
</cfscript>
<cffunction name="doThis" access="public" returntype="string">
<cfargument name="parent" type="numeric" default="0">
<cfscript>
var LOCAL = {};
</cfscript>
<cfquery name="LOCAL.q" dbtype="query">
SELECT ID, parentID, title
FROM db
WHERE parentID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.parent#">
ORDER BY priority;
</cfquery>
<cfsavecontent variable="LOCAL.html">
<cfif LOCAL.q.RecordCount>
<ul>
<cfoutput query="LOCAL.q">
<li>
<span>#LOCAL.q.title#</span>
#doThis(parent=LOCAL.q.ID)#
</li>
</cfoutput>
</ul>
</cfif>
</cfsavecontent>
<cfreturn LOCAL.html>
</cffunction>
<cfoutput>#doThis()#</cfoutput>
In Coldfusion 2016:
<ul>
<li>
<span>Main 1</span>
<ul>
<li><span>Main 2 - Sub 1</span></li>
<li>
<span>Main 2 - Sub 2</span>
<ul>
<li><span>Main 2 - Sub 2 - Deep 1</span></li>
<li><span>Main 2 - Sub 2 - Deep 2</span></li>
</ul>
</li>
</ul>
</li>
</ul>
In Coldfusion 11:
<ul>
<li>
<span>Main 1</span>
<ul>
<li><span>Main 2 - Sub 1</span></li>
<li>
<span>Main 2 - Sub 2</span>
<ul>
<li><span>Main 2 - Sub 2 - Deep 1</span></li>
<li><span>Main 2 - Sub 2 - Deep 2</span></li>
</ul>
</li>
<li><span>Main 2 - Sub 3</span></li>
</ul>
</li>
<li><span>Main 2</span></li>
<li><span>Main 3</span></li>
<li><span>Main 4</span></li>
<li><span>Main 5</span></li>
</ul>
It appears to me that the LOCAL.q is actually getting overwritten each time, it isn't actually being stored LOCALLY. I've tried your suggestion with var q as well and it was the same.
Thanks!!
Copy link to clipboard
Copied
It looks like this might indeed be a bug with ColdFusion 2016: Bug#4126393 - cfloop over a function local scope query ends iteration early‌
The good news is that it is purportedly fixed. The bad news is the fix hasn't been released yet. You might go vote it up. I'm adding a vote and a comment that other users are affected.
Copy link to clipboard
Copied
Thanks Carl! Have you ever heard when the first update will be released? Trying to decide if I want to go through the pain of downgrading. Thanks!
Copy link to clipboard
Copied
Hi Kevin,
The CF2016 Update 1 will be released very soon. No need for you to downgrade.
Regards,
Anit Kumar
Copy link to clipboard
Copied
I'm kinda stuck and can't work until that release is out. I'm sure you can't tell me the exact date but I really can't lose another couple days. Is "very soon" in a couple days or do I need to downgrade to continue working?
Copy link to clipboard
Copied
It's a long shot, but have you tried using the result attribute?:
<cfquery name="tmpqry" result="LOCAL.q" dbtype="query">
I don't have CF2016, so I can't test it for you.
If that also doesn't work, a possible workaround (until you get the fix) is to dynamically create the query name. The following works in CF11, try it in CF2016:
<cfscript>
db = QueryNew("ID,parentID,title,priority", "Integer,Integer,VarChar,Integer");
queryAddRow(db, [
{ID=1, parentID=0, title="Main 1", priority=1},
{ID=2, parentID=1, title="Main 2 - Sub 1", priority=1},
{ID=3, parentID=1, title="Main 2 - Sub 2", priority=2},
{ID=4, parentID=3, title="Main 2 - Sub 2 - Deep 1", priority=1},
{ID=5, parentID=3, title="Main 2 - Sub 2 - Deep 2", priority=2},
{ID=6, parentID=1, title="Main 2 - Sub 3", priority=3},
{ID=7, parentID=0, title="Main 2", priority=2},
{ID=8, parentID=0, title="Main 3", priority=3},
{ID=9, parentID=0, title="Main 4", priority=4},
{ID=10, parentID=0, title="Main 5", priority=5}
]);
</cfscript>
<cffunction name="doThis" access="public" returntype="string">
<cfargument name="parent" type="numeric" default="0">
<cfscript>
var LOCAL = {};
var sName = 'qry' & arguments.parent;
</cfscript>
<cfquery name="#sName#" dbtype="query">
SELECT ID, parentID, title
FROM db
WHERE parentID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.parent#">
ORDER BY priority;
</cfquery>
<cfsavecontent variable="LOCAL.html">
<cfif evaluate('#sName#.RecordCount')>
<ul>
<cfoutput query="#sName#">
<li>
<span>#title#</span>
#doThis(parent=ID)#
</li>
</cfoutput>
</ul>
</cfif>
</cfsavecontent>
<cfreturn LOCAL.html>
</cffunction>
<cfoutput>#doThis()#</cfoutput>
Here's hoping.
Cheers
Eddie
Copy link to clipboard
Copied
Please use JVM argument -Dcoldfusion.udf.reuseTagInstances=false, mentioned in CF2016's release notes for this and other issues*, while waiting for CF2016's Update 1. I've added a comment on ticket 4126393.
* - not all issues fixable using that JVM argument are listed in the Release Notes
Thanks!,
-Aaron