Sunday, February 22, 2009

CF: Coldfusion and the perennial rounding bug

Through the years using any function that did implicit rounding in CF was not the safest thing to do. Many times when I thought this was resolved it came back with a vengeance to bite me in the you-know-what.
Thus, the safe route to use is to go through the database to round anything, unless you really do not have any choice.
This time it was the LSCurrencyFormat function which caused the headaches. It will round down at the .5 fraction rather than round up which is very annoying and disturbing at the same time. Here is a function specifically made for currency handling and it does not handle the basic calculations correctly.

Example code (comparing the round behavior against LSCurrency):

<cfloop from="0.001" to="0.009" step="0.001" index="fraction">

<cfset Amount = 1.10 + fraction>
number: #Amount# ls: #LSCurrencyFormat(Amount,'none')#
compare to rounded #Round(Amount *100)/100#


Unfortunately, I had flip back all the use of LSCurrencyFormat and pre-round the numbers via the database before passing them to this function. I do hope that Adobe does a little more testing on rounding for these in the future.

Thursday, February 12, 2009

CF: How to detect nested transactions within cftransaction

Sometimes it cannot be helped. You are expanding ColdFusion code and have to implement transactions. You have to, then, use components that cannot be changed, that, in turn, may have to do transactions. Now the problem, ColdFusion does not like nested transactions. Nested transactions are simply not supported.

Well, at least if I could detect whether I am in a transaction I could write around this I think. But there is no way that I have found. No clear posting on how to do this.

First approach I used was to create a function that would open and close a transaction, then detect the error thrown. If the error was thrown I was assuming that we were in a transaction and thus could not open a new one, a fuction like this:

<CFSET var blnReturn = false>
<!--- emptry transaction tag --->

<CFCATCH type="Any">
<CFSET blnReturn=true>

<CFRETURN blnReturn>

Unfortunatly, this does not work. When CF throws an error for nesting, even within the try/catch block for the purposfully nested transaction, the transaction wrapper is removed. Thus you are hosed if an error occurs later down the execution.

What to do then?

After much researching and failure, here is the approach I did find working. The trouble with this is, that there is no guarantee that it will work in future versions of CF, which I hope will introduce a simple function like InTransaction() . We are using the ColdFusion Java implementation of the Transaction Tag to find out whether we have a current transaction. This is the fully wrapped function.

<CFFUNCTION name="InTransaction" access="public" displayname="checks to see whether we are currently running a database transaction. returns true or false." output="No" RETURNTYPE="boolean">
<CFSET var objTrans ="">
<CFSET var blnActiveTransaction=false>
<CFSET var objCurrentTrans="">
<!--- Call to CF implementation of TransactionTag to expose Java functions --->
<cfobject type="Java" class="coldfusion.tagext.sql.TransactionTag" name="objTrans" action="create">
<!--- objCurrentTrans will become undefined if the Java function call getCurrent() returns Null,
otherwise this returns a pointer to current transaction instance --->

<cfset objCurrentTrans = objTrans.getCurrent()>
<cfif IsDefined("objCurrentTrans")>
<CFSET blnActiveTransaction=true>
<!--- return result --->
<CFRETURN blnActiveTransaction>

This works in ColdFusion 8 and 7.