Error: CLI0115E Invalid cursor state. SQLSTATE=24000 - sql-server

I'm trying to execute an SQL Server stored procedure using the execute SQL task of an SSIS package and I'm getting errors.
CLI0115E Invalid cursor state. SQLSTATE=24000
Cannot fetch a row from OLE DB provider "xxx.xxx" for linked
server "xxxxx".". Possible failure reasons: Problems with the query,
"ResultSet" property not set correctly, parameters not set correctly,
or connection not established correctly.
The stored procedure inserts data to a temp table and it contains a query with a join to db2 server. I'm using OPENQUERY to connect to the db2 database.
Example:
select column1, column2, column3 from OPENQUERY(#databasename,'select col1, col2, col3 from db2table1 where col3=xx') as qry1
join sqltable1 on qr1.col1 = sqltable1=col1
The SSIS package is supposed to run in loops and each time the stored procedure is supposed to return nearly 500 records. The error happens intermittently and doesn't occur when the stored procedure is run manually using SQL Server Management studio.
Any help would be much appreciated.

Related

Execute Stored Procedure with multiple result sets

I am using SSIS 2016. I need to execute a stored procedure that returns 4 result sets. I only need to keep the first result set and write this to a table. I can not modify the stored procedure. I do not care about any of the data returned in the other result sets. The stored procedure is in a SQL Server 2016 database. Results will also reside in SQL Server 2016.
I currently have this process running in SSIS 2008 using the "SQL Command" data access mode in an OLE DB Source like below. I have this in a For Each Loop Container to pass a series of param values to the stored procedure as I execute it multiple times for different param values on a daily basis.
SET FMTONLY OFF;
EXEC myProc
#Param1 = ?,
#Param2 =?,
#Param3 = ?;
By default SSIS 2008 is only returning the first result set, which has worked for me as I only care about the first result set.
I am using the Native OLEDB SQL Server client. From what I have read, it has changed the way it handles multiple result sets. I have used the WITH RESULT SETS to define the first result set but if I execute SSIS will fail indicating other result sets need to be defined.
In short, what is the best approach to duplicate what works in SSIS 2008 in SSIS 2016?
Solution Overview
I made 2 Experiments on that issue, the first experiments showed that in case of stored procedures with no parameters, nothing changed in SQL Server 2016 and SSIS 2016, the first Result Set is returned and others are ignored.
The second experiment showed that when using parameters, this will throw an exception, so you have to define metadata using WITH RESULT SETS option, then remove this option.
Detailed Solution
Experiment 1
The following experiment are made using SQL Server 2016 and Visual Studio 2015 with SSDT 2016
First i created this stored procedure
CREATE PROCEDURE sp_Test
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 10 PersonType,NameStyle,Title
FROM [AdventureWorks2016CTP3].[Person].[Person]
SELECT TOP 10 PersonType,Firstname,Lastname
FROM [AdventureWorks2016CTP3].[Person].[Person_json]
END
GO
Then i added a Data flow task to SSIS package
Added an OLEDB Source, Recordset destination
In OLEDB source i select the Data access mode to SQL command
an use the following commnad
EXEC sp_Test
When clicking on Columns Tab it shows the first ResultSet structure
And we i executed the package it runs succesfully
Experiment 2
I changed the stored procedures to the following:
ALTER PROCEDURE [dbo].[sp_Test]
#param1 varchar(10),
#param2 varchar(10),
#param3 varchar(10)
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 10 PersonType,NameStyle,Title ,#param2 as 'Param'
FROM [AdventureWorks2016CTP3].[Person].[Person]
SELECT TOP 10 PersonType,Firstname,Lastname,#param3 as 'Param'
FROM [AdventureWorks2016CTP3].[Person].[Person_json]
END
And i used the following SQL Command in the OLEDB Source:
EXEC sp_Test ?,?,?
WITH RESULT SETS (
(
PersonType NVarchar(10),
NameStyle NVarchar(10),
Title NVarchar(10),
Param Varchar(10)
)
)
And i mapped the parameters correctly.
When running the package it throws the following exception.
[OLE DB Source 2] Error: SSIS Error Code DTS_E_OLEDBERROR. An OLE DB error has occurred. Error code: 0x80040E14.
An OLE DB record is available. Source: "Microsoft SQL Server Native Client 11.0" Hresult: 0x80040E14 Description: "EXECUTE statement failed because its WITH RESULT SETS clause specified 1 result set(s), and the statement tried to send more result sets than this.".
After that i tried to remove the With RESULT SETS option, so the command is :
EXEC sp_Test ?,?,?
I tried to execute the package again, so it is executed with no errors.
Conclusion
Try to use the WITH RESULT SETs option to define the OLEDB Source metadata, after that the metadata is defined, just remove this option and run the package, so it will just take the first Result Set succesfully.
I know it's not exactly what you are asking for, but maybe you could create another stored proc that will return only the first result set for you? (Without touching the first stored proc.) Or insert the data into a table for you and then you just read the data?

What happens with OPENQUERY when the linked server is down/unavailable?

In a stored procedure on an SQL Server 2008 database, I've added an OPENQUERY in the FROM clause of a SELECT statement, and that in turn contains an OPENQUERY, something like this:
SELECT MyField
FROM OPENQUERY (LinkedServer,
'select MyField
from OPENQUERY (OtherServer,
''select t.SomeField as [MyField]
from table t'');
Now, I wonder what happens if either one of these servers is down for some reason. Does it just return an empty result set or does it throw an error? Also, if OtherServer is down, do I need to handle the error in the outer OPENQUERY?
It is important that everything is handled within the sproc, i.e. no error should be propagated to the caller of the sproc.
The MSDN documentation on OPENQUERY does not detail any behaviour in case the linked servers are unavailable.
I found this answer on DBA.SE that mentions the sp_testlinkedserver sproc. Is calling this the way to go? How would I use it to test OtherServer?
We've tested it by changing credentials for OtherServer so that the inner OPENQUERY fails. An exception occurs:
Cannot initialize the data source object of OLE DB provider "MSDASQL" for linked server "OtherServer".
OLE DB provider "MSDASQL" for linked server "OtherServer" returned message "[MySQL][ODBC 5.3(a) Driver]Access denied for user '[user]' (using password: YES)".
And it is propagated to the stored procedure. Thus, surrounding the query in a TRY...CATCH block should provide correct means for error handling.

SSIS OLEDB data transfer calling parametereized stored procedure | Columns not found

I have a SQL server stored procedure which takes as parameter a part of the database name. It works perfectly when executing from SQL Server Management Studio.
However I need to call this SP from SSIS OLE DB Source component. When I specify the SQL command and parameters in the OLE DB Source component, I get the following error:
"Error at SSIS Error Code DTS_E_OLEDBERROR. An OLE DB error has
occurred. Error code: 0x80004005. An OLE DB record is available.
Source: "Microsoft SQL Server Native Client 10.0" Hresult: 0x80004005
Description: "The OLE DB provider "SQLNCLI10" for linked server does
not contain the table The table either does not exist or the current
user does not have permissions on that table.".: Unable to retrieve
column information from the data source. Make sure your target table
in the database is available".
Basically it cant find the table used by the stored procedure as the database name is parameterized. I searched around and found that OLE DB data source needs meta data for the table. How can I provide this?
This is my stored procedure:
USE [ILLP]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[OUTPUT_MI_Tyep12] #param1 varchar(5)
AS
BEGIN
SET FMTONLY OFF;
SET NOCOUNT ON;
declare #query varchar(1000)
set #query='
SELECT [M12]
,[T3Size]
,[SizeVCost]
,NULL as [DefaultTonnage]
,NULL as [IdleCost]
,NULL as [SuperLocoID]
,[IfAllowFleetSizeVio]
FROM [ServN\PROD2].[Scenario_' + #param1 +'_PRD].[dbo].[Para_LTYPE]'
exec(#query)
END
I am guessing you are trying to loop through different databases using the SP with a parameter in SSIS. However you could do this with a Select Command From variable source:
Create a new Variable - SELECT_OUTPUT_MI_Tyep12 for instance (String Type);
Within the variable properties check EvaluateAsExpression = True;
Under the Expression use the following:
SELECT [M12]
,[T3Size]
,[SizeVCost]
,NULL as [DefaultTonnage]
,NULL as [IdleCost]
,NULL as [SuperLocoID]
,[IfAllowFleetSizeVio]
FROM [ServN\\PROD2].[Scenario_" + #[User::DBNameParameter] + "_PRD].[dbo].[Para_LTYPE]
Change the #[User::DBNameParameter] for your specific one;
Use the SQL Command from variable in the connection manager, selecting the SELECT_OUTPUT_MI_Tyep12 variable.
This should allow you to gather all the Meta data back from the table and carry on with the rest of the data flow.

Select From SQL Server Stored Procedure Resutls

I am migrating several hundred stored procedures from one server to another, so I wanted to write a stored procedure to execute an SP on each server and compare the output for differences.
In order to do this, I would normally use this syntax to get the results into tables:
select * into #tmp1 from OpenQuery(LocalServer,'exec usp_MyStoredProcedure')
select * into #tmp2 from OpenQuery(RemoteServer,'exec usp_MyStoredProcedure')
I then would union them and do a count, to get how many rows differ in the results:
select * into #tmp3
from ((select * from #tmp1) union (select * from #tmp2))
select count(*) from #tmp1
select count(*) from #tmp3
However, in this case, my stored procedure contains an OpenQuery, so when I try to put the exec into an OpenQuery, the query fails with the error:
The operation could not be performed because OLE DB provider "SQLNCLI"
for linked server "RemoteServer" was unable to begin a distributed transaction.
Are there any good workarounds to this? Or does anybody have any clever ideas for things I could do to make this process go more quickly? Because right now, it seems that I would have to run the SP on each server, script the results into tmp tables, then do the compare. That seems like a poor solution!
Thank you for taking the time to read this, and any help would be appreciated greatly!
I think your method would work - you just need to start the MSDTC. This behavior occurs if the Distributed Transaction Coordinator (DTS) service is disabled or if network DTC access is disabled. By default, network DTC access is disabled in Windows. When running and configured properly, the OLE DB provider would be able start the distributed transaction.
Check out this for instructions- it applies to any Windows Server 2003 or 2008.
Similar to your question.
Insert results of a stored procedure into a temporary table

SSIS + Temp Table

I am having a stored proc which return 2 records and which contains a select statement from a temp table, So when i used this stored proc inside a OLEDB Source in SSIS and just trying to insert the set of records into a destination SQL table using OLEDB destination.
Its throwing a ERROR at source side saying :
[OLE DB Source [1661]] Error: A rowset based on the SQL command was not returned by the OLE DB provider.
Moreover tried with set nocount on and with SET FMTONLY OFF
But of no avail...........
Need help in this.........
I had a similar problem before and it was due to SSIS not being able to determine the output for dynamic SQL. I solved it by including a "fake" Select statement at the top of the query that matched the expected output. i.e.
CREATE PROCEDURE MyStoredProc
AS
SELECT 1 As Field1, 2 As Field2, 3 As Field3 -- list of fields of appropriate type
WHERE 1 = 0 -- so nothing is actually returned
-- Real SQL goes here.
GO
Please use same connection and , make delay validation=true

Resources