I need to return a resultset consisting of database errors from a SQL Server stored procedure's CATCH
clause but I'm stuck with it. Do I need to use cursors to return resultset and if so, then what is the type declaration for the OUTPUT
parameter in my .NET application? I tried Object
and Variant
but did not work.
I also tried the simple way just using a SELECT
statement to return and it works with one stored procedure but not with another as thus in my CATCH
clause:
while (@I <= @count)
begin
BEGIN TRY
-- delete all previous rows inserted in @customerRow for previous counts @I
delete from @customerRow
-- this is inserting the current row that we want to save in database
insert into @customerRow
SELECT
[id],[firstname], [lastname], [street], [city],
[phone],[mobile],[fax], [email], [companyName],
[licence],[brn], [vat], [companyStreet], [companyCity], [status]
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY id ASC) AS rownumber,
[id], [firstname], [lastname], [street], [city],
[phone], [mobile], [fax], [email], [companyName],
[licence], [brn], [vat], [companyStreet], [companyCity], [status]
FROM
@registerDetails) AS foo
WHERE
rownumber = @I
-- this stored procedure handles the saving of the current customer row just defined above
-- if there is any error from that sproc, it will jump to CATCH block
--save the error message in the temp table and continue
--with the next customer row in the while loop.
exec dbo.sp_SaveCustomer @customerRow
END TRY
BEGIN CATCH
IF @@TranCount = 0
-- Transaction started in procedure.
-- Roll back complete transaction.
ROLLBACK TRANSACTION;
if XACT_STATE()= -1 rollback transaction
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT @ErrorMessage = ERROR_MESSAGE() + ' ' + (select firstname from @registerDetails where id=@I)
SELECT @ErrorSeverity = ERROR_SEVERITY();
SELECT @ErrorState = ERROR_STATE()
INSERT INTO #registrationResults (error,id)
SELECT @ErrorMessage, @I
END CATCH
set @I = @I +1
end
COMMIT TRANSACTION registerTran
select * from #registrationResults
The above works with one stored procedure when I call it in my vb.net code as :
ta.Fill(registrationErrors, clientDetailsDT)
where registrationErrors
and clientDetailsDT
are strongly typed data tables.
This one does not :
begin catch
IF @@TranCount > 0 or XACT_STATE()= -1 ROLLBACK TRANSACTION;
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorLine INT;
SELECT @ErrorMessage = ERROR_MESSAGE();
SELECT @ErrorSeverity = ERROR_SEVERITY();
SELECT @ErrorState = ERROR_STATE();
SELECT @ErrorLine = ERROR_Line();
****ERROR -- THIS SELECT WAS MESSING ALL UP as it was this select that was being returned to the .NET and not the select of the desired #temp table after, hence returning 0 resultset as this select was EMPTY. !!
select status_indicator from InsertInvoiceTriggerData where session_GUID = guid**
delete from InsertInvoiceTriggerData where session_GUID = @guid**
INSERT INTO #registrationResults (error,id)
SELECT @ErrorMessage, NULL
select * from #registrationResults
end catch
Any suggestions how to return resultsets?
I haven't seen your database code, but in my experience the very first error caught by
catch
means that the entire transaction has to be rolled back. Apart from other things, it also implies that I never have more than 1 error to return in any given situation.As such, I use 2 scalar output parameters in my stored procedures, that is:
And I can retrieve them just like any other output variables.
UPD: Even after you have added some code, I still fail to understand what is your problem, exactly. However, I see several problems with your code, so I'll point them out and chances are, one of them will solve the problem. I am commenting only the first snippet, since the last one is too incomplete.
dbo.sp_SaveCustomer
stored proc. If not, the whole discussion is pointless, since there are nosave tran
orrollback @savepoint
statements in the code you have shown.catch
statement -IF @@TranCount = 0 ROLLBACK TRANSACTION
is all wrong. If the condition is successful, it will result in error trying to rollback nonexistent transaction. Should not be here if you rely on savepoints.if XACT_STATE()= -1 begin rollback transaction; break; end;
INSERT INTO @registrationResults (error, id) SELECT error_message() + ' ' + firstname, id from @registerDetails where id=@I;
commit
should be conditional, because you may end up at this point with no transaction to commit:if @@trancount > 0 commit tran;
commit
statement, it only leads to confusion (though isn't considered an error). Also, there should not any savepoint in this module (unless you have defined it before the loop).I suspect that's just the tip of the iceberg, since I have no idea what actually happens inside the
dbo.SaveCustomer
stored procedure.UPD2: Here is a sample of my VB.NET code which I use to receive recordsets from stored procedures:
I use .NET 4.5, which has a very nice method to automatically select the most appropriate data adapter based on the actual connection. And here is a call of this function:
Here, SearchPatients() is a wrapper on top of the SearchObjectsBase().