I'm working with ColdFusion 11 and am getting an error with cftransaction. I'm not sure what causing it.
I have two CFC's: abc.cfc and xyz.cfc. abc.cfc does not use the datasource attribute: as it is defined in the Application.cfc using this.datasource.
Here is the error:
Error! The root cause was that: java.sql.SQLException: Usernames and Passwords for all the database tags within the cftransaction tag must be the same. Datasource inventorymgt verification failed.. Entry rolled back
What I am doing is:
<cftransaction action="begin">
<cftry>
<cfscript>
f = structNew();
f.companyName = '#arguments.structform.companyname#';
f.address = '#arguments.structform.address#';
f.settingsID = arguments.structform.settingsID;
r = tblUpdate('settings',f);
sresult = 'Updated';
</cfscript>
<cfset str = "Cool! Settings has been " & sresult>
<cftransaction action="commit"/>
<cfcatch type="any">
<cftransaction action="rollback"/>
<cfset str = "Error! #cfcatch.Detail# #cfcatch.Message#. Entry rolled back">
</cfcatch>
</cftry>
</cftransaction>
And another CFC which is expecting the init function like the datasource, username,password is using the following query way to update it:
<cfquery name="q"
datasource="#variables.dbsource#"
username="#variables.dbuname#"
password="#variables.dbpword#">
I think the reason is explained in this post:
https://groups.google.com/forum/#!topic/cfwheels/AZTvxvhsapc
Within a cftransaction tag, every query has to use the same authentification. You cannot have one query use a datatasource and the other use a username and password within the same transaction.
I would agree with the author of the link. I always just define the datasource once in the cf-administrator, so I don't have to deal with username/password. Then you can initialize your cfc just by datasource.
I don't know what your function tblUpdate is actually doing, but might be that you use a different syntax than in the query you posted? Because, that's what your error code says:
Usernames and Passwords for all the database tags within the cftransaction tag must be the same.
Related
i'm working on my legacy system old code of coldfusion, is there a way i can define cfcatch in application.cfc and catch all errors of my application with
Function name
Query name
Line Number of code
Template Name
To debug fast rather then writing everywhere in code.
application developer did not catch any error anywhere in code.i did insert cfcatch in code some of the places but still lot more to do, and because of production i don't want to modify so much of code.
im inserting cfcatch in databse and sending email to development team. because system is in production.
You can use the cferror tag, or onError to direct all errors to a given page/function.
If you use cferror, the exception will be passed in the error variable. If you use OnError, it's a parameter.
To help you along, my own error emails include the following. You will notice that we have special handling to help point out places where a blank may have been passed into a sql integer field, which happens more often than I'd like to admit.
An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.query_string#<br />
Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
<!--- Smarter error catching for form fields --->
<cfif (error.message contains "Invalid data '' for CFSQLTYPE CF_SQL_INTEGER") and isdefined("form")>
<!--- This stores a list of the Id fields --->
<cfloop collection="#form#" item="thisField">
<!--- Get the last two characters of the field name --->
<cfset lastTwoChars = right(thisField, 2)>
<!--- Get the value of the field --->
<cfset thisFieldValue = evaluate('form.#thisField#')>
<!--- Check to see if this is an Id field and if it's value is blank. --->
<cfif lastTwoChars eq 'Id' and thisFieldValue eq ''>
<h3 style="font-weight: bold; color: red">#thisField# is blank and it's possibly an integer field.</h3>
</cfif>
</cfloop>
</cfif>
<cfdump var="#error#" label="Error">
<br/>
<cfdump var="#form#" label="Form">
<br/>
<cfdump var="#url#" label="URL">
<br/>
<cfdump var="#session#" label="session">
I am using CF10. I have a Select:
<cfselect name="company" id="company" query="qcompany" display="placename" value="placeid" queryposition="below">
<option value="0">--Select--
</cfselect>
I have another cfselect that is bound to the first:
<cfselect name="People" bind="cfc:schedule.GetPeopleArray({company})" ></cfselect>
I cannot get the second cfselect to display any results. To test whether or not I am receiving data from my component (which I will display at the bottom), I bound a text box:
<cfinput name="test" bind="cfc:schedule.GetPeopleArray({company})" bindonload="false"/>
This text box is displaying the results of the call to my component every time, but the cfselect never displays anything.
What could I possibly be doing wrong?
I have tried returning arrays and queries from my component. No help. I have tried adding display and value attributes to the second cfselect. No help.
Here is my component:
<cfcomponent output="false">
<cffunction name="GetPeopleArray" access="remote" returnType="array" output="false">
<cfargument name="company" type="string" >
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<cfquery name="qEmployee" datasource="texas" >
SELECT 0 as personid,'Select Person' as fullname,0 as sortorder
UNION
SELECT p.personid ,concat(firstname,' ',lastname) as fullname,3 as sortorder
FROM person p
INNER JOIN placeperson pp
ON p.personid=pp.personid
where personstatus='ACT'
and pp.placeid=#arguments.company#
order by sortorder,fullname
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#qEmployee.RecordCount#">
<cfset result[i][1]=qEmployee.personid[i]>
<cfset result[i][2]=qEmployee.fullname[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>
Ultimately, you may want use jQuery anyway, but FWIW your existing code worked fine with CF10. (The only change was removing the JOIN for simplicity) So either you are using different code, or there is something else going on we are unaware of ..
Truthfully the Ajax functionality does have some "quirks". However, you should not have any problem with a simple case like this. Aside from adding a text field, what other debugging or troubleshooting steps did you perform? What I usually recommend is:
Test the CFC independently first. Access it directly in your browser with a variety of sample values:
http://localhost/path/to/schedule.cfc?method=GetPeopleArray&company=someValue
I did this with the original code and discovered an error occurred when the company value is not numeric, like an empty string. (I suspect that might have been the problem) You can prevent that error by substituting an invalid ID like 0 instead. Note, be sure to use cfqueryparam to prevent sql injection.
AND pp.placeid = <cfqueryparam value="#val(arguments.company)#"
cfsqltype="cf_sql_integer">
Enable the CF AJAX debugger in the CF Administrator. Then append ?cfdebug to your test script so you can view the console and check for problems/errors.
http://localhost/path/to/yourTestForm.cfm?cfdebug
Again, I did this after tweaking the query. But there were no errors. Your existing cfform code worked perfectly.
Usually those two steps are enough to pinpoint any problems. If not, make sure your Application.cfc file (if you are using one) is not interfering with the Ajax request. That is a common gotcha. Test the code in a separate directory that is outside any Application files.
EDIT: Also, you may as well set bindonload="false" for the select list too. Since you do not want to call the function when the page first loads. Only when the user selects something from the list.
After trying for about an hour without success... (coldfusion8) a dummy question, but I*m stuck:
My URL (Jquery Mobile, no pushstate, that's why it looks like it is):
http://www.page.de/test/mem/search.cfm#/test/mem/search.cfm?id=9900000003869
If I output:
<cfdump output="e:\website\dump.txt" label="catch" var="#url#">
I get this:
catch - struct
ID: 9900000003869
But how do i access it... I'm trying forever, nothing works:
<cfdump output="e:\website\dump.txt" label="catch" var="#id#">
<cfdump output="e:\website\dump.txt" label="catch" var="#ID#">
<cfdump output="e:\website\dump.txt" label="catch" var="#url.id#">
<cfdump output="e:\website\dump.txt" label="catch" var="#url.ID#">
<cfdump output="e:\website\dump.txt" label="catch" var="#StructGetValue(url,"id")d#">
...
Thanks for helping!
Ok... This works:
URL = http://www.page.de/test/mem/search.cfm#/test/mem/search.cfm?id=9900000003869
<cfset objRequest = GetPageContext().GetRequest() />
<cfset strUrl = right( objRequest.GetRequestUrl().Append( "?" & objRequest.GetQueryString() ).ToString(), 13)>
Credit
If someone finds an easier, please post. I will check as answer.
You're trying to read this from a txt file?
Can you not simply use:
<cfdump label="catch" var="#url.id#" />
Does that work?
EDIT:
Could you try capturing and formatting what you need first then after, writing it to the file?
For example, try using:
<cfsavecontent variable="myFileContents">
<cfoutput>#url.id#</cfoutput>
</cfsavecontent>
<cffile action="Write" file="e:\website\dump.txt" output="#myFileContents#" />
I have not tested this code, but give it a go and see!
Might want to put a check on that URL variable too using isDefined()
Good luck.
Doing some research on fragment identifiers (which is a new term to me :( )prompted by Peter and Duncan's comments, I've found from wiki: http://en.wikipedia.org/wiki/Fragment_identifier
The fragment identifier functions differently than the rest of the
URI: namely, its processing is exclusively client-side with no
participation from the server — of course the server typically helps
to determine the MIME type, and the MIME type determines the
processing of fragments. When an agent (such as a Web browser)
requests a resource from a Web server, the agent sends the URI to
the server, but does not send the fragment. Instead, the agent waits
for the server to send the resource, and then the agent processes the
resource according to the document type and fragment value.
now, being your client IS sending the fragment and the url variable is accessible to you for some reason, using it is done by my original post to follow.
<cfoutput>
is generally how you output a variable or other evaluations to the screen.
<cfset myName = "Travis">
<cfoutput>Hello, my name is #myName#</cfoutput>
You can also access the variable by using it in a statement that doesn't output anywhere.
<cfset myFullName = myName & " Mak">
You can also use the variables in a query
<cfquery name = "qSomeQuery" datasource = "#application.dsn#">
select * from table where id = #url.id#
</cfquery>
However, that's the bad way to use it in a query, you should always use cfquery param.
<cfquery name = "qSomeQuery" datasource = "#application.dsn#">
select * from table where id = <cfqueryparam cfsqltype="cf_sql_integer" value="#url.id#">
</cfquery>
The problem you're having in testing the variable is due to incorrect syntax.
<cfif isDefined("url.id")> verses <cfif isDefined(url.id)> a more accurate test is <cfif structKeyExists(url, "id")>
For some reason my CF server truncates everything in the url after the # but yours doesn't seem to have this problem. As your cfdump states, you can see your url variables so "accessing" the url variable is as easy as using it: #url.id# or testing it <cfif isDefined("url.id")>
Let's say i've just parsed someone else's XML document which is a response to an API request. I want to know if a value nested deep inside exists. If my API request worked, it will be in the same place every time. If my API request fails, the root of the XML is very different.
If I try <cfif structKeyExists(myStruct.level1.level2.level3, 'myTarget')> on a failed api request, I get the fatal error: Element LEVEL1.LEVEL2 is undefined in MYSTRUCT.
Of course, I could try to depend on the root level of the XML telling me of success or failure, and not looking for the result if it failed, but... barring that solution, what should i do?
Do i need to check for the existence of each level of the struct? As in:
<cfif structKeyExists(myStruct, 'level1')
and structKeyExists(myStruct.level1, 'level2')
and structKeyExists(myStruct.level1.level2, 'level3')
and structKeyExists(myStruct.level1.level2.level3, 'myTarget')>
<!--- ... --->
</cfif>
This is not a real-world problem, this is just something i've faced too many times. Please don't tell me solutions that involve changing the API or solutions like those in the third paragraph.
Thanks!
edit: i should have mentioned why i can't use isDefined() - some of the keys do not have syntactically valid names, so isDefined() throws an error, eg myStruct.level1[42].level3
XMLSearch
I would use the parsed XML document (i.e. xmlDoc) and XMLSearch:
<cfset xmlDoc = xmlParse(responseData)>
<cfset nodes = XmlSearch(xmlDoc, '/level1/level2/level3/myTarget')>
<cfif arrayLen(nodes)>
<!--- do something, you have the "nodes" array to work with too --->
</cfif>
xpath for XMLSearch() assumes the structure keys are nodes. You would need to modify accordingly if, for instance, 'myTarget' is an attribute of a node.
StructFindKey
Another way of doing this would be StructFindKey.
<cfset result = structFindKey(myStruct, "myTarget")>
<cfif arrayLen(result) AND result.path EQ "level1.level2.level3">
<!--- do something --->
</cfif>
Conclusion
Haven't tested, but I believe either will be faster than using IsDefined() or a try-catch block. Has the advantage over XMLValidate() of not needing a DTD. And, even with a DTD, the node you want may be defined as optional, so it could still validate.
You could validate the XML against a DTD to make sure the document was in the right format. XmlParse() and XmlValidate() both take a DTD as a parameter.
<cfset validateResult = XmlValidate(myXmlDocument, myDTD)>
<cfif validateResult.status>
<!--- xml is valid continue processing --->
<cfelse>
<!--- xml did not validate handle the error --->
</cfif>
Personally I wouldn't go crazy checking for every level of a 'deep' structure like this. I would presume that if the top level exists the rest of the document will be as you expect, and I'd just address the document from there.
If you wanted you could perhaps try to address the value in your struct and wrap it in a try/catch. That way you can handle any errors at any 'level' in the same way.
<cftry>
<cfset myVar = myStruct.level1.level2.level3 />
<cfcatch type="any">
<!--- Handle error --->
</cfcatch>
</cftry>
Hope that helps some.
I know I'm going to get booed off the stage here, but this is where isDefined() can save you a lot of typing:
<cfif isDefined(structKeyExists(myStruct.level1.level2.level3)>
<!--- do something --->
</cfif>
I know this is a year old, but I'm going to put in an answer here. I struggled for a good long time with this one, till I found a simple solution. If I know the structure of the XML already, a simple IsDefined works to test if the node or node attribute exists. I don't think most people know you can do this, or have tried and failed because they didn't include single quotes in the IsDefined function.
So say I grab some user xml from a web service somewhere and want to display the user's ID.
<cfhttp url="https://mycompany.com/mywebservices/getusers" username="me" password="mysecret">
<cfset userXMLDoc = XMLParse(ToString(cfhttp.FileContent).trim())>
<cfif IsDefined('userXMLDoc.Data.Record.User.XmlAttributes.id')>
<cfdump var="#userXMLDoc.Data.Record.User.XmlAttributes.id#">
<cfelse>
<cfoutput>Failed: No User ID found</cfoutput>
</cfif>
I have to use a Variable(Query Resultset) in ColdFusion, which will get the results from Other Application DB, and stores in Coldfusion Application.
The main idea is that I need to call the other Application DB only at Server startup time and cache the results in local. And I need to read the variable in other pages in my Application. I won't overwrite that variable in any page.
On googling I found that 'onApplicationStart' is useful to assign the variables at Application Startup time.
Is using the onApplicationStart fine or is there any other way? We can assign a variable at startup time(one time).
If onApplicationStart is fine: how to use? Maybe any link where it is explained clearly is helpful.
Well, it depends. How often will this query data be updated? If it really is unchanging, then onApplicationStart() is a fine place to put it. However, if it will change every so often, you can just tell Coldfusion to cache the query for a certain period of time, then you don't need to mess with onApplicationStart(), but rather when you call the query it will return the cached result automatically (within your specified time period).
Regardless, I would write a custom function to retrieve the data. Then it will be trivial to call it from onApplicationStart() or elsewhere.
Startup.cfc: (Named whatever you like)
<!--- Replace the datasource name with your db name --->
<cffunction name="getStartupQuery" hint="Returns a query recordset for startup">
<cfargument name="datasource" required="no" type="string" default="OtherAppDB">
<!--- Init the query variable --->
<cfset var result = queryNew("id")>
<!-- Get the query dataset --->
<cfquery name="result" datasource="#arguments.datasource#">
YOUR QUERY HERE
</cfquery>
<cfreturn result>
</cffunction>
Application.cfc: (Just the important parts)
<cffunction name="onApplicationStart">
<!--- init the startup.cfc, then retrieve the data
and save it to the application scope. Remember the component name must match
your component above --->
<cfset var startup = createObject("component", "startup")>
<cfset application.varFromOtherDB = startup.getStartupQuery()>
<cfreturn true>
</cffunction>
Now, you should be able to access this variable from any CFM or CFC in your application using:
<cfset myNewVar = application.varFromOtherDB>
or
#application.varFromOtherDB#
IF you use the onApplicationStart() method, I highly recommend implementing a method to reinit the application. For an example, see this other discussion.