ADVERT: RMR Software
Please visit the sponsor of this series, and don't forget to say where you heard of them!
3-Lib banner

The Absolute Beginners Guide to OPL

Part 34 - A database starter


Please ensure you have the latest version (1.7) of the RMREvent program from the RMR web site before reading through this tutorial. If you use an older version, some of the text may not make sense.


This is the last in the current session of OPL/32 tutorials based on RMREvent. Some of the procedures haven't yet been touched upon, but hopefully these are obvious enough to not need much explanation. If you have any specific areas you'd like to see covered. please email me so that I can research material for a new series starting in April 1999. From January 'til April, I'm going to run a 16-bit Series 3-only example project, with the raw code again provided by RMR.

Let's examine the way OPL/32 handles databases. We touched on simple databases in session 11, and to be backwardly compatible OPL/32 was designed to work even using the simple OPL/16 commands. Under the surface however, EPOC uses an advanced SQL-based data system. SQL stands for Structured Query Language and is something of an industry standard - by giving OPL/32 an SQL-friendly language Psion have ensured that companies can implement their corporate applications as painlessly as possible.

One of the advanced features of the RMREvent example is that it creates a data file with the "full" SQL-like syntax, including an 'Index' on the date field. Then, once OPENed, it shows how to make OPL/32 sort by date and also puts in place an example 'Filter'. Welcome to the world of database jargon!

Note that at the top of the main RMREvent program is a line:

INCLUDE "DBASE.OXH"

Due to the complexity of its database operations, OPL/32's designers decided to put most of the non-trivial functions into a special OPX in the Series 5's ROM. As with previous OPXes, you can view the contents of the OPX by doing Create standard files within any OPL/32 program and then opening the dbase.oxh file that gets created. You might like to do this now and print out the file for easy reference. Skip ahead in RMREvent to the Create: procedure.

PROC Create:(File$)
LOCAL Key1&
SETDOC File$
CREATE """"+File$+""" FIELDS Date,Number,Details TO Entries",A,F1&,F2%,F3$
USE A : CLOSE
Key1&=DbNewKey&:
DbAddField:(Key1&,"Date",1)
DbSetComparison:(Key1&,1)
DbCreateIndex:("Date",Key1&,File$,"Entries")
DbDeleteKey:(Key1&)
DocumentName$=File$
LastUsed$=File$
ToolBarTitle:(File$)
giPRINT "File created"
ENDP

Let me talk you through the procedure above. The SETDOC command is one of OPL/32's little 'kludges'. Essentially it says: "Look, the file I'm mentioning by name here is about to be created. When I do this, please jump in and insert the right header informsation so that the system screen will show the file as having the right icon." If we don't use SETDOC , the file File$ will end up with a 'question-mark' icon next to it, something which is guaranteed to confuse users when seen in their default folder.

Following SETDOC, the next thing is, of course, to actually create the file itself. Note the funny sequence of quote marks at the start of the command. They're there just on the off chance that the user chooses a filename that includes spaces - it's a standard feature of most programming languages that if you want to include a quotes character within a string (itself of course delimited by quotes) you just put it in twice and the language works out what you want. Thus a double-double-quote within text string end-quotes equates to OPL sticking in a quotes character in the CREATE command here. It's all rather clever, as if the user now asks for a filename which includes spaces, there will be hard quotes characters in the right places to delimit it and make sure CREATE doesn't get confused into taking part of the filename as a parameter.

The rest of the CREATE command can also be confusing... OPL/32 treats a database file as a group of tables, each giving different views on subsets of the larger data set. Thus the line:

CREATE """"+File$+""" FIELDS Date,Number,Details TO Entries",A,F1&,F2%,F3$

