The Recordset's Open Method
the ADO Recordset's Open method accepts the following parameters:
objRS.Open source, connection, [cursortype], [locktype], [options]
where the [ ] indicates optional parameters.
Source: is an SQL Statement, a variable containing an SQL statement, the name of table within the database or the name of a stored procedure. If you are passing an SQL statement, a tablename or the name of a stored procedure the source must be enclosed in " marks.
Connection: is a valid ADO Connection String or a variable containing a connection string. You can also pass in a valid existing ADO Connection object. If you are passing in a connection string you need to enclose it in " marks.
CursorType:can be one: adOpenForwardOnly (default), adOpenStatic, adOpenDynamic, adOpenKeyset
LockType: can be one of: adLockReadOnly (default), adLockOptimistic, adLockPessimistic, adLockBatchOptimistic
Options can be any valid options. By far the most commonly passed in is an option to indicate the type of Source you are using eg adCmdText (for an SQL Statement), adCmdTable (if you want ADO to construct an SQL statement to get all the rows in a table), adCmdTableDirect (if you want to directly retrieve all the rows in a table - from ADO 2.5 onwards) or adCmdStoredProc (if you are accessing a stored procedure). If you do not specify the type of source then adCmdUnknown is used as the default.
Example of the correct use of the Recordset's Open method would be:
strSQL = "SELECT field1, field2 FROM table1"
strConnect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\db1.mdb"
objRS.Open strSQL, strConnect, adOpenForwardOnly, adLockReadOnly, adCmdText
- or -
strConnect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\db1.mdb"
objRS.Open "table1", strConnect, adOpenForwardOnly, adLockReadOnly, adCmdTable
When starting out with ASP development many struggle just getting ADO to work, let along worrying about how or why it works. What results in code that is more expensive than is really required - in order to get the code working developers always use the most expensive cursors, since they will support all operations, rather than using the most appropriate cursor for the job. If you don't know much about setting the cursor type for an ADO Recordset object you might want to read this first.
What is a cursor?
This is a difficult concept to explain - but I'll give it a go :-) A relational DBMS (like SQL Server) returns the results of your query as a set based recordset. Basically the results are the subset of records from the table(s) that match your search criteria.
However most people, and applications, don't operate on the results as a set. Instead they work on the results in a sequential order. E.g. you edit the first record, update the database, move to the second record & edit it, update the database etc, or perhaps you just wish to write the results into a HTML table - you write the 1st record, then start a new row, write the 2nd record, start a new row etc.
In order to facilitate this movement one uses an ADO cursor. A cursor keeps track of which record you are currently at in the recordset. Different types of cursors allow different types of actions. Some cursors allow only movement forwards. Others allow movement forwards, backwards, and allow you to set "bookmarks" so you can quickly jump to a pre-set position in the recordset.
Which cursor type should I use?
As mentioned above, each cursor type allows different types of operations. One allows forward movement only (adOpenForwardOnly), whereas others allow movement backwards and forwards. The question that is asked is: "Why should I use a forwardonly cursor when I can get additional benefits from using the more sophisticated cursors?". The answer to the question is "performance". The more sophisticated the cursor the more work Jet, and ADO have to do in order to keep track of the records in the Recordset. For example, with a ForwardOnly cursor, once you have moved past a record, ADO & Jet can forget all about it (since you can't move backwards). However with an adOpenStatic cursor, ADO & Jet have to keep track of all the records since you can always move backwards.
My personal experience with various tests (and also my reading) is that an adOpenStatic cursor is about twice as expensive as an adOpenForwardOnly cursor. By this, I mean that performing operations like writing out the records in the recordset take twice as long using an adOpenStatic cursor compared to an adOpenForwardOnly cursor.
What types of cursors are there?
There are 4 types of cursors supported by ADO. We'll look at them all briefly now:
adOpenForwardOnly: This is the lightest (cheapest) cursor, and the default when opening a recordset. It allows only forwards movement. Only the most minimal information about the recordset is calculated by Jet (eg you can't even get a .recordCount of the total number of records in the recordset). If you try to move backwards using this cursor, the recordset is closed, and the query re-executed. Avoid doing this!
adOpenStatic: A static snap-shot of the records that match your search criteria are put into the recordset. You can scroll forwards and backwards, and set bookmarks. Changes made to the database by other users however are not visible - all you can see are the records that matched your search at the point in time when the query was executed
adOpenKeyset: A static snap-shot of the primary key values of the records that match your search criteria are put into the recordset. As you scroll backwards and forwards, the primary key value in the recordset is used to fetch the current data for that record from the database. This cursor thus allows you to see updates to the data made by other users, but it doesn't let you see new records that have been added by other users (because the primary key values for those records are not in your recordset).
adOpenDynamic: A dynamic snapshot of the database is maintained by OLEDB/ADO. All changes by other users to the underlying database are visible. Obviously this is the most sophisticated cursor, and thus is usually the most expensive. Because the data in the recordset is dynamic, attributes like AbsolutePosition and AbsolutePage can not be set. The adOpenDynamic cursor is not supported by the Jet OLEDB Provider (see below).
What cursors are supported by Jet?
This is a tricky question to answer. When you open the recordset you can request any of the 4 cursor types above. However, depending on the locktype you request, and the command type that you specify, the Jet OLEDB Provider may change the cursortype to something else behind your back! Jet never changes the locktype that you request however.
The table below shows the cursor type that you get, depending on the cursor and locktype you request:
adLockOptimistic------ Keyset-------- Keyset-- Keyset--- Keyset----
adLockPessimistic----- Keyset-------- Keyset---Keyset----Keyset-----
adLockBatchOptimistic--Keyset-------- Keyset--- Keyset--- Keyset----
There is one caveat to the above. If you set the CommandType to adCmdTableDirect you always get an adOpenKeyset cursor. The above values told for CommandTypes adCmdText and adCmdTable. Also be aware that using client-side cursors results in an adOpenStatic cursor no matter what cursor type you request. This behaviour is common to all OLEDB Providers, not just Jet. The default cursor location is server-side, so you don't have to worry about this unless you explicitly set the cursor location to client-side.
If you would like to see the code that generates the above results table click here.