Executing Stored Procedure From MS Access Causes Timeout - sql-server

The weirdest thing. I have a simple procedure that I developed in Microsoft Access 2010 with a SQL Server 2012 backend. I am now trying to deploy this into production which is Access 2016 and a SQL Server 2014 backend.
I've compiled, compact and repaired in the new environment... but I can not get Access to execute this simple stored procedure. Even worse it still executes several other stored procedures fine... but a couple of them it times out and refuses to execute?
Here is my VBA and stored procedure:
Private Sub GenerateUnitKey(UnitColumns As String)
Dim Msg, Style, Title, Response As Variant
Dim lngProcessID As Long
Dim Conn As ADODB.Connection
Dim Cmd As ADODB.Command
Dim CurrentConnection As String
CurrentConnection = LinkMasterConnection()
Msg = "Are you sure you want to update the UnitKey with the selected columns?"
Style = vbYesNo + vbCritical + vbDefaultButton2
Title = "Save Campaign?"
Response = MsgBox(Msg, Style, Title)
If Response = vbYes Then
Call OpenSixHatLoader("Generating Unit Key Across Campaign Records", 1, "")
Set Conn = New ADODB.Connection
Conn.Open CurrentConnection
Set Cmd = New ADODB.Command
With Cmd
.ActiveConnection = CurrentConnection
.CommandText = "usp_GenerateUnitKey"
.CommandType = adCmdStoredProc
.CommandTimeout = 30
.Parameters.Append .CreateParameter("#UnitColumns", adVarChar, adParamInput, 4000, UnitColumns)
.Execute
End With
End If
End Sub
And stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_GenerateUnitKey]
#UnitColumns AS VARCHAR(4000)
AS
SET NOCOUNT ON
DECLARE #SQL AS VARCHAR(MAX)
UPDATE tblStagingTable SET UnitKey =''
SET #SQL = 'UPDATE tblStagingTable SET UnitKey = ' + #UnitColumns + ' FROM tblStagingTable st'
EXEC(#SQL)
-- UPDATE Interests to match Staging Table
UPDATE tblInterests SET UnitKey = st.[UnitKey] FROM tblInterests i
INNER JOIN tblStagingTable st ON i.StagingTableID = st.StagingTableID
I am fairly confident there is nothing wrong with the code... as I said it worked fine in my development environment... even more I am manually able to execute the stored procedure within SQL Server. My SQL Server Native Client 11.0 connection works in executing other stored procedures... but for a couple of them it does not work. I am thinking I need to configure something within SQL Server itself or maybe within the Native Client 11.0 driver?
Unfortunately it gives no exception. I've set the CommandTimeout property to 0 and let it chug for a few hours hoping it would throw and exception to give me a clue but nothing... it just was frozen trying to execute. Any suggestions or ideas would be greatly appreciated because this one has me really stumped because it should be fine!

I would first launch SSMS, and from the SQL studio type in
Exec xxxxx ''
And ensure it runs (and use the SAME logon and connection to SSMS that you currently have for Access.
I would also consider creating a pass-though query, and saving that query in access. (set returns records = false if the sp does not return records). Then in code to run any proc, you can go:
With CurrentDb.QueryDefs("qryPass")
.SQL = "exec usp_GenerateUnitKey '" & UnitColumns & "'"
.Execute
End With
You note how simple the above code is - so if sp works from SSMS, then try the above code.

This was a difficult one that took me about 3 solid days of troubleshooting to get a solution to. Although I am not satisfied with the end solution as it should have just worked... but in the end my theory of the server being an Virtual Machine proved correct. When I deployed this exact same setup to Microsoft Access 2016 32 bit and SQL Server 2014 32 bit on a dedicated server it worked exactly as it was supposed to compared to the Azure VM and 1&1 Cloud Servers I had attempted to deploy to.
SQL Server integration with VM's is getting better from what all I have read, but apparently there is a ways to go. Maybe SQL Server needs to release a special VM version. Thank you to all those who took the time to look into this.

Related

Executing stored procedure in MS Access through ADO connection - removing application role

I have an app developed in MS Access which uses ADO connections to SQL server (Microsoft SQL Server 2017) to execute numerous stored procedures. The ADO connections are all done through an application role in order to limit permissions.
In the latest update, I created a few new stored procedures which return several recordsets, which are pasted in Excel. My issue is that when I execute these stored procedures, the application role is removed... The query runs without any issues, but when it finishes running, the application role is unset.
The following is an example of one of the stored procs being called in VBA Access:
Public Function CDTExceptionsReport() As ADODB.Recordset
On Error GoTo ErrorHandler
Set objConn = DB.MaintainConnection
On Error GoTo 0
If objCmd_ER Is Nothing Then
Set objCmd_ER = New ADODB.Command
With objCmd_ER
.CommandType = adCmdText
.CommandTimeout = 60 ' increase command
.CommandText = "EXEC tool.ExceptionsReport;"
.Prepared = True
' set connection object
.ActiveConnection = objConn
End With
End If
Set CDTExceptionsReport = objCmd_ER.Execute
On Error GoTo 0
Exit Function
ErrorHandler:
MsgBox "Error: " & Err.DESCRIPTION & vbNewLine & "Number: " & Err.Number
On Error GoTo 0 ' reset error handling
End Function
Note that objConn is my connection object, and objCmd_ER is my global command object.
Through the immediate terminal in VBA, I can check what role is being activated by using the following in debug mode:
Set RS = objConn.Execute("SELECT CURRENT_USER")
?RS.Fields(0)
If I run this before the objCmd_ER.Execute line, I can see the application role is still in use. However, when I run this immediately after that statement, the application role is removed and my windows username is returned. Has anyone experienced this before?
I've executed this stored procedure in SQL Server directly, and it works fine and does not log the application role out. Therefore my thinking is it's something to do with the ADO connection.
Please let me know what further details would be helpful to provide. The stored procedure does not contain any DDL or DML language - just 4 select queries.
Thanks
Never do this!
.ActiveConnection = objConn
That casts the connection object objConn to a connection string, then creates a new connection using that connection string, and uses that as the active connection.
Instead, always do this:
Set .ActiveConnection = objConn
That actually sets the active connection to your connection object.

ADODB open recordset fails / "Operation is not allowed when object is closed"

I have the following UDF in excel which uses ADO to connect to my MSSQL server. There it should execute the scalar udf "D100601RVDATABearingAllow".
For some reason the parameters that I try to append are not send to the sql server. At the server only:
SELECT dbo.D100601RVDATABearingAllow
arrives.
MY EXCEL UDF:
Function RVDATA(Fastener) As Long
Dim cnt As ADODB.Connection
Dim rst As ADODB.Recordset
Dim Cmd1 As ADODB.Command
Dim stSQL As String
Const stADO As String = "Provider=SQLOLEDB.1;Data ................"
'----------------------------------------------------------
Set cnt = New ADODB.Connection
With cnt
.ConnectionTimeout = 3
.CursorLocation = adUseClient
.Open stADO
.CommandTimeout = 3
End With
'----------------------------------------------------------
Set Cmd1 = New ADODB.Command
Cmd1.ActiveConnection = cnt
Cmd1.CommandText = "dbo.D100601RVDATABearingAllow"
Cmd1.CommandType = adCmdStoredProc
'----------------------------------------------------------
Set Param1 = Cmd1.CreateParameter("Fastener", adInteger, adParamInput, 5)
Param1.Value = Fastener
Cmd1.Parameters.Append Param1
Set Param1 = Nothing
'----------------------------------------------------------
Set rst = Cmd1.Execute()
RVDATA = rst.Fields(0).Value
'----------------------------------------------------------
rst.Close
cnt.Close
Set rst = Nothing
Set cnt = Nothing
'----------------------------------------------------------
End Function
When I use adCmdStoredProc the whole thing fails and in the vba debugger the properties of the recordset has a lot of "Operation is not allowed when object is closed" (may sound a bit different, the message is translated)
When I don't use adCmdStoredProc I get the message that the variable Fastener was not provided.
I think that maybe something is wrong in the way I open the recordset.
In other treads I read about using the "SET NOCOUNT ON" option, but that did not work either.
Does anyone have a idea?
Regards Lumpi
Ran into this error as well (in my case I am using a Stored Procedure to retrieve some information). I had made some changes which caused the execution to malfunction.
The error disappeared when I put SET NOCOUNT ON as the first statement of the Stored Procedure.
You do not need to SELECT the server side function, just provide its name ("[tra-CAE400-1].dbo.D100601RVDATABearingAllow") in the .CommandText property.
Also you should set the .CommandType property to "stored-procedure" (property reference on w3schools.com).
Then adodb will know that you are talking about calling a function, and not trying to send a plain sql-command.
Chances are that it will then allow you to define the parameters on the command object.
But the parameters you define on the command object should correspond exactly (in name and type) to the ones that are defined as the arguments of the function in the sql server.
An example from microsoft.com on using the command-object with a stored procedure
ADO Reference on microsoft.com
Another possible cause of this is debug statements. I just spent far too long trying to work out why this wouldn't work for me, the Proc on the database worked fine, the data it was supposed to insert was inserted, the VBA code worked fine, but there was nothing in the recordset.
Final solution was to go through the procs that had been built and remove the PRINT statements.
To test if this is the problem, run your proc on SQL Server manually, then look at the messages tab of the results, if there's anything there other than "Command(s) completed successfully." you need to eliminate those messages. "SET NOCOUNT ON" will get rid of the row count messages, but there may be others.
I'm assuming that after 5 years the OP has solved this particular problem, so this is just for anyone like me that finds this while searching for the same problem.
I also ran into this with a stored procedure. Did you SET NOCOUNT = OFF; at the bottom of your code? That is what worked for me after lots of googling. Also, if you have any other code that runs, you have to wrap it in Nocount = on/off, INCLUDING insert and update statements. You would think that an insert statement wouldn't matter but wrapping the code that way is what kept me from committing suicide today.
In our shop we often use lines like this in our stored procedures to assist with debugging:
RAISERROR('Debug message here',0,1) WITH NOWAIT;
This also breaks opening a recordset in Excel vba. I believe the complete answer for this question is, in the stored procedure:
use SET ROWCOUNT OFF
remove all PRINT statements
remove all RAISEERROR statements used for debugging (ie severity of 0)

Microsoft OLE DB Provider for SQL Server error '80040e14'

Stored procedure, and using ADO to connect, i'm having problems with the quotes however..
x = "text'"
If instr(x,"'") then x=replace(x,"'","''")
'x = "text''" at this point
Set Rs = Server.Createobject("adodb.recordset")
Rs.Open "Select_SP #name='" & x & "'"
I thought i was doing this right.. But I guess not, because i'm getting this error:
Microsoft OLE DB Provider for SQL Server error '80040e14'
SELECT ID from Table where Name='text''
Shouldn't it be
Name = 'text'''
Why isn't SQL recognizing the double quotes using ADO?
The Select_SP Uses something like this:
SET #sql = 'SELECT ID from Table where Name='''+#name+''''
Exec(#sql)
Do I have this SP written correctly?
The short answer is, don't call procedures the way you're doing it. Use a Command instead. This is from memory, since I don't have a Windows system in front of me at the moment, but it should work:
Dim cmd
Set cmd = Server.CreateObject("ADODB.Command")
Set Cmd.ActiveConnection = myConnectionVariableHere
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "Select_SP"
'Note: if the above two lines don't work, replace them with the following
'cmd.CommandType = adCmdText
'cmd.CommandText = "Select_CP #name=?"
cmd.Parameters.Append cmd.CreateParameter("name", adVarChar, adParamInput, len(x), x)
Rs.Open cmd
Now, all that said, I can't tell you why your procedure is giving that particular output since you're not showing us the code for it. But I'm fairly certain ADO isn't going to convert a pair of single quotes into a double quote - not sure why you'd expect it to.
Edit after seeing the OP's edit. Don't execute SQL that way unless you absolutely have to. You will only give yourself grief. I don't know what database you're using and that procedure syntax doesn't look familiar, but in Oracle you could write something like:
PROCEDURE sql_test(MyName IN VARCHAR2, MyCursor OUT SYS_REFCURSOR) IS
BEGIN
OPEN MyCursor FOR SELECT id FROM some_table WHERE name = MyName;
END;

Issue with parameters assignment in ADODB Command

We use an ADODB command to perform queries (call stored procedures) on our SQL Server 2000 database, using SQLOLEDB driver.
On one of our server we have issues when we assign parameter values. Here's how it goes :
Set conn = Server.CreateObject("ADODB.Connection")
conn.CommandTimeout = 0
conn.ConnectionTimeout = 15
conn.Mode = 1 ' adModeRead
conn.ConnectionString = connectionString ' SQLOLEDB
conn.CursorLocation = 3 ' adUseClient
conn.Open
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn ' previously created connection
cmd.CommandType = 4 ' adCmdStoredProc
cmd.CommandText = "dbo.StoredProcedureName"
cmd.CommandTimeout = 0
cmd.Parameters.Refresh ' Get the parameters info from the database
' Pseudo code here :
Foreach cmd.parameters
cmd.parameters(index).value = somevalue
Next
This code actually works on our production server, but for some odd reasons it does not work on our dev server and generates this error : Application uses a value of the wrong type for the current operation when we assign a value (which contain a decimal part, let's say a string like "12.75") to a datatype money parameter.
The code is exactly the same on dev and on prod. Do this could have something to do with regional settings, language of ADODB, language of thr OS or some other Windows component ? Because it is classic ASP code we already looked at Session.LCID but they are the same on both servers, so we are clueless right now.
Have any idea ?
Is it possible the dev server is set up with a different base language or other regional settings? Just for kicks try assigning the value 12,75 instead of 12.75.
From the MS KB
Parameters.refresh will fail in some situations or return
information that is not entirely correct. Parameters.refresh is
particularly vulnerable when used on ASP pages.
There is a known issue regarding parameter direction when using Parameters.refresh from Classic ASP. MS guidance is to manually generate the parameters.
http://support.microsoft.com/kb/183008
http://support.microsoft.com/kb/174223

SQL Server 2005 stored procedure fast in SSMS slow from VBA

I have a stored procedure which when run from SQL Server Management Studio consistently takes 5 seconds to run when called like this.
exec dbo.MyStoredProc '2009-04-30 00:00:00', '2009-04-30 20:00:00'
When called from an excel spreadsheet via VBA it takes 6 minutes plus (not including the time taken to copy the recordset to a sheet. The VBA is nothing fancy simply using an ADO connection to return a recordset. Unfortunately the Excel approach is a client requirement that I can't get rid of yet.
Public Function GenerateSQL(strQueryName As String) As Recordset
Dim rs As Recordset, cm As Command, dbsConn As Connection
Set dbsConn = New ADODB.Connection
dbsConn.Open Configuration.Range("ConnectionString")
Set cm = New ADODB.Command
With cm
.CommandText = strQueryName
.CommandType = adCmdStoredProc
.CommandTimeout = 300
.ActiveConnection = dbsConn
Set rs = .Execute()
End With
Set GenerateSQL = rs
End Function
Does anyone have any idea why this would happen or how I could begin to trace what is happening?
Thanks,
Steve
Everything you need to know about this topic: Slow in the Application, Fast in SSMS? Understanding Performance Mysteries
I believe I have the same problem as Steve Homer.
In addition to this SO question I also found this thread on eggheadcafe.com Very slow SP execution when using .net - very fast in Management Studio - totico
The answers say it's about parameter sniffing and how that affects which execution plan is used. The answers there specifically mentions the arithabort set option and how that affects the selection of plan.
Now I just need to find out how to change the set options from VBA...
Finally thanks to this forum entry on social.msdn.com i managed to get it right. First, set multiple connections to false:
connectionObject.Properties("Multiple Connections") = False
and then use the following function on your connection to set arithabort on ...
Private Sub OptionSet(ByRef cnn As adodb.Connection)
Dim cmd As adodb.Command
Set cmd = New adodb.Command
With cmd
Set .ActiveConnection = cnn
.CommandType = adodb.CommandTypeEnum.adCmdText
.CommandText = "set arithabort on"
Call .Execute
End With
Set cmd = Nothing
End Sub
Use SQL Server Profiler
Set up a trace on your database.
Limit the trace only to the stored procedure object in question
Limit to the username used by the VBA code
An introduction to SQL Server Profiler
In particular, check the SET options used by the connection and compare these with the defaults used when running the stored procedure in SSMS.
I have come across scenarios before where the SET options were different between calling code and within SSMS and the difference in performance was HUGE.
Thanks I'll take a look at the trace tools.
In reply to the comments on the original question
Are you using the exact same parameter values?
Yes exactly the same.
How much data is being returned (roughly) - number of rows and columns (and are any of them particularly big)?
Under 200 rows, perhaps 15 fields mostly ints with a couple of 20 character varchars.
Can you run SQL profiler and confirm if the sql is the issue or the remains of the macro in excel ?
The SQL is pretty ugly, as is the underlying database schema, and unfortunately is under NDA so I can't post it. If the query were the issue then wouldn't it be slow in management studio too though?

Resources