You can use OPL to create data files (databases) like those used by the Database. You can store any kind of information in a data file, and retrieve it for display, editing or calculations.
Data files (or databases) (picture)
are made up of records
For example, in a data file of names and addresses, each record might have a name field, a telephone number field, and separate fields for each line of the address.
In OPL you can:
Use the CREATE command like this:
CREATE filename$,logical name,field1,field2,...
creates a data file called "clients".
The file name is a string, so remember to put quote marks around it. You can also assign the name string to a string variable (for example "fil$="clients"") and then use the variable name as the argument "CREATE fil$,A,field1,field2".
You can have up to 4 data files open at a time. Each of these must have a logical name: "A", "B", "C" or "D". The logical name lets you refer to this file without having to keep using the full file name.
A different logical name must be used for each data file opened one called "A", one called "B", one called "C" and one called "D". A file does not have to be opened with the same logical name as the last time it was opened. When a file is closed, its logical name is freed for use by another file.
"field1, field2",... are the field names up to 32 in any record. These are like variables, so use "%" "&" or "$" to make the appropriate types of fields for your data. You cannot use arrays. Do not specify the maximum length of strings that the string fields can handle. The length is automatically set at 255 characters.
Field names may be up to 8 characters long, including any qualifier like "&".
When referring to fields, add the logical file name to the front of the field name, to specify which opened file the fields belong to. Separate the two by a dot. For example, "A.name$" is the "name$" field of the file with logical name "A", and "C.age%" is the "age%" field of the file with logical name "C".
The values of all the fields are 0 or null to start with. You can see this if you run this example program:
PROC creatfil: CREATE "example",A,int%,long&,float,str$ PRINT "integer=";a.int% PRINT "long=";a.long& PRINT "float=";a.float PRINT "string=";a.str$ CLOSE GET ENDP
When you first CREATE a data file it is automatically open, but it closes again when the program ends. If a file already exists, trying to CREATE it again will give an error- so if you ran the procedure "creatfil:" a second time you would get an error. To open an existing file, use the OPEN command.
OPEN works in the same way as the CREATE command. For example:
PROC openfile: IF NOT EXIST("example") CREATE "example",A,int%,lng&,fp,str$ ELSE OPEN "example",A,int%,lng&,fp,str$ ENDIF PRINT "Current values:" show: PRINT "Assigning values" A.int%=1 A.lng&=&2**20 REM the 1st & avoids integer overflow A.fp=SIN(PI/6) PRINT "Give a value for the string:" INPUT A.str$ PRINT "New values:" show: ENDP
PROC show: PRINT "integer=";A.int% PRINT "long=";A.lng& PRINT "float=";A.fp PRINT "string=";A.str$ GET ENDP
Opening/creating the file The IF...ENDIF checks to see if the file already exists, using the EXIST function. If it does, the file is opened; if it doesn't, the file is created.
Giving values to the fields The fields can be assigned values just like variables. The field name must be used with the logical file name like this: "A.f%=1" or "INPUT A.f$".
If you try to give the wrong type of value to a field (for example ""Davis"" to "f%") an error message will be displayed.
You can access the fields from other procedures, just like global variables. Here the called procedure "show:" displays the values of the fields.
Field names You must know the type of each field, and you must give each a separate name you cannot refer to the fields in any indexed way, eg as an array.
Opening a file for sharing The OPENR command works in exactly the same way as OPEN, except that the file cannot be written to (with UPDATE or APPEND), only read. However, more than one running program can then look at the file at the same time.
The last example procedure did not actually save the field values as a record to a file. To do this you need to use the APPEND command. This program, for example, allows you to add records to the "example" data file:
PROC count: LOCAL reply% OPEN "example",A,f%,f&,f,f$ DO CLS AT 20,1 :PRINT "Record count=";COUNT AT 9,5 :PRINT "(A)dd a record" AT 9,7 :PRINT "(Q)uit" reply%=GET IF reply%=%q OR reply%=%Q BREAK ELSEIF reply%=%A OR reply%=%a add: ELSE BEEP 16,250 ENDIF UNTIL 0 ENDP
PROC add: CLS PRINT "Enter integer field:"; INPUT A.f% PRINT "Enter long integer field:"; INPUT A.f& PRINT "Enter numeric field:"; INPUT A.f PRINT "Enter string field:"; INPUT A.f$ APPEND ENDP
The BEEP command makes a beep of varying pitch and length:
The duration is measured in 1/32 s of a second, so "duration%=32" would give a beep a second long. Try "pitch%=50" for a high beep, or "500" for a low beep.
The COUNT function returns the number of records in the file. If you use it just after creating a database, it will return 0. As you add records the count increases.
Use the APPEND command to save a new record. This has no arguments. The values assigned to "A.f%", "A.f&", "A.f" and "A.f$" are added as a new record to the end of the "example" data file. If you only give values to some of the fields, not all, you won't see any error message. If the fields happen to have values, these will be used; otherwise null strings ("") will be given to string fields, and zero to numeric fields.
New field values are always added to the end of the current data file as the last record in the file (if the file is a new one, it will also be the first record).
At any time while a data file is open, the field names currently in use can be used like any other variable for example, in a PRINT statement, or a string or numeric expression.
APPEND and UPDATE
APPEND adds the current field values to the end of the file as a new record, whereas UPDATE deletes the current record and adds the current field values to the end of the file as a new record.
When you open or create a file, the first record in the file is current. To read, edit, or erase another record, you must make that record current that is, move to it. Only one record is current at a time. To change the current record, use one of these commands:
POSITION `moves to' a particular record, setting the field variables to the values in that record. For example, the instruction "POSITION 3" makes record 3 the current record. The first record is record 1.
You can find the current record number by using the POS function, which returns the number of the current record.
FIRST moves to the first record in a file.
NEXT moves to the following record in a file. If the end of the file is passed, NEXT does not report an error, but the current record is a new, empty record. This case can be tested for with the EOF function.
BACK moves to the previous record in the file. If the current record is the first record in the file then that first record stays current.
LAST moves to the last record in the file.
ERASE deletes the current record in the current file.
The next record is then current. If the erased record was the last record in a file, then following this command the current record will be empty and EOF will return true.
FIND makes current the next record which has a field matching your search string. Capitals and lower-case letters match. For example:
would select the first record containing a string field with the value "Brown", "brown" or "BROWN", etc. The number of that record is returned, in this case to the variable "r%". If the number returned is zero, no matching field was found. Any other number means that a match was found.
The search includes the current record. So after finding a matching record, you need to use NEXT before you can continue searching through the following records.
"FIND("Brown")" would not find a field "Mr Brown". To find this, use wildcards, as explained below.
You can only search string fields, not number fields. For example, if you assigned the value 71 to the field "a%", you could not find this with FIND. But if you assigned the value "71" to "a$", you could find this.
"r%=FIND("*Brown*")" would make current the next record containing a string field in which "Brown" occurred for example, the fields "MR BROWN", "Brown A.R." and "Browns Plumbing" would be matched. The wildcards you can use are:
? matches any one character
* matches any number of characters.
Once you've found a matching record, you might display it on the screen, erase it or edit it. For example, to display all the records containing "BROWN":
FIRST WHILE FIND("*BROWN*") PRINT a.name$, a.phone$ NEXT GET ENDWH
FINDFIELD, like FIND, finds a string, makes the record with this string the current record, and returns the number of this record. However you can also use it to do case-dependent searching, to search backwards through the file, to search from the first record (forwards) or from the last record (backwards), and to search in one or more fields only.
You may experience some problems in using FINDFIELD with some versions of OPL. To ensure that problems are avoided use the line:
immediately before each call to FINDFIELD.
The first argument to FINDFIELD is the string to look for, as for FIND. The second is the number of the field to start looking in (1 for the first field), and the third is the number of fields to search in (starting from the field specified by the second argument). If you want to search in all fields, use 1 as the second argument and for the third argument use the number of fields you used in the OPEN/CREATE command.
The fourth argument adds together two values:
Immediately after a file has been created or opened, it is automatically current. This means that the APPEND or UPDATE commands save records to this file, and the record-position commands (explained below) move around this file. You can still use the fields of other open files, for example "A.field1=B.field2"
USE makes current one of the other opened files. For example "USE B" selects the file with the logical name B (as specified in the OPEN or CREATE command which opened it).
If you attempt to USE a file which has not yet been opened or created, an error is reported.
In this procedure, the EOF function checks whether you are at the end of the current data file that is, whether you've gone past the last record. You can use EOF in the test condition of a loop UNTIL EOF or WHILE NOT EOF in order to carry out a set of actions on all the records in a file.
PROC copyrec: OPEN "example",A,f%,f&,f,f$ TRAP DELETE "temp" REM If file doesn't exist, ignore error CREATE "temp",B,f%,f&,f,f$ PRINT "Copying EXAMPLE to TEMP" USE A REM the EXAMPLE file DO IF a.f%>30 and a.f<3.1415 b.f%=a.f% b.f&=a.f& b.f=a.f b.f$="Selective copy" USE B REM the TEMP file APPEND USE A ENDIF NEXT UNTIL EOF REM until End Of File CLOSE REM closes A; B becomes current CLOSE REM closes B ENDP
This example uses the DELETE command to delete any "temp" file whch may exist, before making it afresh. Normally, if there was no "temp" file and you tried to delete it, an error would be generated. However, this example uses TRAP with the DELETE command. TRAP followed by a command means "if an error occurs in the command, carry on regardless".
There are more details of TRAP in the chapter on `Error Handling'.
You should always `close' a data file (with the CLOSE command) when you have finished using it. Data files close automatically when programs end. You can only have 4 files open at a time if you have 4 files open and you want to access another one, close one of them. CLOSE closes the current file.
When you change or delete records in a data file, the space taken by the old information is not automatically recovered. By default, the space is recovered when you close the file, provided it is on `Internal drive' or on a RAM SSD (ie it is not on a Flash SSD).
Closing a very large file which contains changed or deleted records can be slow when compression is enabled, as the whole file beyond each old record needs copying down, each time.
You can prevent data file compression if you wish, with these two lines:
p%=PEEKW($1c)+$1e POKEW p%,PEEKW(p%) or 1(Use any suitable integer variable for "p%".) Files used by the current program will now not compress when they close.
Use these two lines to re-enable auto-compression:
p%=PEEKW($1c)+$1e POKEW p%,PEEKW(p%) and $fffeWarning: be careful to enter these lines exactly as shown. These examples work by setting a system configuration flag.
If you have closed a file without compression, you can recover the space by using the COMPRESS command to create a new, compressed version of the file. "COMPRESS "dat" "new"", for example, creates a file called "new" which is a compressed version of "dat", with the space which was taken up by old information now recovered. (You have to use COMPRESS to compress data files which are kept on a Flash SSD.)
The files you use with the Database (listed under the Data icon in the System screen) often called databases or database files are also just data files.
Data files created by the Database can be viewed in OPL, and vice versa.
In OPL: to open a data file made by the Database, begin its name with "\DAT\", and end it with ".DBF". For example, to open the file called "data" which the Database normally uses: