I have used Access 2003 to develop a frontend to a SQL Server database. Because the system was intended to use different Schemas to partition the table data, an Access Project did not work. So, instead, I am forced to take over the connection management for access - I maintain a global connection object, and assign recordsets to Forms rather than recordsources.
One issue this causes - any time someone tries to use built-in Access functionality that interacts with the recordset, the operation doesn't work, and a dialog box is displayed saying 'Data Provider could not be initialised'. I've done some research, and have been unable to find a relevant cause for this, but I suspect it's due to Access expecting a Form to have a proper recordsource property, and does not really work with assigned recordsets.
Anyone able to shed any more light on this one? Is there a way to use self-managed recordsets, AND make use of built-in functionality? Can anyone confirm this is an Access bug?
After some playing around, I found a partial solution. I was using Client-side cursors, but leaving the recordsets connected. By instead disconnecting the recordsets, the Data Provider messages went away. Of course, that introduced other issues, but that's another story...and of course, I still don't understand WHY doing this made a difference...anyone else?
Related
My company uses a shared MS Access database, with a back end stored on a server and a front end copied onto users desktops.
Recently, our IT department moved us to a new server without giving us any notice, and now our database keeps crashing.
Every 20-40 minutes, users get an error message that says:
Error 3043 Your network access was interrupted. To continue, close the database, and then open it again.
If they close and reopen, it does work. However, I'd like to stop this from happening, since it typically happens when they are in the middle of something and have to re-do everything.
I've already spoken with our IT consultants and they see no issue with our server/network, nor do they know anything about Access and therefore are no help.
Does anyone have any experience with this or have any ideas that may help me repair my database?
Thanks in advance.
Here are some thoughts:
It sounds very much like (short) network interruptions. MS Access doesn't like these at all, in particular it doesn't recover from a broken connection (even if very short) until you restart the frontend.
Network interruptions during write operations on Access backends are the prime cause of backend database corruption. Consider yourself lucky if you haven't experienced that yet. But you should backup and Compact&Repair the backend often (!) .
You can prevent backend corruptions by moving the backend to a server database, e.g. SQL Server Express (free). Errors will still occur ("ODBC call failed" instead of error 3043), but they will only affect the frontends.
You can probably work around all errors by changing the frontend from bound forms to unbound forms. This is a major undertaking.
I don't think there is anything you can do with the backend to prevent the errors.
If this database has value to your company, and IT says there is no problem, I suggest you escalate the problem to someone who can make IT look closer into the issue.
(How to do so would be a separate question, perhaps on SuperUser.)
I have an Access 2013 database split across a network that is mainly used via Citrix. I keep getting the error message that the database is in an inconsistent state and I don't know why. I created a query to capture the user name and machine id as a auto-exec macro so I can go back and ask users what happened etc. But what I'd like to know is if it would be possible to know which user first encountered this error? Can I trap the error somehow and know which user "caused" it? I have a feeling that this error happens prior to the auto_exec macro firing but I live in hope.
What I am hoping to be able to do is get with the Citrix team and see if they have a corresponding error or something in their logs.
.. sadly they are all sharing the same front end. It's only being used
for read-only lookup purposes. I wanted each user to have their own
copy but IT disagreed with me.
The only way it could work reliably, is if the accdb file itself is marked as Read-Only, and that would probably leave your application useless.
I've been through this with a client running a huge Citrix setup (40000+ employees) for an application with a priority. IT had for a reason a strict view on security, but though quite cooperative, they were of little help.
However, I got it solved by a VB script. It worked in the first attempt and so well, that I wrote up a description here:
Deploy and update a Microsoft Access application in a Citrix environment
The great thing is, that you probably won't need IT to do anything for you.
I am looking for a solution to effectively communicate between two running MS Access applications.
The approaches I tried so far is to use a common linked table and to use MSMQ service for communication. Both approaches work, but there is no way to "push" the data or command from one application to another and since MS Access doesn't support multi-threaded execution of VBA code, it is very difficult to implement polling without performance disadvantages.
Same time, VBA does support the addressof operator (from version 2000) that means we can also theoretically implement call-back functions in VBA and MS Access. But I have never seen any example how this can be used for inter-process communication and would appreciate any minimal example how I can send a string from one MS Access application to another without monitoring a shared table all the time.
You can use GetObject() to return the Access.Application object from another running db. With the application object you have access to just about everything you might need. Here's a contrived example of opening a form (but you can do a myriad of other things with the Application object):
Sub TestInterop()
Const mdbPath As String = "C:\OtherApp.mdb"
Dim OtherApp As Access.Application
Set OtherApp = GetObject(mdbPath)
OtherApp.Visible = True
OtherApp.DoCmd.OpenForm "Accounts"
End Sub
If the program is not already running, the GetObject() call will start the application (you would need to be careful if you have multiple versions of Access installed as it's difficult to know at runtime which version would actually open the .mdb). However, if GetObject() needs to start the app, it will do so with the visibility set to False, so we explicitly set it to True. If the app is already running, setting its Visibility to True will have no effect.
Consider it a wild idea, but may be put all your tables into sql express and/or sql ce and make look like a frontend to those tables?
What is the simplest way to allow one user write access and everyone else read-only access to a MS Access database on a local network?
I trust my users, but unfortunately Access saves changes to data as soon as the row of a table is deselected. Accidental keystrokes are saved without the user asking for the changes to be saved.
Some thoughts on controlling user rights to a Jet data store:
if you really want to lock things down, you'll never manage it with Jet, as it's inherently vulnerable because the user has to have WRITE access to the MDB file.
if you are content with controlling rights to the data in your front-end application, you could provide different front ends (one for WRITE users and one for READ-ONLY).
if you're not using ACCDB format, you can use Jet user-level security. It's a surprisingly complicated technology if you really want to lock down access to the data -- you have to follow all the instructions in the Jet Security White Paper to the letter, or your data will be open to anyone with the standard Jet workgroup file. And even once you're done, it is crackable (though not without spending $$$ to buy cracking software). BTW, database passwords before Access 2007 were completely useless and easily cracked. Access 2007 enhances the security by raising the level of data encryption, but a database password causes lots of issues and doesn't allow you to have more than one level of access (unless you provide two different front ends with different passwords -- cf. #2).
if you just want to use Jet ULS to control access in your front end, you can add your users to groups and then check the group membership in your front-end UI objects (i.e., forms), and give WRITE permission to the users who are in the user group that provides that level of access. The easiest way to do this, assuming you have more READ-ONLY users than those with WRITE permission is to have the READ-ONLY users log on as the default admin user (i.e., you do nothing for their setup), and have the WRITE users log on as a user in the group with WRITE permission. In other words, if they aren't logged on as user "admin", they have full WRITE access.
another alternative is to use NTFS security groups. API code for that is found on the Access Web, but it does require a Windows administrator to implement for you. Again, you would be limiting access in your front end application, rather than actually restricting user rights in the back-end MDB.
Only Jet ULS actually allows you to prevent a READ-ONLY user (who hasn't cracked your workgroup file) from editing your data. All users have to have network access to your back-end MDB, but you can make it hard for them to get to the data even without jumping through the hoops in implementing Jet ULS. Here are some steps to do that (and yes, all of these are a form of "security by obscurity" and will only slow down a READ-ONLY user determined to hack your back end):
Right click each table in your back end and turn on the HIDDEN attribute. This can also be done in code (see SetHiddenAttribute in Help). Naturally, if the end user sets their Access options to display hidden tables, this won't do anything. But most end users don't know about that, and if your users are running your app in the runtime, they won't have the option.
Change the back-end database's Startup Properties to not display the database window and to not use special keys. You can find code for setting the startup properties in the Help topic for "AllowBypassKey".
In your back-end, create a macro named AutoExec with one command, Quit. With special keys disabled, there is no way to prevent the execution of this macro, and as soon as the user attempts to open the back end (even if they hold down the SHIFT key, i.e., the standard keystroke for bypassing all startup routines), the database (and the instance of Access) will close.
Now, all of these things can be undone by someone who knows what they are doing. If you gave me a back end with these things implemented, I'd be in it in about 5 minutes, simply by running code in another Access database to change all these startup properties to give me access.
But your end users likely don't have that level of expertise. Any such user who does probably ought to be a WRITE user, no? :)
Yes, of course -- all of these things are easily hackable by anyone who knows how. But it's also easy to break into your house in seconds for the person with the right tools. That doesn't mean you don't lock the doors, even though it's not bulletproof protection from burglary.
Another consideration is that if you provide your users only the Access runtime instead of full Access, they won't be able to undo any of these settings in your back-end MDB.
Last of all:
Security is not solely a technical issue -- most of it is, in fact, a people problem. In order for people to do their work, you have to trust them to a certain extent in giving them access to your data. There is no technical solution to the problem of the untrustworthy system administrator, for instance, and the only way to fully protect your data is to not give them any access to it at all.
The easiest way would be to use share permissions. Grant write access to a group and put the users who must write to the database in that group. Put everyone else in a read group. This assumes you have a Windows domain, of course.
Here is a site that has some information on securing Access databases. It deals with Access 2000, there may be more options for newer versions.
This is the cheeky answer, but if you need better security, seriously consider upgrading to a more robust RDBMS.
I think it is possible using an ODBC connection to use Access as an interface to almost any database. For example, I have successfully configured a SQL Server 2008 Express Edition database with 2 users, one read/write and one read-only. I have been able to connect to the database from Access by opening an ODBC data source. So a user can have the Office-based report-generating and mail-merging functionality they are familiar with. But with any database server you wish.
This conversation may be a little old, but for some reasons I got the same problem recently. It will not suit to everyone, cause it relies not on M$ SQL Server but on MySQL. Use the MySQL ODBC connector (available here: http://dev.mysql.com/downloads/connector/odbc/), and store your tables on a MySQL server. The Access user's rights on tables will inherit from the MySQL user's rights. Pretty easy to customize...
Fact is, there is NO functional security for an access database.
The link below sells software that will 'recover' your access database Even if it has a a password.
It is a good thing they exist. Their program saved one of my customer's butts once when their previous programmer died and no one else had the password. Thanks to this program we could not get in and no data was lost.
http://www.stellarinfo.com/access-recovery.htm
And before you even think it, No, I do not work for them.
From the documentation, I would expect adModeShareDenyWrite to be the way, but it's not working right.
I'm using an Access database via ADO. My connection string says Mode=8, which is adModeShareDenyWrite. But when I try to delete a row from a table, I get:
Unspecified error, Description:Could not delete from specified tables., Source:Microsoft JET Database Engine
In other words, the setting is preventing ME from updating the database using my OWN connection.
I found a couple other posts on the web reporting the same thing, the adModeShareDenyWrite setting used with Access not working as documented.
I am looking for a solution that doesn't involve an administrator changing permissions. It needs to be something that my program can control.
My motivation here is to minimize the chances of database corruption. One of the causes of mdb file corruption documented by Microsoft is two apps writing to the same db. So, I want to make sure that only one app can have a write connection to the db. Others can read, but should fail when they try to write. Whoever makes a connection first wins.
Cory Trager wrote:
My motivation here is to minimize the
chances of database corruption. One of
the causes of mdb file corruption
documented by Microsoft is two apps
writing to the same db. So, I want to
make sure that only one app can have a
write connection to the db. Others can
read, but should fail when they try to
write. Whoever makes a connection
first wins.
Why are you worrying about it? Jet is by default a multi-user database engine. If somebody else is updating a table, the data pages involved will be locked as read-only (in the state they were before the write began).
There is no realistic reason to fear corruption from mere multi-user interaction. Corruption of Jet databases usually happens because of dropped connections or an interruption of the connection during a write (such as users who force quit an app that is not responding as fast as they want).
I think your fear of corruption is misplaced.
On the other hand, you should still be able to open with an exclusive lock, and I'm not sure why it's not working. Have you considered using DAO instead of ADO to manipulate Jet data? Given that it's the native data interface (instead of a generic interface layer), it ought to be easier.
One solution is to give them access to a copy of the database. They can change whatever they want, but it won't keep past your copying it over with the master.
I suppose you access here an MDB file from a client interface, whatever it is, and others can also connect to the same file at the same time. When you use adModeShareDenyWrite in your connection mode, it means that you can still share the data with others (no locks of any kind on tables or records in the MDB file) but it can't be modified (this is why you get an error).
One solution would be to manage your connection parameters, with something like that:
(where you have a user object with a '.role' property, or anything equivalent ...)
if activeUser.role = "admin" then
m_connectionMode = adModeWrite
else
m_connectionMode = adModeShareDenyWrite
endif
Then you can open your ADO connection with the parameter m_connectionMode. Administrators will be given the right to insert/update/delete while other users will ony be able to view the data. This means you have somewhere in your program, or ideally in a table, some data saying who is what in your application.
EDIT: Following multiples comments with Corey:
You won't be able to do what you want to do in a straight way. My proposal: when the app accesses the database, it checks for a special file in the .mdb folder (whatever the file is).
If this file exists, the app opens a "read-only" connection.
If this file does not exist, the app creates the file (you can create one for example with "transferDatabase") and open a read-write connection. Once you quit the app, destroy the file.
If you have multiple users connecting to an access database across a network you might want to consider upgrading to SqlServer instead of using Access.
Corey Trager wrote:
I am looking for a solution that
doesn't involve an administrator
changing permissions. It needs to be
something that my program can control.
Well, if the problem is due to NTFS permissions being read-only for the user, there isn't a thing you can do to make the MDB writable. You don't specify where the MDB is stored, on a server or on a local hard drive, but in either case, for a user to have WRITE permissions on the MDB, NTFS permissions have to be set to allow it (for a share on a server, it has to be allowed both on the SHARE and on the underlying file). If it's a local file, the best solution is to make sure that you're storing the file in a location in which user-level logons have full WRITE permission. This would be anywhere in the user profile, and just about nowhere else.
That said, I'm not really suggesting that this is the source of your problem (I really can't say one way or the other), just pointing out that if it is the cause, then there's not a damned thing you can do programmatically to work around it.