Of Cursors and RowSets

A Cursor is an object that Commence uses to hand-out RowSets to the application. A RowSet is an object that the application uses to Query, Add, Edit and Delete data from the database.

In Commence, there is the concept of a single cursor, and four different types of RowSet objects. The different row set types are:

Each of these row set types performs one or more functions. For instance, the Query row set type can read data from a category, but it cannot write or delete or add data. The Edit row set can read the data, just like the query row set can, but it cannot delete data, or add data.

The purpose for having four different row set types is unclear to this software developer. Therefore, due to that general lack-of-understanding on my part, the Dumont implementation of the Cursors and RowSets is slightly different than the Commence implementation. Functionally, this means nothing, since the Dumont implementation is completely compatible with the current Commence implementation. The result, however, is a great simplification of the Cursor/RowSet API.

I'll explain the differences by providing a typical programming example. The first step is to get your hands on a cursor object, this is typically done with the following code:

vbScript Example - Getting A Cursor
 dim dexe: set dexe = createObject("Dumont.EXE") ' get a handle on dumont
 dim dapp: set dapp = dexe.applications("MyDB")  ' Get a specific app instance
 dim cursor: set cursor = dapp.db.getCursor( "Person" )
You now have a handle on a standard Cursor object, assigned to a category, and the category name is called "Person". I'm assuming there are people's names and phone numbers stored there.

Now, here is where the fun begins. Normally, when connected directly to Commence, you would fetch cursors using the following codes:

vbScript Example - Fetching Different Rowset Types
 dim qrs: set qrs = cursor.getQueryRowSet(  cursor.rowCount )
 dim ers: set ers = cursor.getEditRowSet(   cursor.rowCount )
 dim drs: set drs = cursor.getDeleteRowSet( cursor.rowCount )
 dim ars: set ars = cursor.getAddRowSet( 10 )
What you would have now is four different row set types, one for each of the row set types available from the Commence API. Note that this code example is still running through Dumont, and the Commands shown above still work in Dumont, even though Dumont has been enhanced greatly.

Here is another way to fetch the same row set objects using some of the new syntax that is available through Dumont:

vbScript Example - Fetching Different Rowset Types ~ The Dumont Alternative
 const ROWSET_QUERY  = 1
 const ROWSET_ADD    = 2
 const ROWSET_DELETE = 3
 const ROWSET_EDIT   = 4
 dim qrs: set qrs = cursor.getRowSet(  ROWSET_QUERY      )
 dim ers: set ers = cursor.getRowSet(  ROWSET_EDIT,   5  )
 dim drs: set drs = cursor.getRowSet(  ROWSET_DELETE, 10, "do-we-deletem-and-howe" )
 dim ars: set ars = cursor.getRowSet(  ROWSET_ADD,    10 )
Here is the thing to notice in the above two code examples. In both examples the *same* rowset object wrapper was fetched. It's just that each rowset wrapper has different properties. One of those properties is the rowset type. It is this type value that determines what the rowset is capable of doing. In each case, different types of rowsets are capable of doing different things. One can add, one can delete.

Another thing to notice, is that in the first "getRowSet" example, where we fetch a query rowset, we do not specify the row count. Why is that? Because we don't have to! The cursor already knows how many rows are on the rowset, so why does it need to be specified every time we ask for a rowset? It doesn't! And I've made Dumont not require this parameter value. You can put it on or leave it off if you like - your preference! If you leave the rowCount specification off the request then you will end up with a row set object that has the same number of rows in the originating cursor. How handy is that? Incidently the same thing can be done with the original call to getWhateverRowset. Behold:

vbScript Example - Fetching a RowSet sans RowCount
 dim qrs: set qrs = cursor.getQueryRowSet  ' get cursor.rowCount rows
 dim ers: set ers = cursor.getEditRowSet   ' get cursor.rowCount rows
 dim drs: set drs = cursor.getDeleteRowSet ' get cursor.rowCount rows
 dim ars: set ars = cursor.getAddRowSet    ' add just one row by default
That's the whole idea behind Dumont - making programming Commence easier.

Yet another thing to notice is that in one of the rowset fetch functions, I have specified another string "do-we-deletem-and-howe". What is this for? Well, the simple answer is, every object in Dumont has a name. And, a rowset, by way of Commence, doesn't have a name, but since we're wrapping a Commence rowset in Dumont, Dumont can provide one - if you want! You don't have to name your rowsets, but, depending on what you're doing you might want to.

Now,. you're wondering, what's the big deal? Why is it so important that there is only one object in dumont (cmcRowSet) that is wrapping all the four different Commence row sets objects? Here's the answer: "all of the four rowset objects are nearly identical, and use nearly the same code". I hate code duplication. It is the number one source to having bugs creep in to your programs; being forced to duplicate code when you shouldn't have to, but I digress. Let it suffice to say that I avoid code duplication as a first priority - otherwise what's the point?

The cmcRowSet object that is housed in Dumont is a smart object, and it knows from whence it sprang, and what type of rowset object is was springed as. With this knowledge, it is able to insure that you don't do something like take a QueryRowSet type of object wrapper and delete some rows with it. If you do, then you will get a stern warning from Dumont. So, don't do it. Don't even think about doing it!

But, if you do accidently use the generic row set object wrapper for a function it wasn't set up to do, that's all you will get - a stern warning. The function won't complete. and nothing will be requested (incorrectly) from Commence. Dumont will intervene before the request gets that far. And, that's another thing. If you have your hands on a rowset object, and you try to acess some data that is beyond the range of the rowset, Dumont will intervene there as well.

These are all good things, and makes working with Cursors and Rowsets in Dumont a pretty easy thing to do. Plus it's all documented here. Hey, what a concept - documentation!

~ ~ ~ ~ ~

Now, here is another topic on Cursors and Rowsets. There is somewhat of a new feature in Commence Cursors that allows one to fetch from the cursor the THID value from an item in question. This "feature", however, is nearly completely undocumented except for a few renegade .pdf files on the topic, and of course the most totally awesome http://www.freedomcomputing.com newsgroup.

These THID values are fetched from the Row Sets by making a call to the cmcRowSet::getRowID function. However, before you are able to make that call, you have to first open the cursor with the USE_THIDS parameter turned on. There is a problem with turning on THID values on cursors. It's complicated, but it has mostly to do with connection fields. When THIDS are turned on, and you request values from connection fields, you will get THID values for those connections rather than name values. This is something you need to think about before attempting to use the USE_THIDS feature of a Commence cursor object.

Take a look at the default values for the two functions:

The default values are for the flag (the last) parameter, and have the following meaning:

figure out what the two values are for opening a cursor.
 #define USE_THIDS      256
 #define SOMETHING_ELSE 512
By applying these two values when opening a cursor, then the rowsets created with that cursor will respond to getRowID function calls. If you desire, you can override this value when you make your calls to get a cursor object, but I'm not sure why you'd want to.

Once you have the cursor open, you can get a query row set on that cursor and begin probing it for THID values or whatever other values you want from the category.

There is a very long article in this documentation set that discusses how to open a cursor properly and assign columns to it and walk the items and columns and so on. That article is located here: Accessing Cursor Data using Column Labels

~ ~ ~ ~ ~ ~
Source Code without Comments is like a Cranberry Garland
without the berries. Comment your Code!
Commence Database Support User Group Forum
~ ~ ~ ~ ~ ~
Author: Mark Petryk
Lorimark Solutions, LLC