Could not update; currently locked. (VB6 and MS Access ) - ms-access

I'm getting the error "Could not update; currently locked." when two or more users insert a record in two different MS Access database files nearly simultaneously. What appears to be happening is that running a second copy of the code causes both databases to eventually become locked at the same time and each program is waiting for the other to release the locks on the table it was inserting into. So the first instance of the program goes into the error trap to wait for Logs.accdb to become unlocked so it can insert into the Logs table and the second instance of the program goes into the error trap to wait for Data.accdb to become unlocked so it can insert into the Transactions table. It is very common for us to have multiple computers running multiple exes. Each exe has two connections, one for each database. This configuration absolutely cannot be changed.
The production code uses substantially more complicated (and better organized) code, but I've reduced it down to the bare minimum to verify that code complexity wasn't the issue. I've created a test program that can recreate the error and have been unable to figure out any way to stop the error from happening other than switching the CursorLocation from adUseServer to adUseClient. This solution is unacceptable though because of the drastic increase in the time it takes to execute queries.
Things I've tried that didn't stop the error:
Closing the connection after every insert. (In addition to not fixing the issue, this also caused drastic increases in the execution time.)
Closing all connections when the error is detected and trying to Resume.
Every permutation of CursorTypes.
Replacing the ADODB RecordSet Update method for SQL Execute (INSERT INTO ...).
Converting the Access 2003 database to Access 2013 and switching Jet 4.0 to Jet Ace 12.
Creating a Front End for the database. (The databases typically reside on a network share with no Front End.)
Moving the databases to C:. (I've read that long paths to the database can generate errors.)
Changing the Client Settings within Access to do Row-based locking and changing All Locks to No Locks to Edited Rows.
Edit: Add a delay in the error trap before Resume.
I'm looking for any help at all at resolving this issue without making drastic changes (like switching to SQL Server, which I've also tried and also resolves the issue but is also not an option). This is in production code for a very long-running company, so major changes are extremely difficult to implement (and also why there's so many 'requirements').
This is the code for the test program. The two WriteRecord functions are practically identical. Compiling this code into an exe and running two copies of the exe on the same machine always recreates the error.
Option Explicit
Public oLConnection As ADODB.Connection
Public oTConnection As ADODB.Connection
Sub Main()
Dim RecordID As Long
On Error GoTo ErrorOccurred
For RecordID = 1 To 100000
DoEvents
Transaction_WriteRecord "Joe", 40000
Log_WriteRecord "Inserted Transaction", "Joe"
Next 'RecordID
ErrorOccurred:
oTConnection.Close
Set oTConnection = Nothing
oLConnection.Close
Set oLConnection = Nothing
End Sub
Public Function Transaction_WriteRecord(TransAccount As String, TransDate As Long) As Boolean
Dim rsTransaction As ADODB.Recordset
Dim sQuery As String
Dim TryCount As Integer
Static RecordID As Long
On Error GoTo ErrorOccurred
sQuery = _
"SELECT * " & _
"FROM Transactions " & _
"WHERE RecordID = 0"
If oTConnection Is Nothing Then
Set oTConnection = New ADODB.Connection
oTConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Data.accdb"
oTConnection.CursorLocation = adUseServer
oTConnection.Open
End If
Set rsTransaction = New ADODB.Recordset
rsTransaction.ActiveConnection = oTConnection
rsTransaction.CursorType = adOpenKeyset
rsTransaction.LockType = adLockOptimistic
rsTransaction.Open sQuery, Options:=adCmdText
rsTransaction.AddNew
rsTransaction!TransAccount = TransAccount
rsTransaction!TransDate = TransDate
rsTransaction.Update
RecordID = rsTransaction!RecordID.Value
rsTransaction.Close
Transaction_WriteRecord = True
Exit Function
ErrorOccurred:
'If the error is that the table is locked because another user
'is adding or deleting records, just try again.
If VBA.Error(Err) Like "Could not update; currently locked*" Then
DoEvents
TryCount = TryCount + 1
If TryCount >= 5 Then
MsgBox "Could not update; currently locked. " & vbCr & _
"Table: Transaction" & vbCr & _
"RecordID: " & RecordID
Err.Raise Err.Number
Else
Resume
End If
Else
Err.Raise Err.Number
End If
Transaction_WriteRecord = False
End Function
Public Function Log_WriteRecord(LogMessage As String, LogAccount As String) As Boolean
Dim rsLog As ADODB.Recordset
Dim sQuery As String
Dim TryCount As Integer
Static RecordID As Long
On Error GoTo ErrorOccurred
sQuery = _
"SELECT * " & _
"FROM Logs " & _
"WHERE RecordID = 0"
If oLConnection Is Nothing Then
Set oLConnection = New ADODB.Connection
oLConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Logs.accdb"
oLConnection.CursorLocation = adUseServer
oLConnection.Open
End If
Set rsLog = New ADODB.Recordset
rsLog.ActiveConnection = oLConnection
rsLog.CursorType = adOpenKeyset
rsLog.LockType = adLockOptimistic
rsLog.Open sQuery, Options:=adCmdText
rsLog.AddNew
rsLog!LogMessage = LogMessage
rsLog!LogAccount = LogAccount
rsLog.Update
RecordID = rsLog!RecordID.Value
rsLog.Close
Log_WriteRecord = True
Exit Function
ErrorOccurred:
'If the error is that the table is locked because another user
'is adding or deleting records, just try again.
If VBA.Error(Err) Like "Could not update; currently locked*" Then
DoEvents
TryCount = TryCount + 1
If TryCount >= 5 Then
MsgBox "Could not update; currently locked. " & vbCr & _
"Table: Logs" & vbCr & _
"RecordID: " & RecordID
Err.Raise Err.Number
Else
Resume
End If
Else
Err.Raise Err.Number
End If
Log_WriteRecord = False
End Function

Related

MS Access DAO recordset update not working

I made a MS Access DB (old XP version) which used to work seamlessy.
I had to add a routine to "move" some data from a table to another, and wrote a function to do this.
The method I always used was to use dynamic recordsets (or dynasets), but this time it doesn't work.
The flow correctly opens dynasets, find and copy data from one recordset to the other, but when .update is done nothing appears in the original table.
I use DAO 3.60.
Here's the (summarized) code:
On Error Resume Next
Dim rstDoc As Recordset
Dim rstAdd As Recordset
Dim rstDocEmessi As Recordset
Dim rstAddDocEmessi As Recordset
Dim Incassato As Integer
Set rstDoc = CurrentDb.OpenRecordset("Documenti", dbOpenSnapshot)
Set rstDocEmessi = CurrentDb.OpenRecordset("TS_DocumentiEmessi", dbOpenDynaset)
Set rstAdd = CurrentDb.OpenRecordset("Addebiti", dbOpenDynaset)
Set rstAddDocEmessi = CurrentDb.OpenRecordset("TS_Addebiti_DocumentiEmessi", dbOpenDynaset)
numDoc = Forms!TS_SceltaStampa!IdDocumento
With rstDocEmessi
rstDocEmessi.AddNew
rstDocEmessi!IdDocOriginale = rstDoc!IdDocumento
rstDocEmessi!Data = rstDoc!Data
rstDocEmessi![#Fattura] = rstDoc![#Fattura]
...
rstDocEmessi!TS_Opposizione = rstDoc!TS_Opposizione
rstDocEmessi!TS_DataPagamento = rstDoc!TS_DataPagamento
rstDocEmessi!IsIncassato = (IIf(Incassato = vbYes, True, False))
rstDocEmessi!IsImportatoInSospesi = False
rstDocEmessi.Update
rstDocEmessi.Close
' Copia Addebiti
If Not (rstAdd.EOF And rstAdd.BOF) Then
rstAdd.MoveFirst
Do Until rstAdd.EOF = True
If rstAdd!Documento = numDoc Then
rstAddDocEmessi.AddNew
rstAddDocEmessi!IdAddebito = rstAdd!IdAddebito
rstAddDocEmessi!Documento = rstAdd!Documento
...
rstAdd!TS_TipoSpesa
rstAddDocEmessi!Calcola = rstAdd!Calcola
rstAddDocEmessi!Totale = rstAdd!Totale
rstAddDocEmessi.Update
End If
rstAdd.MoveNext
Loop
End If
rstAddDocEmessi.Close
rstAdd.Close
TS_Registra = True`
I have a few suggestions.
Firstly don't use On Error Resume Next unless you are expecting a particular error in a line of code that you are going to explicitly test for and handle in the very next line of code (by testing If Err.Number = ...). You should have an error handling code block and use On Error GoTo ERROR_CODE_BLOCK. If you are going to turn off the error handler for one particular command then you should turn it back on again straight after you've handled the expected error.
Because you've turned off error handling, it could be that your insert statements are failing due to some constraint violation but you're just not seeing this. For error handling I would recommend structuring your code like this:
On Error GoTo PROC_ERR
Dim rstDoc As Recordset
'...
'insert the body of your Procedure here
'...
PROC_EXIT:
'Add any tidying up code that always needs to run. For example, release all your Object variables
Set rstDoc = Nothing
Set rstAdd = Nothing
Set rstDocEmessi = Nothing
Set rstAddDocEmessi = Nothing
Exit Sub
PROC_ERR:
MsgBox "Error " & Err.Number & " - " & Err.Description
Resume PROC_EXIT
End Sub
General code tidying suggestions.
The With rstDocEmessi construct is used to save you a bit of typing. There should be an associated End With somewhere in your code, but I don't see this. I would change this bit of code as follows:
With rstDocEmessi
.AddNew
!IdDocOriginale = rstDoc!IdDocumento
!Data = rstDoc!Data
![#Fattura] = rstDoc![#Fattura]
...
!TS_Opposizione = rstDoc!TS_Opposizione
!TS_DataPagamento = rstDoc!TS_DataPagamento
!IsIncassato = (IIf(Incassato = vbYes, True, False))
!IsImportatoInSospesi = False
.Update
.Close
End With
Finally, the inserts into rstAddDocEmessi could be cleaned up a bit. Rather than opening the whole table of records for rstAdd and then checking each record in turn to see if you need to add a rstAddDocEmessi record, why not just get the relevant records in your rstAdd recordset?
Set rstAdd = CurrentDb.OpenRecordset("Select * From Addebiti " & _
"Where Documento = " & Forms!TS_SceltaStampa!IdDocumento, dbOpenDynaset)
'No need to test for (rstAdd.BOF And rstAdd.EOF), and no need for rstAdd.MoveFirst
'Just go straight into...
Do Until rstAdd.EOF = True
rstAddDocEmessi.AddNew
rstAddDocEmessi!IdAddebito = rstAdd!IdAddebito
rstAddDocEmessi!Documento = rstAdd!Documento
...
rstAddDocEmessi!Calcola = rstAdd!Calcola
rstAddDocEmessi!Totale = rstAdd!Totale
rstAddDocEmessi.Update
rstAdd.MoveNext
Loop

get the name of a query from an access table, then run the query

I have an access db that pulls volumes from a table of exceptions. Each volume has an ID. I've created queries to pull details, for all possible volumes, and saved each one with the same name as each volume ID. Each time the volume exceptions are pulled into this db, the volume IDs can change. So, there is a query that runs that updates the volume table with the new IDs.
Unless you know a way to do this with a query, I need to write Access VBA code that will loop through the volume table, identify the name of each query and then run those queries until it reaches the end of the table. For example, the code needs to look at the first record in the volume table, say it is 1040. This is the name of the query that needs to run. The code then needs to find the query named 1040 and run it. It is a make table query.
The table name is FacilityVolume and it has one field named Volume. The value in the field is shorttext format even though it is numeric.
I've tried a couple of different things. Here is my latest try.
Dim db as Database
Dim vol as Recordset
Dim code as QueryDef
Set db = CurrentDb()
Set vol = db.OpenRecordset("FacilityVolume")
Set Volume = vol.Fields("Volume")
Vol.MoveFirst
Do Until vol.EOF = True
If QueryDef.Name = Volume Then
DoCmd.OpenQuery
Else MsgBox("The query does not exist")
vol.MoveNext
Loop
End Sub
I've searched the internet for a few days and can't find any reference to this particular code. I'm sure other users would like to know how to do this. I'm a novice and still learning VBA so any help you can provide is greatly appreciated.
Your code will loop through, even if you found your query and you do not pass the Query-Name to the OpenQuery command... This won't work...
The collection CurrentDb.QueryDefs knows all existing queries, but there is no "Exists" or "Contains" method.
So: The approach would be a loop (as you tried it) or an Error handling.
It's quite a time ago since I've coded with VBA, but I think you could try:
On Error Resume Next
DoCmd.OpenQuery "YourQueryName"
If Err Then
MsgBox("The query does not exist!")
Err.Clear
End If
On Error Goto 0
I recommend using full DAO in VBA to accomplish your goal. DoCmd.OpenQuery is really a VBA function that mimics the Macro RunQuery action. You don't get much control or true error handling capability.
Here is a complete code function that
Gives you an example of how to select all or some records from your table that lists the queries, including the ability to only select "Active" records, and even sort them in a particular execution sequence
Handles the instances where the query name in your table does not exist
Allows you to display a message about any errors that occur
Allows you to return an exit code to the calling procedure so that you can possibly act on the results of running these queries (such as choosing not to do the next step in your code if this function encounters an error of any kind (returns a non-zero value)
Here is the code. You will need to modify the SQL statement for your correct table name and field names, but this should be a good example to get you on your way.
Public Function lsProcessQuerySet() As Long
On Error GoTo Err_PROC
Dim ErrMsg As String
Dim db As DAO.Database
Dim rstEdits As DAO.Recordset
Dim qdf As DAO.QueryDef
Dim mssql As String
Dim ReturnCode As Long
Set db = CurrentDb()
'============================
'Select the list of Queries you want to process
'============================
mssql = "SELECT tblQueryList.ID, tblQueryList.QueryName, "
mssql = mssql & "tblQueryList.QueryShortDesc "
mssql = mssql & "FROM tblQueryList "
mssql = mssql & "WHERE tblQueryList.QueryActive = True "
mssql = mssql & "ORDER BY tblQueryList.SortOrder;"
Set rstEdits = db.OpenRecordset(mssql, dbOpenDynaset)
DoCmd.Hourglass True
'============================
'Execute each query, allowing processing to continue
'if the query does not exist (an error occurs)
'============================
Do While Not rstEdits.EOF
Set qdf = db.QueryDefs(rstEdits("QueryName"))
qdf.Execute dbSeeChanges
ResumeNextEdit:
rstEdits.MoveNext
Loop
rstEdits.Close
Exit_PROC:
lsProcessQuerySet = ReturnCode
Set qdf = Nothing
Set rstEdits = Nothing
db.Close
Set db = Nothing
DoCmd.Hourglass False
Exit Function
Err_PROC:
Select Case Err.Number
Case 3265 'Item Not Found in this Collection
ReturnCode = Err.Number
ErrMsg = "Query Not Found:" & vbCrLf & vbCrLf
ErrMsg = ErrMsg & rstEdits("QueryName")
DoCmd.Hourglass False
MsgBox ErrMsg, vbOKOnly + vbCritical, "Function lsProcessQuerySet"
Resume ResumeNextEdit
Case Else
ReturnCode = Err.Number
ErrMsg = "Error: " & Err.Number & vbCrLf
ErrMsg = ErrMsg & Err.Description
DoCmd.Hourglass False
MsgBox ErrMsg, vbOKOnly + vbCritical, "Function lsProcessQuerySet"
Resume Exit_PROC
End Select
End Function
The answer of #Shnugo is already good. Just to give you a complete VBA function, this should be working for you.
Public Sub MySub()
On Error GoTo err_mySub
Dim db as Database
Dim vol as Recordset
Set db = CurrentDb()
Set vol = db.OpenRecordset("FacilityVolume", dbOpenDynaset) ' I don't know if you want to run all queries of the table "FacilityVolume".
'So maybe you could also use something like "SELECT Volume FROM FacilityVolume WHERE Volume LIKE ""*10*"""
Vol.MoveFirst
Do Until vol.EOF = True
DoCmd.OpenQuery vol!Volume
vol.MoveNext
Loop
exit_MySub:
Exit Sub
err_MySub:
If Err.Number = 7874 Then
MsgBox "The Query """ & Vol!Volume & """ wasn't found."
Resume Next
Else
MsgBox Err.Description
Resume exit_MySub
End If
End Sub

MS Access to MySQL Connection

I am building an application, using MS Access as a front-end of a MySQL DB. The application consists of a lot of Forms all of which will execute many different SQL statements.
I am establishing the connection using:
Dim oConn As New ADODB.Connection
Dim Server_Name As String
Dim Database_Name As String
Dim User_ID As String
Dim Password As String
Server_Name = "localhost"
Database_Name = "test"
User_ID = "root"
Password = ""
oConn.Open "DRIVER={MySQL ODBC 5.3 ANSI Driver}" _
& ";SERVER=" & Server_Name _
& ";DATABASE=" & Database_Name _
& ";UID=" & User_ID _
& ";PWD=" & Password _
& ";OPTION=16427"
My questions are:
Is it better to Open and Close the connection each time i run an SQL Statement, or Open the connection, when the Application runs and close when the application closes?
-If the first way is better, Can I Create a global Function that returns a connection, to be used in the current form and not having to write the same code over and over for each form and/or SQL statement?
-If the second way is better, Can I Declare and Open the Connection globally, so It can be used from any form?
Keep in mind that:
-There are 50+ different forms and sub-forms in the application.
-The application should be able to run on multiple computers at once accessing 1 database.
I had this same question and nobody got around to answering it.
In general, its better to keep the connection open when you're going to use it and close it when you're done, but not before then. Which is fine if you use it on a per-form basis but if it gets shared it gets a little more complicated.
What I did initially was open the connection for each form, subforms grabbed the connection from their parent, and the form closes the connection when it gets closed.
The issue, if multiple forms use the same connection, is that if you close that connection, other forms using it will have errors and fail. So, if you want to share the connection between forms you can, but just make sure that it never closes unless the file is being closed. I am currently using this method, since I have a base 'menu' form that can't be closed without closing the file, I close the connection onClose for that form.
Another thing to keep in mind, is that the computer could be randomly disconnected from the server, so any code that requires the connection should have a quick test to re-open the connection if it got closed by accident somehow.
EDIT:
In it's own module.
Public DB_CONNECTION As ADODB.Connection
Function openConnect(ByRef myconn As ADODB.Connection) As Integer
Static retries As Integer
Dim server As String
server = "localhost"
On Error GoTo connectError
myconn.ConnectionTimeout = 10
myconn.Open "DRIVER={MySQL ODBC 5.1 Driver};SERVER=" & server & "DATABASE=data;USER=" & getSQLuser & ";PASSWORD=password;Option=3"
openConnect = 1
retries = 0
Exit Function
connectError:
'retry several times on failure
Dim errADO As ADODB.Error
For Each errADO In myconn.Errors
Debug.Print vbTab & "Error Number: " & errADO.Number
Debug.Print vbTab & "Error Description: " & errADO.Description
Debug.Print vbTab & "Jet Error Number: " & errADO.SQLState
Debug.Print vbTab & "Native Error Number: " & errADO.NativeError
Debug.Print vbTab & "Source: " & errADO.Source
Debug.Print vbTab & "Help Context: " & errADO.HelpContext
Debug.Print vbTab & "Help File: " & errADO.HelpFile
If errADO.Number = -2147467259 Then
If retries < 3 Then
If MsgBox("Connection Error, Try to reconnect or close any connection-enabled forms,check your internet connection and try again.", vbCritical + vbRetryCancel, "Connection Error") = vbRetry Then
retries = retries + 1
Call openConnect(myconn)
Exit Function
End If
Else
MsgBox "Connection error. Retried 3 times, check your internet connection and/or contact your system administrator.", vbCritical + vbOKOnly, "Critical Connection Error"
retries = 0
Exit Function
End If
End If
Next
Select Case err
Case 0
Case Else
MsgBox "Error Code " & err & ", " & Error(err), vbCritical, "Error #" & err
End Select
openConnect = -1
End Function
Function closeConnect()
If Not (DB_CONNECTION Is Nothing) Then
If DB_CONNECTION.State = adStateOpen Then
DB_CONNECTION.Close
End If
End If
End Function
Function tryConnect()
Dim err
If DB_CONNECTION Is Nothing Then
Set DB_CONNECTION = New ADODB.Connection
Call openConnect(DB_CONNECTION)
Else
If Not (DB_CONNECTION.State = adStateOpen) Then
Call openConnect(DB_CONNECTION)
End If
End If
End Function
In my case, I never call openConnect directly, but always call tryConnect onOpen of any forms that use the DB, or before calls that might happen after some time (for example, the save button). If it's already open, no harm done, but if it's not it prevents an error.
closeConnect I call OnError and OnClose of the menu form.

Using ADODB.Recordset.Index when connecting to MySQL ODBC in VB6

I am working on a system that has been in use since the 90's. Written in VB6, it was originally setup to utilize an Access Database and the JET driver.
Now, since we have clients running up against the 2GB file size limit on Access DBs, we are looking into converting everything over to mySQL.
Unfortunately, everything in the system that was written prior to about 5 years ago is using this type of logic:
Dim rst As New ADODB.Recordset
rst.ActiveConnection = cnn
rst.Open "table"
rst.Index = "index"
rst.Seek Array("field1", "field2"), adSeekFirstEQ
rst!field1 = "something new"
rst.Update
The newer code is using SQL commands like SELECT, UPDATE, etc.
So, what we're hoping to do is to phase in the new mySQL DBs for our clients - get them the DB setup but using all the old code.
The problem is that I can't use Index when using the SQL db... everything else seems to work fine except for that.
I get the error: #3251: Current provider does not support the necessary interface for Index functionality.
Is there something I'm missing? Is there another way to so a Seek when using SQL so that I can sort by my Index? Or will I have to go in and change the entire system and remove all the Seek logic - which is used THOUSANDS of times? This is particularly an issue for all of our Reports where we might have a Table with an Index where Col 1 is sorted ASC, Col 2 is sorted DESC, Col 3 is ASC again and I need to find the first 5 records where Col 1 = X. How else would you do it?
Since, as you posted, the DB doesn't support Seek or Index, you're kind of out of luck as far as that is concerned.
However, if you really must use seek /index I'd suggest importing the result of the SQL query into a local .mdb file and then using that to make the recordset work like the rest of the code expects.
This is slightly evil from a performance point of view, and honestly it may be better to replace all the seeks and index calls in the long run anyways, but at least it'll save you time coding.
For creating the local db you can do:
Function dimdbs(Temptable as String)
Dim tdfNew As TableDef
Dim prpLoop As Property
Dim strDbfullpath As String
Dim dbsn As Database
Dim idx As Index
Dim autofld As Field
'PARAMETERS: DBFULLPATH: FileName/Path of database to create
strDbfullpath = VBA.Environ$("TMP") & "\mydb.mdb"
If Dir(strDbfullpath) <> "" Then
Set dbsn = DBEngine.Workspaces(0).OpenDatabase(strDbfullpath)
Else
Set dbsn = DBEngine.CreateDatabase(strDbfullpath, dbLangGeneral)
End If
Set tdfNew = dbsn.CreateTableDef(Temptable)
With tdfNew
' Create fields and append them to the new TableDef
' object. This must be done before appending the
' TableDef object to the TableDefs collection of the
' database.
Set autofld = .CreateField("autonum", dbLong)
autofld.Attributes = dbAutoIncrField
.Fields.Append autofld
.Fields.Append .CreateField("foo", dbText, 3)
.Fields.Append .CreateField("bar", dbLong)
.Fields.Append .CreateField("foobar", dbText, 30)
.Fields("foobar").AllowZeroLength = True
Set idx = .CreateIndex("PrimaryKey")
idx.Fields.Append .CreateField("autonum")
idx.Unique = True
idx.Primary = True
.Indexes.Append idx
Debug.Print "Properties of new TableDef object " & _
"before appending to collection:"
' Enumerate Properties collection of new TableDef
' object.
For Each prpLoop In .Properties
On Error Resume Next
If prpLoop <> "" Then Debug.Print " " & _
prpLoop.Name & " = " & prpLoop
On Error GoTo 0
Next prpLoop
' Append the new TableDef object to the Northwind
' database.
If ObjectExists("Table", Temptable & "CompletedCourses", "Userdb") Then
dbsn.Execute "Delete * FROM " & Temptable & "CompletedCourses"
Else
dbsn.TableDefs.Append tdfNew
End If
Debug.Print "Properties of new TableDef object " & _
"after appending to collection:"
' Enumerate Properties collection of new TableDef
' object.
For Each prpLoop In .Properties
On Error Resume Next
If prpLoop <> "" Then Debug.Print " " & _
prpLoop.Name & " = " & prpLoop
On Error GoTo 0
Next prpLoop
End With
Set idx = Nothing
Set autofld = Nothing
End Function
to find and delete it later you can use the following:
Function DeleteAllTempTables(strTempString As String, Optional tmpdbname As String = "\mydb.mdb", Optional strpath As String = "%TMP%")
Dim dbs2 As Database
Dim t As dao.TableDef, I As Integer
Dim strDbfullpath
If strpath = "%TMP%" Then
strpath = VBA.Environ$("TMP")
End If
strDbfullpath = strpath & tmpdbname
If Dir(strDbfullpath) <> "" Then
Set dbs2 = DBEngine.Workspaces(0).OpenDatabase(strDbfullpath)
Else
Exit Function
End If
strTempString = strTempString & "*"
For I = dbs2.TableDefs.Count - 1 To 0 Step -1
Set t = dbs2.TableDefs(I)
If t.Name Like strTempString Then
dbs2.TableDefs.Delete t.Name
End If
Next I
dbs2.Close
End Function
To import from SQL to that DB you'll have to get the recordset and add each record in using a for loop (unless it's a fixed ODBC connection, i think you can import directly but I don't have example code)
Dim formrst As New ADODB.recordset
Set mysqlconn = New ADODB.Connection
Dim dbsRst As recordset
Dim dbs As Database
'opens the ADODB connection to my database
Call openConnect(mysqlconn)
'calls the above function to create the temp database
'Temptable is defined as a form-level variable so it can be unique to this form
'and other forms/reports don't delete it
Call dimdbs(Temptable)
Me.RecordSource = "SELECT * FROM [" & Temptable & "] IN '" & VBA.Environ$("TMP") & "\mydb.mdb'"
Set dbs = DBEngine.Workspaces(0).OpenDatabase(VBA.Environ$("TMP") & "\mydb.mdb")
Set dbsRst = dbs.OpenRecordset(Temptable)
Set formrst.ActiveConnection = mysqlconn
Call Selectquery(formrst, strSQL & strwhere & SQLorderby, adLockReadOnly, adOpenForwardOnly)
With formrst
Do Until .EOF
dbsRst.AddNew
dbsRst!foo = !foo
dbsRst!bar = !bar
dbsRst!foobar = !foobar
dbsRst.Update
.MoveNext
Loop
.Close
End With
dbsRst.Close
Set dbsRst = Nothing
dbs.Close
Set formrst = Nothing
You'll have to re-import the data on save or on form close at the end, but at least that will only need one SQL statement, or you can do it directly with the ODBC connection.
This is by far less than optimal but at least you can couch all this code inside one or two extra function calls and it won't disturb the original logic.
I have to give huge credit to Allen Browne, I pulled this code from all over the place but most my code probably comes from or has been inspired by his site (http://allenbrowne.com/)
Who wants to use VB6? Nevertheless...
When you do not specify Provider, you can't use Index property. As far as i know only OleDb for MS Jet supports *Seek* method and *Index* property.
Please read this:
Seek method - http://msdn.microsoft.com/en-us/library/windows/desktop/ms675109%28v=vs.85%29.aspx
Index property - http://msdn.microsoft.com/en-us/library/windows/desktop/ms675255%28v=vs.85%29.aspx
ConnectionString property - http://msdn.microsoft.com/en-us/library/windows/desktop/ms675810%28v=vs.85%29.aspx
Provider property - http://msdn.microsoft.com/en-us/library/windows/desktop/ms675096%28v=vs.85%29.aspx
For further information, please see: http://msdn.microsoft.com/en-us/library/windows/desktop/ms681510%28v=vs.85%29.aspx
[EDIT]
After your comments...
I would strongly recommend to download and install Visual Studio Express Edition and use VB.NET instead VB6. Than install ADO.NET MySQL Connector and re-write application, using the newest technology rather than torturing yourself with ADODB objects, etc.
Examples:
Connecting to MySQL databases using VB.NET
[/EDIT]

Access ADO: operation is not allowed when the object is closed error message

I am using Access 2003 with a local table which will later be transferred and linked to a SQL Server 2008 table. I am using the following code but get the error: "Run-time error 3704: Operation is not allowed when the object is closed" on the cnn.Execute line.
sub test()
On Err GoTo Err_Sub
Dim cnn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim str As String
Dim strSQL As String
'Open a connection.
Set cnn = New ADODB.Connection
cnn.ConnectionString = _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & CurrentDb.Name & ";" & _
"Persist Security Info=False"
strSQL = Me.RecordSource
str = Mid(strSQL, InStr(strSQL, "Where "))
strSQL = "Update myTable SET Active = False " & str
Set rs = cnn.Execute(strSQL)
If Not rs Is Nothing Then rs.Close
Exit_Sub:
Set rs = Nothing
Exit Sub
Err_Sub:
MsgBox Err.Description
Resume Exit_Sub
End Sub
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.
Try CurrentProject.Connection.Execute strSQL instead of declaring your cnn object.
Well that's simple. You need to add
cnn.Open
somewhere before cnn.Execute
also, don't forget to call
cnn.Close
Set cnn = nothing
before exiting from the sub
I recently ran into this issue as well. My error came up because I was naming one of the columns in the sql query 'Pit#'. I am fairly certain that it was the # that caused this error to happen for me. I hope this helps someone in the future.
Thanks -- Shell