I use ColdFusion to call stored procedure to either insert or update users data. These two transactions are separated in two procedures. My SQL code should return row-count 1 or 0 depends if transaction was successful or not. If transaction failed I'm wondering what is the best way to handle errors in that case? Both cfstoredproc
are wraped in try/catch block but in case when error occured in SQL procedure my Count
variable in result set will return 0 and try/catch won't register error returned from the procedure. Here is my code example:
<cftry>
<cfif trim(arguments.process) EQ "Insert">
<cfstoredproc procedure="InsertRec" datasource="#dsn#">
<cfprocparam dbvarname="@Status" value="#trim(arguments.status)#" cfsqltype="cf_sql_bit" />
<cfprocparam dbvarname="@Code" value="#trim(arguments.frmcode)#" cfsqltype="cf_sql_char" maxlength="2" null="#!len(trim(arguments.code))#" />
<cfprocparam dbvarname="@Name" value="#trim(arguments.name)#" cfsqltype="cf_sql_varchar" maxlength="50" null="#!len(trim(arguments.name))#" />
<cfprocresult name="Result"/>
</cfstoredproc>
<cfelse>
<cfstoredproc procedure="UpdateRec" datasource="#dsn#">
<cfprocparam dbvarname="@Status" value="#trim(arguments._status)#" cfsqltype="cf_sql_bit" />
<cfprocparam dbvarname="@Code" value="#trim(arguments.code)#" cfsqltype="cf_sql_char" maxlength="2" null="#!len(trim(arguments.code))#" />
<cfprocparam dbvarname="@Name" value="#trim(arguments.name)#" cfsqltype="cf_sql_varchar" maxlength="50" null="#!len(trim(arguments.name))#" />
<cfprocresult name="Result"/>
</cfstoredproc>
</cfif>
<cfset local.fnResults = {
status : "200",
message : "Record successully saved!",
recCount : Result.Count
}>
<cfcatch type="any">
<cfset local.fnResults = {
error : cfcatch, <!--- I use this just for testing purpose. --->
status : "400",
message : "Error! Please contact your administrator."
}>
</cfcatch>
</cftry>
Code above returns Count column/variable as I mentioned already from Result set. If process sucesfully executed user will be notified with the message. If something is wrong I would like to send them a message that is in my catch
block. Here is SQL code:
CREATE PROCEDURE [dbo].[InsertRec]
@Status BIT = NULL,
@Name VARCHAR(50) = NULL,
@Code CHAR(2) = NULL
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRY
BEGIN
INSERT INTO dbo.Books(
Status,Name,Code
)
VALUES(
@Status,@Name,@Code
)
SELECT @@ROWCOUNT AS Count;
END
END TRY
BEGIN CATCH
SELECT
@@ROWCOUNT AS Count,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage,
CURRENT_TIMESTAMP AS DateTime
END CATCH
I only showed Insert SQL code since Update procedure is the same. When I use I would see this message if something went wrong. This is just and example when I tried to insert primary key that already exist on purpose:
COUNT
0
DATETIME
2018-08-24 07:00:01.58
ERRORLINE
16
ERRORMESSAGE
Violation of PRIMARY KEY constraint 'PK_Books'. Cannot insert duplicate key in object 'dbo.Books'. The duplicate key value is (44).
ERRORNUMBER
2627
ERRORPROCEDURE
InsertRec
ColdFusion is not catching this error. Is there a way to catch this error when I use ColdFusion to call stored procedure in result set?
As @Ageax mentions, you're handing the error in your stored procedure, so from CF's point of view, the stored procedure executed correctly.
I tend to use a standard message packet for all calls to stored procedures when they do not return a record set. Add two local variables to your procs and update as needed:
DECLARE @SUCCESS BIT = 1;
DECLARE @MSG VARCHAR(50) = 'Some default success message.'
Update those values in your CATCH
statement:
BEGIN CATCH
SET @SUCCESS = 0;
SET @MSG = 'There was a problem ...';
SELECT
@SUCCESS as success,
@MSG as message,
@@ROWCOUNT AS Count,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage,
CURRENT_TIMESTAMP AS DateTime
END CATCH
But also return these values after the CATCH
so that the proc always returns a status.
SELECT
@SUCCESS as success,
@MSG as message
This will give you a user-friendly message, as well as the actual SQL error (when it happens) that can be logged as needed.