Error Handling in VBS third party program like SQL - sql-server

I have to develop a WinCC Visual Basic Script management application. In this application I read an XML archive, and after that I put the information in a SQL database through a SQL INSERT query.
My problem is that I don't know how to do the error handling to view the SQL errors in VBScript MsgBox for example.
Activating the error handling with On Error Resume Next and after the evaluation of these errors with If Err.Number <> 0 Then ... the errors produced in SQL Server don't appear in VBScript.

If you want to get SQL Server error, You can use stored procedure with transaction to insert data into table:
create procedure dbo.InsertTable (
#param1 nvarchar(80)
,#param2 nvarchar(80)
,#error_text nvarchar(400) output)
as
begin
begin tran
begin try
insert into YourTable (column1, column2)
values (#param1, #param2)
end try
begin catch
set #error_text = error_message()
rollback
return
end catch
commit
end
Now You will get eventually error from the output parameter #error_text
declare #error_text nvarchar(400)
exec dbo.InsertTable 'Value1','Value2', #error_text output
select #error_text

Related

SQL Server does not catch link server timeout error

I wrote a procedure that calls another procedure through link server, it has try catch block and catch block works very well in case of most of the errors, for example when I want to "insert a NULL value to a not null able column" catch block is executed successfully and log error result to my table,but when it comes to link server timeout, catch block is not working, I don't know where I missed things up that caused this issue.
You can take a look at my procedure
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION
DECLARE #BeforeCall DATETIME,#AfterCall DATETIME,#DiffSec BIGINT,#CycleId BIGINT
DECLARE #TBL TABLE(Date INT,Time INT,Branch INT,Amount BIGINT)
----------------Get Last CycleId------------------------------------------
SELECT TOP 1 #CycleId=CycleId FROM dbo.BranchesResetDate_History
ORDER BY CycleId DESC
SET #CycleId=ISNULL(#CycleId,0)+1;
------------------------------------------------------------------
-----------------Get Reset Date--------------------------------------------
SET #BeforeCall=GETDATE()
INSERT INTO #TBL
(
Date,
Time,
Amount,
Branch
)
EXEC [AB_TO_FK].[xxxx].dbo.GetResetDate
SET #AfterCall=GETDATE()
SET #DiffSec=DATEDIFF(SECOND,#BeforeCall,#AfterCall)
-------------------------------------------------------------------
--------------------Log Execute Result To History------------------
INSERT INTO dbo.BranchesResetDate_History (Date,Time,Branch,Amount,InsertionDateTime,SecondsElapsed,CycleId)
SELECT Date,Time,Branch,Amount,dbo.DateTimeMDToSHD(GETDATE()),#DiffSec,#CycleId
FROM #TBL
--------------------------------------------------------------------
---------------------Insert Result To Main Table--------------------
INSERT INTO dbo.BranchesResetDate
(
ResetDate,
ResetTime,
BranchCode,
Amount,
InsertionDateTime
)
SELECT Date,
Time,
Branch,
Amount,
dbo.DateTimeMDToSHD(GETDATE())
FROM #TBL
-------------------------------------------------------------------
-------------Delete Duplicate Records------------------------------
DELETE res FROM (
SELECT id,ROW_NUMBER() OVER(PARTITION BY BranchCode,ResetDate,ResetTime,Amount ORDER BY ResetTime)rn FROM dbo.BranchesResetDate
) res WHERE res.rn>1
-------------------------------------------------------------------
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##TRANCOUNT>0
ROLLBACK TRANSACTION;
------------------------Log Exception------------------------------
INSERT INTO dbo.Proc_Exception (ErrorNumber,ErrorSeverity,ErrorState,ErrorProcedure,ErrorLine,ErrorMessage,DateTime)
SELECT ERROR_NUMBER(),
ERROR_SEVERITY(),
ERROR_STATE(),
ERROR_PROCEDURE(),
ERROR_LINE(),
ERROR_MESSAGE(),
dbo.DateTimeMDToSHD(GETDATE())
-------------------------------------------------------------------
END CATCH
END
GO
When it reaches to line below
EXEC [AB_TO_FK].[xxxx].dbo.GetResetDate
In case of timeout error, catch block does not executed and I just get this error
OLE DB provider "SQLNCLI11" for linked server "AB_TO_FK" returned message "Query timeout expired
Timeout is always caused by the client (here the server with the linked server definition), which cancels the running query by sending a TDS Attention event. The error message you see is generated locally, and (for reasons lost to history) does not have a high-enough severity to trigger a CATCH block or flip ##error.
The recommended solution is to prevent the linked server timeout.
Either by extending it, eg setting the remote query timeout to 0 (infinite wait), by using this code:
sp_configure 'remote query timeout', 0
go
reconfigure with override
go
as per this support article, or by causing the remote call to fail with a trappable error instead of timeout. EG you can SET LOCK TIMEOUT in the procedure or in the batch sent to the remote server before running the procedure.
If the remote procedure succeeds it should return 0. If it fails it should return some non-zero value, and if it's canceled due to a timeout it will return null. So you can check like this:
declare #r int
execute #r = [AB_TO_FK].[xxxx].dbo.GetResetDate
if (#r is null or #r <> 0)
begin
throw 51000, 'Linked Server Procedure failed. Possible timeout.', 1;
end
And you can capture both the stored procedure return code and a resultset. And if it's supposed to output a resultset, you can also determine if it failed by checking the table after the execute. EG
declare #t table (rc int)
declare #r int = -1
insert into #t(id)
execute #r = Loopback.tempdb.dbo.bar
if (#r is null or #r <> 0 or 0 = (select count(*) from #t) )
begin
throw 51000, 'Linked Server Procedure failed. Possible timeout.', 1;
end

Sql script with Transaction/Rollback with "Go" statement

I create desktop application. with user have select .sql file and run it with Transaction/Rollback.
in that case i read all context from sql file. and put between following code to replace sql file script with *****$Replace$***** text.
How can i handle transaction/Rollback if sql file contain "GO" batch. its throwing error.
any solution to Handel thhis type of scenario to any sql file convert to Transaction/Rollback .
Note: without changes in sql file script.
sql file script:
INSERT INTO [dbo].[User] ([Name] ,[ContectNo]) VALUES ('m3','33')
GO BEGIN TRANSACTION
INSERT INTO [dbo].[User] ([Name] ,[ContectNo]) VALUES ('m3',null)
GO BEGIN TRANSACTION
INSERT INTO [dbo].[User] ([Name] ,[ContectNo]) VALUES ('m3','99')
GO
-----------------------------------------------------
Transaction block: replace sql file query from *****$Replace$*****
-----------------------------------------------------
SET XACT_ABORT ON;
GO
BEGIN TRY
BEGIN TRANSACTION
*****$Replace$*****
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##ERROR > 0
BEGIN
ROLLBACK TRANSACTION
DECLARE #ErrorMessage NVARCHAR(max) = ERROR_MESSAGE()
DECLARE #ErrorSeverity INT = ERROR_SEVERITY()
DECLARE #ErrorState INT = ERROR_STATE()
DECLARE #ErrorLine INT = ERROR_LINE()
RAISERROR (#ErrorMessage,
#ErrorSeverity,
#ErrorState
);
END
END CATCH
SET XACT_ABORT OFF
You are getting an error, because GO is not a command that should be sent to the SQL Server engine. It is something recognized by tools like SSMS, sqlcmd and osql. It signals the end of the batch of T-SQL statements and serves as a signal that the commands so far (the current batch) should be send to the SQL Server engine.
You should not try to execute GO statements as T-SQL. You should either try to parse the file for GO lines, split it into separate batches and execute them one by one, or to make sure you are passing valid T-SQL contents in these files.
You can see more information about GO statement in SQL Server Utilities Statements - GO article.

How to modify SQL Server Error Message

I have started a SQL Server locally on my computer. Now I am trying to find a way to modify error messages I get in SSMS.
Well you can do a TRY-CATCH. Something like the following:
SET NOCOUNT ON
CREATE TABLE #tmp(TestCol varchar(20))
INSERT INTO #tmp VALUES('test')
BEGIN TRY
INSERT INTO #tmp VALUES('testtesttesttesttesttest')
END TRY
BEGIN CATCH
DECLARE #nErrorNum INT;
SELECT #nErrorNum = ERROR_NUMBER()
IF #nErrorNum = 8152
BEGIN
RAISERROR('String is too long',10,1);
END
ELSE
THROW
END CATCH

SSISDB - Deploy project using T-SQL

I am trying to deploy SSIS project into SSISDB using T-SQL. Say in case of any error while deploying, error messaged got logged into catalog.operation_messages view.
Now if I execute same deploy statement in Explicit SQL transaction and if any error occurs at time of deployment I am not able to find error logged into catalog.operation_message.
Ex.
BEGIN
BEGIN TRY
BEGIN TRAN TRAN1
Declare #folder_id bigint
EXEC SSISDB.catalog.create_folder #folder_name='test1', #folder_id=#folder_id OUTPUT
Select #folder_id
EXEC SSISDB.catalog.set_folder_description #folder_name='test1', #folder_description='test1'
--Deploy
DECLARE #ProjectBinary as varbinary(max)
DECLARE #operation_id as bigint
Set #ProjectBinary = (SELECT * FROM OPENROWSET(BULK 'C:\Test\MyProject.ispac', SINGLE_BLOB) as BinaryData)
Exec SSISDB.catalog.deploy_project #folder_name = 'test1', #project_name = 'ABC', #Project_Stream = #ProjectBinary, #operation_id = #operation_id out
COMMIT TRAN TRAN1
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE()
COMMIT TRAN TRAN1
END CATCH
END
This return me error message something like
Failed to deploy project. For more information, query the operation_messages view for the operation identifier '34704'.
But when I query view and try looking for same I am not able to find any message logged by this operation_Id, is it rollbacked? if yes by which process? how I can retain it?
Help me in understanding it.

SQL Server Stored Procedure Error Handling

I have a stored procedure which is runs automatically every morning in SQL Server 2008 R2, part of this stored procedure involves executing other stored procedures. The format can be summarised thus:
BEGIN TRY
-- Various SQL Commands
EXECUTE storedprocedure1
EXECUTE storedprocedure2
-- etc
END TRY
BEGIN CATCH
--This logs the error to a table
EXECUTE errortrappingprocedure
END CATCH
storedprocedure1 and storedprocedure2 basically truncate a table and select into it from another table. Something along the lines of:
BEGIN TRY
TRUNCATE Table1
INSERT INTO Table1 (A, B, C)
SELECT A, B, C FROM MainTable
END TRY
BEGIN CATCH
EXECUTE errortrappingprocedure
END CATCH
The error trapping procedure contains this:
INSERT INTO
[Internal].dbo.Error_Trapping
(
[Error_Number],
[Error_Severity],
[Error_State],
[Error_Procedure],
[Error_Line],
[Error_Message],
[Error_DateTime]
)
(
SELECT
ERROR_NUMBER(),
ERROR_SEVERITY(),
ERROR_STATE(),
ERROR_PROCEDURE(),
ERROR_LINE(),
ERROR_MESSAGE(),
GETDATE()
)
99% of the time this works, however occasionally we will find that storedprocedure1 hasn't completed, with Table1 only being part populated. However no errors are logged in our error table. I've tested the error trapping procedure and it does work.
When I later run storedprocedure1 manually it completes fine. No data in the source table will have changed by this point so it's obviously not a problem with the data, something else has happened in that instant which has caused the procedure to fail. Is there a better way for me to log errors here, or somewhere else within the database I can look to try and find out why it is failing?
Try to use SET ARITHABORT (see link). It must ROLLBACK in your case. Also the answer of #Kartic seem reasonable.
I recommned also to read about implicit and explicit transactions - I think that this is your problem. You have several implicit transactions and when error happeneds you are in the middle of the job - so only part is rollbackŠµd and you have some data in that tables.
There are some type of Errors that TRY..CATCH block will not handle them, look here for more information https://technet.microsoft.com/en-us/library/ms179296(v=sql.105).aspx . for such Errors you should handle them in your application.
also I think you might have transaction management problem in your application too.
I am not sure if I understood you completely. Below code is too big for comment. So posting as an answer for your reference. If this is not what you want, I'll delete it.
Can we add transaction handling part as well.
DECLARE #err_msg NVARCHAR(MAX)
BEGIN TRY
BEGIN TRAN
-- Your code goes here
COMMIT TRAN
END TRY
BEGIN CATCH
SET #err_msg = ERROR_MESSAGE()
SET #err_msg = REPLACE(#err_msg, '''', '''''')
ROLLBACK TRAN
-- Do something with #err_msg
END CATCH

Resources