Pete's Windows, Office, VB & SQL Blog

Problems I have solved (or not) and good ideas I've found

Archive for the ‘SQL 2000’ Category

ERROR: 3704 – Operation is not allowed when the object is closed.

leave a comment »

Attempting to access a database running on MS-SQL 2000 or MS-SQL 2008 from an Excel Spreadsheet via a macro using Active X Data Objects Library 2.8.  The macro runs a stored procedure.  If the stored procedure issues only a SELECT the result is data, for UPDATE, INSERT or DELETE the result is 3704.  The stored procedure below does not always produce output.

Here’s the VBA code:

Sub Get_DBDATA(sWkSheet As String, sLocation As String, sClearArea As String, sSQL As String)

‘ FOR THIS CODE TO WORK
‘ In  VBE you need to go Tools  References and check Microsoft Active X Data  Objects 2.x library
‘ sWKsheet to be the worksheet where data is to be placed
‘ sLocation is top left hand cell of where data is to be placed
‘ sSQL is SQL Server comand string (This can be a stored procedure)

Dim Cn As ADODB.Connection
Dim Server_Name As String
Dim Database_Name As String
Dim User_ID As String
Dim Password As String
Dim RS As ADODB.Recordset
Set RS = New ADODB.Recordset
Dim TopLeftCellColNum As Integer
Dim TopLeftCellRowNum As Integer

On Error GoTo SQLError

Server_Name = Range(“SELECTED_DBSERVERS”).Value         ‘ Enter your server name here
Database_Name = Range(“SELECTED_DATABASES”).Value       ‘ Enter your  database name here
‘User_ID = Range(“SELECTED_DBUSERID”).Value              ‘ enter your user ID here
‘Password = Range(“SELECTED_DBUSERPWRD”).Value           ‘ Enter your password here

TopLeftCellColNum = Worksheets(sWkSheet).Range(sLocation).Column
TopLeftCellRowNum = Worksheets(sWkSheet).Range(sLocation).Row

‘Clear data return area
Worksheets(sWkSheet).Range(sClearArea).Clear

Set Cn = New ADODB.Connection
‘ Build connection string with passed variables/Cell values
‘ Cn.Open “Driver={SQL Server};Server=” & Server_Name & “;Database=” & Database_Name & “;Uid=” & User_ID & “;Pwd=” & Password & “;”
Cn.Open “Driver={SQL Server};Server=” & Server_Name & “;Database=” & Database_Name & “;Trusted_Connection=True;”
‘Get the data
RS.Open sSQL, Cn, adOpenStatic

‘Add the column headers
If RS.EOF = False Then

r = TopLeftCellRowNum ‘row in which recordset data is to be placed
C = TopLeftCellColNum ‘first column to be used for headings etc…
For Each RSField In RS.Fields
Worksheets(sWkSheet).Cells(r, C) = RSField.name
C = C + 1
Next

Worksheets(sWkSheet).Cells(TopLeftCellRowNum + 1, TopLeftCellColNum).CopyFromRecordset RS  ‘ add 1 to row to allow for column header

End If

‘Tidy up
RS.Close
Set RS = Nothing
Cn.Close
Set Cn = Nothing

Exit Sub

SQLError:

Dim sErr As String
‘Capture error number and description
sErr = “ERROR: ” & CStr(Err.Number) & ” – ” & Err.Description
‘Publish error at data return location
Worksheets(sWkSheet).Range(sLocation).Value = sErr
‘Tidy up resource
On Error Resume Next
Set RS = Nothing
Set Cn = Nothing

End Sub

Sub Test_Get_DBData()

Range(“K1″).Select
ActiveWorkbook.Names.Add name:=”SELECTED_DBSERVERS”, RefersToR1C1:=”=Test!R1C11″
Range(“K1”).Value = “WXP_PeteFish”
Range(“K2″).Select
ActiveWorkbook.Names.Add name:=”SELECTED_DATABASES”, RefersToR1C1:=”=Test!R2C11″
Range(“K2”).Value = “Pete”

Call Get_DBDATA(“Test”, “A1”, “A1”, “EXEC Test_GetDbData INS”)
Call Get_DBDATA(“Test”, “B1”, “B1”, “EXEC Test_GetDbData UPD”)
Call Get_DBDATA(“Test”, “C1”, “C1”, “EXEC Test_GetDbData DEL”)
Call Get_DBDATA(“Test”, “D1”, “D1”, “EXEC Test_GetDbData SEL”)

End Sub

Here’s the SQL fro the SQL 2000 server:

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[TEST_GetDBData]’) and OBJECTPROPERTY(id, N’IsProcedure’) = 1)
drop procedure [dbo].[TEST_GetDBData]
GO

CREATE PROCEDURE [DBO].[TEST_GetDBData]

@Param1 char(3)
AS
BEGIN
— SET NOCOUNT ON added to prevent extra result sets from
— interfering with SELECT statements.
SET NOCOUNT OFF

Declare @Value int
Select @Value = isnull(Max([Col1]),0) +1 from [Pete].[DBO].[t_One]

