Copy link to clipboard
Copied
Hello all,
I have a process which pulls information from a database, converts the data into an array, in which every element contains a structure with two keys (name and value). That information is then processed and returned to another system. The problem is, often times when looping over the array that contains the structures, the loop will go out of bounds and attempt to access array elements that do not exist. Further more, sometimes either the "name" or "value" key will be blank. I currently am unaware of any pattern to this behavior.
<!--- Get all the data for the given PID (an ID number associated to a contact) --->
<cfquery name="Login" datasource="WebServer" maxrows="1">
Select *
From SFContactSync
Where PID = <cfqueryparam cfsqltype="cf_sql_integer" value="#form.PID#">
</cfquery>
<!--- Assign All the information from the login query into variables we can return --->
<cfloop list="#Login.columnList#" index="columnName">
<cfset counter = counter + 1>
<cfset VariablesObject[counter] = structnew()>
<cfset VariablesObject[counter]["Name"] = columnName>
<cfset VariablesObject[counter]["Value"] = #Login[columnName][1]#>
</cfloop>
<!--- Create one more entry that contains the full name of the person --->
<cfset counter = counter + 1>
<cfset VariablesObject[counter] = structnew()>
<cfset VariablesObject[counter]["Name"] = "FullName">
<cfset VariablesObject[counter]["Value"] = "#Login.Firstname# #Login.Lastname#">
<!--- Set the next page to go to --->
<cfset nextPage = "/15">
<cfset ReturnObject = server.IVRUtilities.printMessage(nextPage,VariablesObject)>
<!--- Function for creating return AngelXML --->
<cffunction name="printMessage" access="remote" hint="Print a message for the Angel IVR System">
<cfargument name="address" default="none" type="string">
<!--- This is an array of structures, with keys "name" and "value" --->
<!--- EX variables[1].Name = Gender --->
<!--- EX variables[1].Value = Male --->
<cfargument name="variablesToInclude" default="" type="any" required="no">
<cfargument name="promptText" default="." type="string" required="no">
<cfoutput>
<cfsavecontent variable="ReturnMessage">
<ANGELXML>
<MESSAGE>
<PLAY>
<PROMPT type="text">
<cfoutput>#arguments.promptText#</cfoutput>
</PROMPT>
</PLAY>
<GOTO destination="#listlast(address)#" />
</MESSAGE>
<cfif IsArray(arguments.variablesToInclude)>
<VARIABLES>
<cftry>
<cfloop from="1" to="#arraylen(arguments.variablesToInclude)#" index="i">
<cfif structkeyexists(arguments.variablesToInclude,'Name') and structkeyexists(arguments.variablesToInclude,'value')>
<VAR name="#ucase(arguments.variablesToInclude['Name'])#" value="#ucase(arguments.variablesToInclude['Value'])#" />
</cfif>
</cfloop>
<cfcatch type="any">
<cfset ErrorData = structnew()>
<cfset ErrorData.Error = cfcatch>
<cfset ErrorData.Arguments = arguments>
<cfset ErrorData.form = form>
<cfset SendError = server.utilities.SendErrorReport(ErrorData)>
</cfcatch>
</cftry>
</VARIABLES>
</cfif>
</ANGELXML>
</cfsavecontent>
</cfoutput>
<cfreturn ReturnMessage>
</cffunction>
For example, I have an error sitting in my inbox now that says
The element at position 25 cannot be found.
But viewing the dump of the included elements shows only 24 elements. For some reason the loop here
<cfloop from="1" to="#arraylen(arguments.variablesToInclude)#" index="i">
<cfif structkeyexists(arguments.variablesToInclude,'Name') and structkeyexists(arguments.variablesToInclude,'value')>
<VAR name="#ucase(arguments.variablesToInclude['Name'])#" value="#ucase(arguments.variablesToInclude['Value'])#" />
</cfif>
</cfloop>
does seem to stop at the right point. The cfif statment would error, becuase it tries to evaluate an array element that does not exist. Whats up with that?
I was thinking of adding more checking to see if the array element exsists, but I am hesitant to add any more "checking" code than I really need beucase this is a somewhat high performance critical app. Any thoughts or comments are welcome.
You might be on to something there ... your function is Server scoped? you
need to var scope the variables in your cfffunction for them to be trully
local
<cfset var x = "">
<cfset var ReturnMessage = "">
etc.
Copy link to clipboard
Copied
Look's like a case of overengineering. What do you think you can accomplish with an array of structures that you can't accomplish with the initial query?
Copy link to clipboard
Copied
Mostly the fact that I wanted that function to be reuseable, there are several occasions where I need to create the AngelXML data, and I don't know ahead of time what kind of data I am going to be passing, if any. The array of structures gives me the flexibility to pass it any kind of data. Sometimes i need to populate it from a query, other times I pass it just a hard coded ID.
Copy link to clipboard
Copied
I can't see anything wrong with your code. What do you get when you dump out
the array length of that variable, at each iteration, from inside the
function's loop?
Copy link to clipboard
Copied
I'll try putting in some more debugging. When I dump out all the arguments, I clearly see there are 24 array elements, but it attempts to loop to 25. You're thinking maybe somehow the data is being affected in the loop?
Here is a sample dump
An error has occurred in a Cold Fusion page template. All the information available is included below. Please note that not all included data may be relevent, but is included for completness sake.
struct | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ARGUMENTS |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ERROR |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FORM |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FromEmail | x | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Subject | Error in template | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
x |
Message was edited by Jochem van Dieten to remove privae information.
Copy link to clipboard
Copied
Wow, it gets weirder. I just got an error report, it tried to access element 17, even though there was only one argument. Am I maybe dealing with variable scope issue here?
An error has occurred in a Cold Fusion page template. All the information available is included below. Please note that not all included data may be relevent, but is included for completness sake.
struct | |||||||||||||||||||||||||||||||||||||||||||||||||||||
ARGUMENTS |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
ERROR |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
FORM |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
Subject | Error in template | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Copy link to clipboard
Copied
You might be on to something there ... your function is Server scoped? you
need to var scope the variables in your cfffunction for them to be trully
local
<cfset var x = "">
<cfset var ReturnMessage = "">
etc.
Copy link to clipboard
Copied
The only variables I use are the ones passed into the arguments, and the loop counter defined as i. if I create i as a local variable and set it to 0 perhaps that will clear the issues up.
Copy link to clipboard
Copied
kenji776 wrote:
The only variables I use are the ones passed into the arguments, and the loop counter defined as i. if I create i as a local variable and set it to 0 perhaps that will clear the issues up.
You should always VAR all variables used in functions, unless you specifically want them to be shared across method calls.
It looks to me like you have your CFC instantiated in some shared scope, and - given you are not VARing any variables - all requests calling those methods are sharing those variables. This will yield "unexpected" results.
--
Adam
Copy link to clipboard
Copied
Wow, it gets weirder. I just got an error report
I suspect Adam is correct about the missing var scoping.
BTW: The account and pin numbers you posted ... are they for anything important?
Copy link to clipboard
Copied
Seems you guys were probably right about the var scoping being the issue. For some reason I had it in my head that variables created within loops where local to that loop or something. Doesn't make much sense in retrospect. Creating the variable beforehand, and setting it to 0 seems to has resolved the issue.
That extra info in the dump isn't anything terribly important (you can only get into some small website that doesn't have any really useful info) but I'll remove it anyway. Thanks for the heads up.
Edit: Damn, for some reason I cannot modify my above posts. Hey mods, if you see this, can you kill those post above witht he dump info in there please?
Copy link to clipboard
Copied
Creating the variable beforehand, and setting it to 0 seems to has resolved the issue.
I assume you mean you "var" scoped the variable? Be sure to do the same for all of the function-local variables (ie ones you do not want shared).
Edit: Damn, for some reason I cannot modify my above posts. Hey mods, if you see this, can you kill those post above witht he dump info in there please?
I do not think this forum has that kind of moderator.
That extra info in the dump isn't anything terribly important (you can only get into some small website that doesn't have any really useful info) but I'll remove it anyway. Thanks for the heads up.
Always scrub stuff before posting. Most forums are routinely archived by search engines and other sites. So once you post something, the original is out there (on one site or another) ... most likely permanently.
Copy link to clipboard
Copied
Yeah I set it as a var. I normally do, just I didn't really think I had to for a for that variable, figured the loop would
re-init it at 0, but that was a dumb assumption. Thats weird I can't edit posts, and there are no mods. Sure I made a mistake, but the fact
that there is no way to correct it is fairly stupid.
Copy link to clipboard
Copied
As son as somebody has replied to a message the message can not be changed anymore, except by a moderator. If you need something fixed in a post, click the "Report abuse" link and explain what needs to be done.