I'm trying to fix a little utility which seems to be losing connection to the database after some idle time. I already set the timeout to 0 but that didn't seem to work.
Instead of simply crashing and displaying a couple of error messages I would like to try to re-establish the connection and execute the query until successful (I realize this is probably a bad use of resources) but even then that's what I'm trying to accomplish here. Or if possible display a Message Box saying that connection was lost which will then be closed once connection is established.
Any suggestions would be greatly appreciated.
Public connMain As ADODB.Connection
Public rsMain As ADODB.Recordset
......
Function Picture_Exists() As Boolean
On Error Resume Next
sqlstr = "select * .... "
Set rsMain = connMain.Execute(sqlstr)
Your connection is probably being dropped at the database end due to non-use. It isn't good practice to maintain a connection when it isn't being used; connections are expensive in terms of resources so any such practice wouldn't scale well. Dbadmins aren't likely to leave unused connections open for very long.
Your potential solution says to try to connect and if you can't ignore the error. We don't say "never" in this business very often, but you should never use "On Error Resume Next" without also evaluating Err.Number to see whether it equals 0 (if it does, there's no error). This is called "inline error handling."
In any case, I wouldn't use this method. I would evaluate the Connection object's State Property, and if it's closed (cn.State = adoStateClosed) then I would reopen it.
You can try the following:
On Error Resume ''''instead of On Error Resume Next
Dim rsMain As New ADODB.Recordset
sqlstr = "select * .... "
If rsMain.State = adStateOpen Then rsMain.Close
rsMain.Open sqlstr, sProvider, adOpenKeyset, adLockOptimistic
Related
We have old VB6 code in our production system that everyone is afraid to touch. But, occasionally, a bug is large enough that someone needs to fix it. We are in the process of rewriting the system, but in the meantime, we still have customers using the existing VB6 code.
My biggest issue right now is my lack of understanding about ObjectContext. I've been reading documentation about it, and the more I read, the less I understand. I see code where sometimes, we have a block that looks like this:
Set CtxObject = GetObjectContext
If Not CtxObject Is Nothing Then
Set objSomeObject = CtxObject.CreateInstance("SomePackage.SomeObject")
Else
Set objSomeObject = CreateObject("SomePackage.SomeObject")
End If
but, ADODB.Connection objects are never created like this. Should connection objects be created like this? If the objContext is aborted, will any updates through that connection be rolled back? Or not since they were not created within the same object context?
Example of how we do create connection objects:
Dim oConn As New ADODB.Connection
Dim oRS As New ADODB.RecordSet
On Error GoTo ErrorHandler
Dim CtxObject As ObjectContext
Set CtxObject = GetObjectContext
oConn.Open *ConnectionString*
oRS.Open *SQL*, oConn, adOpenKeyset, adLockBatchOptimistic
...
Here, the connection object is created before the object context is grabbed, so I don't see how the connection is tied to that. If the RecordSet is updated, and then the ObjectContext is aborted, will the RecordSet updates be rolled back?
I made a software couple years ago using VB6 that works as a TCP server, receives multiple connections from clients.
The basic Idea of the software is to listen on a specific port, accept connections from different clients and pass each connection to a separate winsock which analyzes the data, looks in DB, replies with the proper message, and then closes the connection.
Here's some code:
Initializing the sockets when the application starts:
For i = 1 To MaxCon
Load sckAccept(i)
Next i
sckListen.Listen
Accepting connections:
Private Sub sckListen_ConnectionRequest(ByVal requestID As Long)
Dim aFreeSocket As Integer
aFreeSocket = GetFreeSocket
If aFreeSocket = 0 Then
sckAccept(0).Accept requestID
sckAccept(0).SendData "Server is full!"
sckAccept(0).Close
Else
sckAccept(aFreeSocket).Accept requestID
End Sub
Receiving data, analyzing it, and reply:
Private Sub sckAccept_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim sData As String
sckAccept(Index).GetData sData
'Do lots of analyizing and search in DB
'
'
sckAccept(Index).SendData "Message"
'
'
DoEvents
sckAccept(Index).Close
End Sub
Everything was working fine, but now the number of connections has increased (couple dozens per second), so the software started getting Out of stack space exception (because of DoEvents).
I know that in many cases DoEvents is evil, but if I remove it, the application UI won't respond (because of the over load on the thread) and some data might not be delivered.
So, my question is: does anyone have an idea of how to get around this problem with/without using DoEvents?
Note: I know that VB6 doesn't really support multi-threading and might be a PITA for such situations. I'm actually planning to upgrade the software and re-create it using .Net, but that will take some time. That's why I need to fix this problem in VB6 since the software is written in VB6 for now.
Well, I managed to figure out the problem, and have solved it.
The short answer
Do NOT use DoEvents.. Some data won't be delivered? Well, close the connection ONLY in the SendComplete event.
The long answer
First thing first:
Why I used DoEvents in the first place? because some of the sent messages were not being delivered. A lot of articles/questions on the internet suggest using DoEvents after Socket.SendData in order to guarantee the data arrival to the receiver.
I digged deeper into this trying to figure out why the messages aren't delivered. I found out that this problem only occurs when closing the connection after sending the message:
Socket.SendData "Message"
'
'
Socket.Close
So, I simply moved the line that closes the connection to the SendComplete event, removed the DoEvents sentence -since I don't need it anymore-, and the problem is gone :)
Private Sub sckAccept_SendComplete(Index As Integer)
sckAccept_Close (Index)
End Sub
I hope this could help someone who has the same problem.
I have an old VBScript project I need to debug and due to it's complexity I cannot see where are some functions being called from. Is there any VBScript alternative to PHP's debug_backtrace function or similar to see the stack trace?
So at this point, after a lot of searching, I am going to answer my own question as follows: VBScript is relatively old language and does not seem to have any built-in function/method or other means which would reliably return stack trace of function call (similar to PHP's debug_backtrace() function.
I managed to track the execution path with a simple, custom Function logBreakPointToFile() which I wrote and I placed throughout 100s of .asp files (everywhere where the method in question was referenced directly and indirectly - nested). This gave me a very messy idea what was actually happening. However is cost me a lot of prep. time and clean-up time which I was trying to avoid in the first place.
If anyone finds a better solution, please share.
Thx
VBScript does not throw any exception with stacktrace information in case of error.
#Runtime, in case of error, VBScript throws an Err object.
Ex: Below script will throw 'Division by zero' error & script will not get executed further.
Msgbox 5/0
Msgbox "Hello" 'This will not execute
On Error:
VBScript uses 'On Error Resume Next' statement which starts the error handler. It means, in case of error just skip current line and goto the next line. 'On Error GoTo 0' disables the current error handler. (like you are closing an 'if' block). Please check MSDN for more details.
Consider this example.
On Error Resume Next
Msgbox 5/0
Msgbox "Hello" 'This will say "Hello"
Msgbox Err.Number '11
Msgbox err.Description 'division by zero
On Error GoTo 0 'stops the error handler. any run time error after this will stop the program
Err.Number will be 0 in case no error is found.
So, You can have function like
Function Divide(ByVal A, ByVal B)
On Error Resume Next
Dim Result
Result = A/B
If Err.Number = 0 Then
Divide = Result
Else
Divide = "Infinite"
End If
On Error GoTo 0
End function
Remember this - as it simply goes to the next line in case of error,
On Error Resume Next
If 5/0 Then
Msgbox "???" 'This will get executed. It does not go to Else
Else
Msgbox "Hello" 'It will not show this
End If
On Error GoTo 0
You need to configure IIS to send errors to the browser. Its under Classic ASP settings on IIS 7 - 8. You have the option to send errors to browser on local requests, or all requests. For testing on a dev box usually its set for local. It will tell you what line number you are erroring out on.
As for getting more detail on what functions are slowing your application down. With classic asp you need to write your own timing code to measure such metrics.
I have a very simple code using ADO.NET which throws ORA-08177 exception. I am not sure what's wrong with this. I am trying this on a windows vista machine which has oracle 32 bit client installed. My compile option for visual studio is set to x86 platform.
Dim connection As OracleConnection = Nothing
Dim transaction As OracleTransaction = Nothing
Try
connection = New OracleConnection("Data Source=ora10;User Id=userid;Password=passwd;")
connection.Open()
transaction = connection.BeginTransaction(IsolationLevel.Serializable)
Dim inputStream As New System.IO.FileStream("Dummy.xls", IO.FileMode.Open)
Dim fileLength As Integer = CType(inputStream.Length, Integer)
Dim input(fileLength) As Byte
Try
inputStream.Read(input, 0, fileLength)
Finally
If inputStream IsNot Nothing Then inputStream.Close()
End Try
Dim deleteSql As String = "DELETE FROM TABLE1 WHERE Version = 'v1' "
Dim cmd As New OracleCommand(deleteSql, connection, transaction)
cmd.ExecuteNonQuery()
Dim insertQuery As String = "INSERT INTO TABLE1 (VERSION, DATA) VALUES (:VERSION, :DATA) "
Dim insertCmd As OracleCommand = New OracleCommand(insertQuery, connection, transaction)
insertCmd.Parameters.Clear()
insertCmd.CommandType = Data.CommandType.Text
insertCmd.Parameters.AddWithValue(":VERSION", "v1")
insertCmd.Parameters.AddWithValue(":DATA", input)
insertCmd.ExecuteNonQuery()
transaction.Commit()
Catch
If transaction IsNot Nothing Then transaction.Rollback()
Throw
Finally
If transaction IsNot Nothing Then transaction.Dispose()
If connection IsNot Nothing AndAlso connection.State <> ConnectionState.Closed Then connection.Close()
End Try
Important thing to note: (I am not sure if they are connected) but I do not face this problem if I uninstall latest windows updates from my machine.
Has anyone faced this or have any clue about what is going on here?
Edit:-
I have some progress where I have found out that this problem occurs only when we have blob column type in question. for simple columns it works fine.
Other details (not sure if that makes a difference)
I am working on 64 bit windows vista business machine.
I have installed 32 bit oracle client for windows vista (since 64 bit oracle client does not work on vista).
I am compiling my project for a x86 (32 bit environment) in visual studio.
And this is a console application and I know that nobody else is hitting the database at this time. so there cannot be multiple transactions.
And I do not see this problem if I uninstall latest windows update. (KB963027, KB967190, KB959426, KB960225, KB960803, KB952004, KB956572, KB958687, KB958690, KB958481, KB958483, KB943729)
You are using a serializable transaction which waits for some other transaction locking the same table to ROLLBACK.
If this other transaction does not rollback but commits instead, you will get this error.
The scenario seems to be as following:
Alice opens her browser session which calls DELETE FROM TABLE1 WHERE Version = 'v1'
Bob opens his session which calls DELETE FROM TABLE1 WHERE Version = 'v1' after Alice did it but before she commited.
Bob's transaction waits since Alice locked the rows with Version = 'v1'
Alice commits her transaction
Bob's transaction fails with Cannot serialize access
To work around this, set TRANSACTION ISOLATION LEVEL to READ COMMITTED:
transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted)
In this case, Bob's query will be reissued after Alice commits her changes, as if Bob's transaction were started after Alice's one was committed.
Update
Could you please post a trace of your connection?
To do this, issue this command right after connecting:
(New OracleCommand("ALTER SESSION SET SQL_TRACE=TRUE", connection, transaction)).ExecuteNonQuery();
, then look in $ORACLE_HOME\admin\udump for a fresh *.trc file
We have a bunch of VB6 apps at our company. We are trying to debug a random SQL timeout error and did a trace with SQL Server Profiler on the Audit Login event. We noticed that the connections were coming in as nonpooled. We use the SQLOLEDB provider with SQL Server 2000 & 2005. I searched the internet and everything I come across says that connections are pooled by default in the SQLOLEDB provider, but we are not seeing this. Below is the code we use to connect to the database. We really need to have these connections pooled because we think this may be the problem with our random timeout error. Could any one shine some light on why connection pooling isn't working and any way to make it work? Thanks.
Dim cnn As New ADODB.Connection
cnn.ConnectionString = "Provider=SQLOLEDB;Data Source=xxx;Catalog=xxx;User ID=xxx Password=xxx;"
Call cnn.Open
Dim cmd As New ADODB.Command
Set cmd.ActiveConnection = cnn
cmd.CommandText = "SELECT * FROM [Table]"
Dim rs As New ADODB.RecordSet
Call rs.Open(cmd, , adOpenStatic, adLockOptimistic)
While Not rs.eof
'Do stuff
Call rs.MoveNext
Wend
'Close and Dispose connection here
Disposing the connection on every call could prevent pooling
...at least one instance of a Connection
object instantiated for each unique
user—at all times. Otherwise, the pool
will be destroyed when the last
Connection object for that string is
closed.
http://msdn.microsoft.com/en-us/library/ms810829.aspx
I messed around and opened a connection at app startup and kept it open through the entire time the app was running. Connection pooling did start after the second opened and closed connection.
You mentioned that you were trying to track down a random timeout problem. I've had the same, generally when I was doing a SELECT that returned a lot of rows. Two things:
Cnn.CursorLocation=ADODB.adUseServer
(The other option is adUseClient) - I believe adUseServer gave me faster queries, which reduced the likelihood of timeouts. You do this before you open the connection, I believe.
Cnn.CommandTimeout=0
Also before the open(), tells it that you want an infinite timeout. I think the default timeout is something like 30s, which was way too short for some queries. The CommandTimeout will be used for Recordset queries. If you use a Command object, it has it's own CommandTimeout member, which doesn't appear to inherit from the Connection (ie, I set it before I Execute a command).
Sorry if the syntax isn't quite right, I'm cutting from some C++ code.