IF @Param1 = ‘INS’     INSERT INTO [Pete].[dbo].[T_One]           ([Col1])     VALUES           (@Value)
IF @Param1 = ‘UPD’ UPDATE [Pete].[DBO].[t_One] SET [Col1] =  @Value + 1 Where [Col1] = @Value
IF @Param1 = ‘DEL’ Delete [Pete].[DBO].[t_One] Where [Col1] >= @Value
IF @Param1 = ‘SEL’ Select * from [Pete].[DBO].[t_One]

END
GO

TRUNCAte table [Pete].[dbo].[T_One]

exec [Pete].[dbo].[TEST_GetDBData] ‘INS’
exec [Pete].[dbo].[TEST_GetDBData] ‘UPD’
exec [Pete].[dbo].[TEST_GetDBData] ‘DEL’
exec [Pete].[dbo].[TEST_GetDBData] ‘SEL’

There is a lot of discussion about ‘Set NoCount’ on various web sites.  Either way the result is the same- Error 3704

 

The answer is simple, if unwanted – make sure the stored procedure produces output!

Written by fisherpeter

2012 July 16 at 11:03

Internal connection fatal error.

leave a comment »

A small upgrade to fix a relatively minor problem and suddenly my SQL call result in “Internal connection fatal error.”.  Google, for once doesn’t give an immediate solution.  Too many people get too technical too quickly.  I examined the program carefully to ensure that the queries and updates are all using the correct connections.  This is a multi-threaded, multi-connection application.  There were minor errors.  I fixed them.  I couldn’t understand why I couldn’t reproduce the errors on my own workstation.  It has to be environmental.

Then I came across this. Thanks to Bob whose comment at the end sent me on the MDAC track.

Microsoft provide a nice utility to check the versions of MDAC. It reveals that I have generated and tested the program in a MDAC 2.81.1132 (from XP Sp3) environment, and am running it in a MDAC 2.81.1117 (from XP SP2) environment.  Never clever!

I set up a test environment with the correct version of MDAC – no change, the problem still occurs.  I examined my trace.  The problem always occurs after two threads have processed and their trace entries are intermingled.  If the dispose of one connection occurs while the connection to the other thread is active – Bang!

Much more careful program searching found that the connection that is failing is established on the secondary thread and passed to the primary via an ‘invoke’.  I’ve not found anything that says I shouldn’t do this, but it was the only one and always the one that failed.

Having now changed the code to ensure that connections are not used across a thread the program is functioning correctly and has been stable for over a week.

Written by fisherpeter

2010 May 1 at 09:28

A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 – An existing connection was forcibly closed by the remote host.)

leave a comment »

msdn seems to have a reasonable description of the problem here.  However my SQL Server log does not contain any entries for the time of the failure.

The last message in the latest SQL ErrorLog file is at 04:29:58.48

My application reports the connection status as open at 05:21:37.781

The failure occurs at 05:21:37.875 – less than 0.1 seconds later!

There are no messages in the eventlog in this time period.

Written by fisherpeter

2009 November 30 at 16:01

How to get an empty table from a sql query in VB 2005 (.net) without timeouts

leave a comment »

Its simple – write a select that guarantees the return of nothing.  You will need to know your data.  In my case this is for adding rows to a log table.  The rows are timestamped when they are entered, so I had:

SELECT [Time], [Message] FROM [LogTable]

where [Time] > {fn Now() }

It worked.

Then it began to time out.

Every time the SELECT was run a table scan occurred.  The log now has just over 500,000 rows.

I removed some to a history table, down to 100,000, but still no good.

The execution plan says table scan, so that is the obvious cause.  I soon discounted indexes, the table is rarely read, and I’m prepared for the table scan when it is, as the select is likely to include [Message] Like ‘%something%’

Then I tried

SELECT [Time], [Message] FROM [LogTable]

where 1 = 2

the execution plan says ‘constant scan’, and the query analyser reports 00:00:00 as the execution time.

FIXED!

Written by fisherpeter

2009 November 21 at 14:51

bcp and brackets [x_x].[dbo].[T_TableName] SQLState = 37000, NativeError = 4060

leave a comment »

Bizarrely the format [x_x].[dbo].[TableName] in the BCP command gives

SQLState = 37000, NativeError = 4060
Error = [Microsoft][ODBC SQL Server Driver][SQL Server]Cannot open database requested in login ‘[x_x]’. Login fails.

however in the format  x_x.dbo.[TableName] it works.  Which seems to contradict the MSDN advice.

Full working command line:

C:\Documents and Settings\Peter>bcp x_x.dbo.[T_TableName] out “Z:\Packages\Db\T_TableName.TXT”  -S SERVER -T -f “Z:\Packages\generate packages\T_TableName.FMT”

Full failing command line:

C:\Documents and Settings\Peter>bcp [x_x].[dbo].[T_TableName] out “Z:\Packages\Db\T_TableName.TXT”  -S SERVER -T -f “Z:\Packages\generate packages\T_TableName.FMT”

Written by fisherpeter

2009 November 20 at 11:25