asks OPL to create a Table called 'Entries', with the fields Date, Number and Details. These are to be of type long integer, integer and string (taken from the types of the variables F1&,F2% and F3$.

Tip from Klaus Schnaible:
Declare each database string field in the Create database command with its length, e.g.
CREATE "File FIELDS a(20), b(15), c to TABLE", A, a$, b$, c%
When creating an index and a text field is called, you otherwise get a DISK FULL error.
 

Having created the database, RMREvent then closes it immediately on the next line (it will be opened later in procedure OpenFile:). The next five lines are somewhat mysterious, given that we've now closed the database itself. What RMREvent is doing is creating an index system in memory that can be applied to any database opened thereafter. A Key (yet more database jargon!) is created - think of it as the quick-name of a particular index. The key Key1& is then associated with a named field, i.e. "Date".

DbSetComparison:(Key1&,1) tells OPL to use mode 1 for field comparisons when doing its sorting using anything associated with Key1& . A quick look at the OPL/32 manual on the PsiWin CD tells me that mode 1 is 'Folded' (case-insensitive), the most useful mode in real world situations.

The next line is one of the most important. A key is, remember, just a numerical pointer to an index, and it's now time to create a real index (think of preparing blank index pages in a book). DbCreateIndex:("Date",Key1&,File$,"Entries") does the actual creation, giving the new index the alphabetic name "Date" (again, think of creating an index of entries sorted by date in a paper book) and applying it to the file File$ and table "Entries" which we created earlier. OPL physically goes off and creates this index inside the database file, which is why we closed it down earlier, so as not to conflict with this index creation call. Sharp eyed readers will note that File$ hasn't been surrounded by clusters of quotes as before - I think this is just an oversight by RMR and you should continue to cope with filenames with embedded spaces in a real world example.

Now that the all-important index has been created, with its alphabetic name, the key (its numeric quick-name) is no longer needed and is deleted by DbDeleteKey:(Key1&) . And as things have now gone smoothly, RMREvent sets up the current filename as the name of its officially-open file, as displayed on the top of the toolbar.

So what happens when it's time to actually open up the file, complete with index, tables and the like? Let's find out. Scroll down a few pages to procedure OpenFile:

PROC OpenFile:
LOCAL Order$(20),Filter$(20),Ok%
dINIT "Message"
dTEXT "","The program has been asked to open the"
dTEXT "","the file : "+DocumentName$
dBUTTONS "Close",KDButtonEnter% OR KDButtonNoLabel% OR KDButtonPlainKey%
IF DIALOG
  SETDOC DocumentName$
  Order$=" ORDER BY Date"
  Filter$=" WHERE Number>4"
  TRAP OPEN """"+DocumentName$+""" FOLDED SELECT Date,Number,Details FROM Entries"+Filter$+Order$,A,F1&,F2%,F3$
  IF ERR
    giPRINT "Not a valid RMREvent file"
    RETURN KFalse%
  ELSE
    USE A : CLOSE
    LastUsed$=DocumentName$
    ToolBarTitle:(DocumentName$)
    giPRINT "File Opened"
    RETURN KTrue%
  ENDIF
ENDIF
ENDP

Notice the segment starting Order$= - typical OPL/32 database manipulation commands are so verbose and complex that it's usually a good idea to set up sensibly-named string variables to contain information that would otherwise make the actual database commands even longer. The OPEN command itself should by now be fairly obvious, but allow me to give you a plain english 'translation': Open the document in folded (case-insensitive) mode, selecting all three fields in the Entries table that we set up originally. The index "Date" is to be used to sort the records in the table and only those with a Number value of greater than 4 are to included. Once opened, logical table "A" can be treated much as you would a simple database in OPL/16, with EPOC taking care of working out what to show you and in what order.

Hopefully you'll by now have come to two conclusions about OPL/32 database handling:

  1. It's horrendously complicated compared to OPL/16, with more jargon than you could fill a bath-tub with.
  2. It's tremendously powerful. With judicious juggling of indexes and filters, most of the complicated sorting and filtering that many of us had to code by hand in OPL/16 is now taken care of much more efficiently by the operating system itself.

If speed and efficiency are an issue for you and your intended application, there's a very good case for diving in and experimenting, however daunting it all seems - the rewards really are worth it!

If you want to see more worked examples of OPL/32 database handling, check out Leigh Edwards' article on p77 of Issue 18 of Palmtop magazine.

Programming index