I've got a quandry. I've developed an Access app and I'm getting ready to distribute it. I've just split the database. (I know, some say I should've developed it split from the start... I didn't) I've also just encrypted the backend database. In the frontend, I've linked to the backend and entered the correct password when prompted. The linked tables are now appearing in my fronend database. However, when I try to access one of the linked tables, I get a pop-up message that simply says "Not a valid password".
I've tried deleting the linked tables and relinking. I've tried updating the link. Nothing seems to work. Every search I've done assumes the links were created BEFORE the encryption happened and no password was entered. This is not the case here.
Can anyone please help?
Windows 7 - Access 2010
Multiguy
From comments
OOOOOPPPPPSSSS!!!! Ok, I found the problem. Access doesn't like the
use of other characters. I had a set of parenthesis in my password.
Removed that and all is well! :-)
– MultiGuy
I'd like to add to this; a password for a back end table connection can be updated in a VBA macro. Add the following lines and replace the name for the linked table & the password.
Dim cdb As DAO.Database
Set cdb = CurrentDb
cdb.TableDefs("Projects").Connect = "MS Access;PWD=PaSsWoRd;DATABASE=C:\Users\bob.smith\Desktop\Split\Database_NEW_be.accdb"
cdb.TableDefs("Projects").RefreshLink
I found this was useful after splitting a database into a front end and back end using the built in split functionality. I needed to encrypt the back end for security purposes and didn't want to have to recreate all the data connections - isn't that the point of using the split function?
Duplicate the above lines for each linked table and let the macro run through. The linked tables should resume working after this.
This answer solved an issue for me. So I am upvoting, and also I want to provide an enhanced version that you can run on all tables:
Public Sub RevisePasswordForLink()
Dim cdb As DAO.Database
Set cdb = CurrentDb
Dim tdf As TableDef, colTdf As TableDefs, strConnect As String
Set colTdf = cdb.TableDefs
strConnect = "MS Access;PWD=paSsWoRd;" _
"DATABASE=C:\Users\bob.smith\Desktop\Split\Database_NEW_be.accdb"
For Each tdf In cdb.TableDefs
''I believe best to skip the hidden tables ("MSys*")
If Not tdf.Name Like "MSys*" Then
''If your DB has any local tables, you can save yourself some errors
''by filtering them out (similar to hidden tables).
cdb.TableDefs(tdf.Name).Connect = strConnect
cdb.TableDefs(tdf.Name).RefreshLink
Debug.Print " " & tdf.Name
End If
Next tdf
Set cdb = Nothing
Debug.Print "FINISHED "
End Sub
I came across this thread when I was having a similar problem with Access 2013. I'd encrypted the backend successfully. Each time I opened the backend, I could successfully open the backend using the password I'd used to encrypt the backend.
So, I opened the frontend, deleted the previously linked tables, and re-linked to the newly encrypted backend. As expected, during the link process, it asked me for the password to the backend. I entered the correct password (I know it was correct, because I pasted it instead of typing it) and everything seemed to work correctly. The tables all showed up in the objects list in the frontend. However, if I tried to open a linked table, I would get a message box stating "Not a valid password."
After visiting some other threads, I tried using a password on the backend that did not have any special characters and did not have any spaces. Then relinking those in the frontend. Presto! That solved the problem.
So, try the following if you are getting the "Not a valid password" in the frontend even if you can open the backend just fine if you manually load it yourself: Eliminate any spaces or punctuation from the backend password and then delete and re-link the linked tables in the frontend.
Related
i'm using dsnless links in access 2019 to a mysql instance on aws. I have an Access login form, which passes uid & password to a connection string in VBA, and connects and executes simple "select 1".
All along, i assumed the credentials from my access input form were being used to check against my MYSQL users, BUT...it looks to maybe use a cached user/password instead? When i enter a wrong password into my access login form, it still successfully connects and executes the qdf / sql query.
(i can 'watch' the connection string in vba does have the wrong password)
how can i force odbc to authenticate using the actual id & password actually being sent in connection string??
This simple login form has worked, but just realizing now it will pass a wrong password from my access form, but yet still connect and execute the sql...
Function TestLogin(uid As String, pwd As String) As Boolean
On Error GoTo testerror
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Dim RST As DAO.Recordset
Dim strcon As String
Dim errX As DAO.Error
Dim strsql As String
Dim strRW
strcon = "ODBC; Driver=MySQL ODBC 8.0 Unicode Driver;" & _
"SERVER={xxx};DATABASE=xxx;PORT=3306;" & _
"UID=" & uid & "; PWD=" & pwd & ";COLUMN_SIZE_S32=1;DFLT_BIGINT_BIND_STR=1;OPTION=3"
Set dbs = CurrentDb()
dbs.QueryTimeout = 5
Set qdf = dbs.CreateQueryDef("")
qdf.Connect = strcon
qdf.sql = "SELECT current_user"
Set RST = qdf.OpenRecordset(dbOpenSnapshot, dbSQLPassThrough)
TestLogin = True
mysqlUser = uid
floor = DLookup("floor", "tblxx", "user ='" & mysqlUser & "'")
Set qdf = Nothing
Set RST = Nothing
DoCmd.Close
DoCmd.OpenForm "Switchboard"
exit_errorTrap:
Set qdf = Nothing
Set RST = Nothing
Exit Function
Ok, the WAY this works can be confusing.
On application start up we asume you do not by accient (or intention) let any form, any VBA code that runs to touch, or logon or use IN ANY POSSBILE way on startup.
Ok, with above? If you linked the tables correct without UID/Password, if you touch, or even try to open a table from the nav pane? you SHOULD get a ODBC prompt. So, test the above - hold down shift key during startup - NO CODE or NO touch of a linked table is assumed here.
Now, click on a linked table - if the table opens, then you screwed up your table linking, and you DO NOT need the logon, then, right????
Next issue - and READ VERY careful.
If you execute a VALID logon (with your logon code), then ONCE you done this, the correct connection is cached - you can NOT IN ANY POSSBILE way blow out, remove, or re-set that cache.
If AFTER having executed ANY valid logon?
Then ANY ADTIONAL attempted logons (say with your logon code) WILL ALWAYS return true and valid. INCLUDING WRONG logons!!!! (they STILL return true!!!!).
The above information thus means some very significant issue's.
to clear hte logon, you will have to (must) exit Access. You thus can't crete a logout form - you must EXIT applcation.
Worse yet, you BETTER ALWAYS BUT ALWAYS BUT ALWAYS exit access first to clear that cache when developing and testing re-linking of tables. If you at any point in time during development by intention (or accident) open a linked table, and enter uid/password (or do so via code, or do so by JUST clicking on a linked table that DOES and DID save the uid/password?.
Then if you decide to re-link tables - EVEN WITH a incorrect UID/password, they WILL REPORT they linked ok!!!! - but they did not!!!! Even during re-link, if you use the wrong UID/Password, you are screwed, since access will in fact use the cached one (if your uid/password are wrong!!!!).
So, you first have to 100%, if not 200% do the first test above - check, double check/ triple check that linked tables do NOT WORK when clicked on.
Now, run your VBA logon.
Now, cliking on any linked table should work. But as noted, ONCE you touched, or logged on (by any possbile means), the UID/PW is cached, and will remain so for that session until such time you exit access.
What this means is you get ONCE chance to logon. They can fail, but the instant you achieve ONE successful logon, then ALL FURTHER attempts at logons WILL WORK - even if incorrect.
In summary:
You can prompt for a logon.
you can do this without having to re-link tables.
All linked tables, and EVEN pass-though queries will use that cached logon.
You MUST exit access to clear this cache, and thus it is IMPOSSILE to now launch your custom logon form and logon with a different user, since the previous user remains cached.
This also as noted means during deveopment, to link tables without uid/pw, you need to exit Access. launch access (without ANY POSSBILE touch of linked tables/data).
You then execute your logon. You THEN re-link tables without UID/Password. Then you have to exit access, re-launch (shift startup by-pass). Now click on a table - it should fail - prompt for odbc.
But, if you exit, shift- by pass startup. Execute your logon. Now click on a linked table - it should work. If it does not, or the first test (without a logon DID work, then as noted, you have royal screwed up something here.
so, for wrong/incorrect logons? You can continue trying to log on.
But ONCE you have logged on - that's quite much the end of this process. Any further attempts at logons will ALWAYS work - even for totaly wrong logons - you have to exit to clear the PW cache.
you also as a result can thus not use two cached passwords - say some tables linked as read only, and some tables linked as read/write (based on different uid/pw). and the reason is you can't control which logon will be used - and access will thus choose the read/write logon.
So, I suppose the most simple explain?
Once a uid/pw is cached, then you can and will be able to use all linked tables regardless of what uid/logon you attempt to use. And EVEN if at that point in time you did decide to run your re-link code? it will re-link JUST fine, even if you supply a incorrect uid/password. But, be carful!!! - you can in some cases thus re-link, check that the tables worked, but when you exit, and re-enter - you find those linked tables now don't work!!!
So, be VERY careful, if not outright SUPER careful when you re-link, especially if you been messing around with connections - you have to exit access, shift by-pass startup. and THEN re-link your tables. One stray cached uid/password, and you are in heaps of trouble - since things will work, and not make any sense at all.
keeping the above simple concept in mind - all will and should now make sense.
I been using this code:
Function TestLogin(strCon As String) As Boolean
On Error GoTo TestError
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Set dbs = CurrentDb()
Set qdf = dbs.CreateQueryDef("")
qdf.connect = strCon
qdf.ReturnsRecords = False
'Any VALID SQL statement that runs on server will work below.
' this does assume user has enough rights to query built in
' system tables
qdf.sql = "SELECT 1 "
qdf.Execute
TestLogin = True
Exit Function
TestError:
TestLogin = False
Exit Function
End Function
now you used a pass-though query - and I never done/use that before - and don't think it will work. You have to use above format.
I have some VBA that programmatically updates the location of linked tables so that the front end of my database can be easily pointed at a different back end, without needing to click around in the Linked Table Manager. The technique is explained in this Microsoft blog post. This should be as simple as running the following code for each linked table in CurrentDb.TableDefs:
tableDef.Connect = ";DATABASE=" & newBackEndPath
tableDef.RefreshLink
However, when the table contains a multi-valued field, Access provides the following unhelpful and misleading error message:
Run-time error '3125':
'[table name]' is not a valid name. Make sure that it does not include invalid characters or punctuation and that it is not too long.
The same error appears when manually updating the links from the Linked Table Manager, although sometimes after a few attempts, the update will work without an error message. To work around the problem, I'm trying to refresh the link by creating a new TableDef and then renaming it over the old one:
Dim tdf As TableDef
Set tdf = CurrentDb.CreateTableDef(originalTableName & "_Copy")
tdf.Connect = ";DATABASE=" & newBackEndPath
tdf.SourceTableName = tableName
With CurrentDb.TableDefs
.Append tdf
.Refresh ' Required?
End With
RefreshDatabaseWindow ' Required?
DoEvents ' Required?
DoCmd.Rename originalTableNameName, acTable, originalTableNameName & "_Copy"
This usually works, but sometimes DoCmd.Rename throws the following run-time error:
Run-time error '7874':
Microsoft Access can't find the object '[table name]_Copy'.
If I enter the debugger, this usually triggers some kind of refresh and the _Copy table appears in the navigation pane. If I press F5 at this point, DoCmd.Rename executes with no problems. Clearly, there is some delay after the TableDef is appended before it can actually be found and renamed. I've added the TableDefs.Refresh, RefreshDatabaseWindow and DoEvents lines in an attempt to force the new table to appear, but they don't seem to help. Even forcing a delay of a few seconds doesn't seem to work, but somehow, opening the debugger does.
Is there any reliable way to refresh a linked table that contains a multi-valued field?
(I ignored the advice to avoid using multi-valued fields when I started this project, because I wanted users to be able to filter on multi-valued fields using the Quick Filters on a split form datasheet. This function is very helpful, but I'm beginning to wish I just built my own filtering UI after encountering this and numerous other bugs in the implementation of multi-valued fields.)
You could try a different approach altogether, by using DoCmd.TransferDatabase:
DoCmd.TransferDatabase acLink, "Microsoft Access", newBackEndPath, acTable, tableName, tableName
DoCmd.TransferDatabase is similar to using the GUI to link the table. It handles steps like refreshing the database pane for you. I usually recommend using TableDefs instead, but this situation might be an exception.
Of course, I support Sergey's advice to not use a multi-valued field. I'm a fan of the user experience of multi-valued fields and the associated comboboxes, but it has far-going consequences to use a MVF, like not being able to migrate your database to SQL server in the future
Background:
Split access database, maximum two users. The back end is located on one of the two computers on a mapped drive and the front end is local. The computers are connected to the router by wifi. (I am trying unsuccessfully to get them to connect the computers via cable)
Edit: This problem is now happening in a single user environment.
Problem:
This is happening on one specific form only. Its underlying table has a multi-value field.
Issue 1: We have a situation where a field will be edited, but as soon as the focus moves to another field the edit reverts back to its original value.
Issue 2: When editing one field, some of the other fields are getting the values of the previously shown record.
Note: Navigation from one record to the other is done as follows:
Me.RecordsetClone.FindFirst "ID = " & cmbLocateRecipientID
Me.Bookmark = Me.RecordsetClone.Bookmark
The issues only happen occassionaly.
This is an extremely weird behaviour on the part of Access, so when the users first reported the issues I was convinced that they were entering information mistakenly into another record. However, they have since shown me the issue happening live.
Closing and reopening the form solves the issue. However, they can obviously not work in such a fashion.
I cannot reproduce the problem on my development machine.
Me would think you have to specify and use the recordset object:
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
rs.FindFirst "ID = " & Me!cmbLocateRecipientID.Value & ""
If Not rs.NoMatch Then
Me.Bookmark = rs.Bookmark
End If
Set rs = Nothing
A similar change may be needed in other parts of your code.
You can't use MS Access on a wireless network as "wireless" does not keep a continuous link between the frontend and backend. There are occasional dropouts which you don't notice with most things, however MS Access is very sensitive to this and you will have all sorts of problems over wireless. You must use a physical cable as the connection.
I've been asked to do some maintenance on an Access 2007 VBA database.
It has linked tables to another Access database in the same folder. It had hard-coded links to that database, so if the user copied the folder to a new folder, it tried to use the linked database in the original folder. They asked me to eliminate the danger of using the wrong linked database in that scenario.
I added code that runs when the database is opened, to make it reset the links to the database in it's own folder. If the linked database isn't there or was renamed, the user is prompted to browse to the correct database. So far so good.
But if the user cancels that dialog, I don't want to leave it connected to the wrong database. I want to set the linked tabledef's Connect property to the "correct" path even though the table is not there. Then the user will get an error that the linked table isn't there until they copy in the linked database -- rather than inadvertently use the wrong database.
When I use Resume Next to get past the error that is raised when I set the Connect property to a nonexistent database, the change doesn't stick, leaving it connected to the wrong database. So for now, I'm closing the database when that happens (after alerting the user that the linked database can't be found). That's safe in terms of not using the wrong database, but I don't think it's the ideal user experience.
So -- is it possible to set the Tabledef's Connect property to a nonexistent database?
Thanks,
Greg
is it possible to set the Tabledef's Connect property to a nonexistent database?
I don't think so. I recommend you delete all of the linked tables first, and then if there's no database to connect to, show an error saying so.
In order to relink the tables you will then need to have a local table in your frontend file that holds a list of all tables to be linked. Then you'll need to loop through that list every time you need to relink the tables, assuming that the links have all been deleted.
In order to update table links to render them invalid you need to
create a temporary copy of the back-end database (or perhaps a temporary copy of a "skeleton" back-end database with empty tables),
update the table links to point to the temporary database, and then
delete the temporary database.
For example, if I run the following code
Option Compare Database
Option Explicit
Sub MakeBadLink()
Const linkedTableName = "myLinkedTable" ' test value
Dim cdb As DAO.Database, tbd As DAO.TableDef
Dim tempFolder As String, linkedDb As String, tempDb As String
Dim fso As FileSystemObject
Set cdb = CurrentDb
linkedDb = Mid(cdb.TableDefs(linkedTableName).Connect, 11) ' remove ";DATABASE=" prefix
Set fso = New FileSystemObject
tempFolder = fso.GetSpecialFolder(TemporaryFolder) & "\"
tempDb = tempFolder & fso.GetFileName(linkedDb)
fso.CopyFile linkedDb, tempDb, True
Set tbd = cdb.TableDefs(linkedTableName)
tbd.Connect = ";DATABASE=" & tempDb
tbd.RefreshLink
Set tbd = Nothing
Set cdb = Nothing
fso.DeleteFile tempDb
Set fso = Nothing
End Sub
then any subsequent attempts to use [myLinkedTable] result in the error
Could not find file `C:\Users\Gord\AppData\Local\Temp\myDb.accdb'.
I'm writing an MS Outlook (2003) macro which uses an ADO Connection to an Access DB (2003). I am opening a connection, getting some records into a Recordset, which I use to populate a grid (but not bind to). I then close the Recordset and Connection and set both to Nothing.
The process creates an instance of MSACCESS.EXE, and a .ldb file for the Access DB, both of which remain after I have closed the Connection, Recordset, Macro and Outlook itself. One or both of these remnants is preventing opening the Access DB until the MSACCESS.EXE process is manually killed and the .ldb file is deleted.
Similar posts say "close the connection" but that is not solving the problem.
Here's the VBA code:
Screen.MousePointer = vbHourglass
Set db = New ADODB.Connection 'Declared at module level
Set rs = New ADODB.Recordset 'Declared at module level
Dim sSQL As String
sSQL = "SELECT Customers.ContactFirstName As Name, Customers.ContactLastName As Surname, Customers.EmailName AS Email, Customers.Address, Customers.Area, Customers.Town FROM qryCustomersWithEmail ORDER BY Customers.ContactLastName ASC"
db.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & "C:\My Documents\Tables.mdb;Persist Security Info=False"
rs.Open sSQL, db, adOpenStatic, adLockReadOnly
If rs.RecordCount > 0 Then
'actions performed on recordset removed
End If
rs.Close
db.Close
Set rs = Nothing
Set db = Nothing
Screen.MousePointer = vbDefault
It's on Vista.
I'm doing this to provide my customer with an easy way to send bulk emails to everyone in his Access database. I tried by accessing Outlook from Access but the security "feature" of Outlook, which pops up a warning message for every email created, scuppered this approach.
UPDATE.
I removed PopulateFlexGrid and the problem still occurred just for opening and closing the recordset. What I previously omitted from this sample, as I considered it irrelevant is that I wrapped the code with Screen.MousePointer = vbHourglass at the start and Screen.MousePointer = vbDefault at the end. I removed this and the problem no longer occurs. Stepping through I see MSACCESS.EXE start up in TM when I call Screen.MousePointer = vbHourglass.
I also tried a version where I used DAO instead of ADO, no other difference, and it works without creating .ldb or starting up an MSACCESS.exe. This works with the Screen.Mousepointer code in there.
Can anybody explain this?
The answer to this is that the reference to
Screen.MousePointer
which i'd omitted as irrelevant, is actually a member of Access. Hence when i call it MSACCESS starts up.
I should have used
Me.MousePointer = fmMousePointerHourGlass
So it's my fault for copying some code from Access VBA to Outlook VBA and expecting it to work the same. Apologies to all of you who spent time looking at this!
What is the code of the function PopulateFlexGrid? Is it possible this is not closing the recordset passed to it?
Try removing this line and instead just looping through the code without doing anything and seeing if it still leaves the LDB. If it still leaves the LDB then the problem is not with the PopulateFlexGrid function
I agree with david saying there is something unclear here. Such a code cannot create an instance of Access or an .ldb file. This code could even run without Access being installed on the machine.
Could you open your recordset with a clientSide cursor? Using a serverSide cursor might cause the access file to be modified (not sure ...) in a way or another. To make sure that your next command does not interfeer in a way or another with access, you could even copy your record locally (to an xml file), close both records and connection, reopen the recordset with the xml file as datasource, and then populate your flexgrid.
By the way, and though it has nothing to do with your problem, it is usually preferable to split the object declaration to:
dim myObect as ADODB....
set myObject = New ADODB....