Thursday, July 16, 2015

Problem with sorting dates in Envision

I have encountered a bug today with one of the sort subroutines, S.SORT.BY.DL, that could result to other sorting issues. In one of the processes, the dates were not sorted in the correct descending-order. After some much digging through log files and test cases, I finally shred some lights to the issue. If the date array to be sorted contains date that is before 5/18/1995, the array will not be sorted correctly. The reason for this bug is related to the way Unidata stores date in the database. Unidata dates are stored as a counter from a default date, 1/1/1968. All dates are presented as a numbers, so 1/2/1968 has a value of 2, and 1/5/1968 has a value of 5 and so on. 

For that reason, let's consider this example. Say we have an array of dates of 01/01/2000 and 5/17/1995. In envision these two dates are presented by 11689 and 9999. Because Unibasic(Envision) is a loosely-typed language, these numbers can be considered as "strings" at run-time when their type is not strictly/explicitly enforced. So after sorting the date array with descending order:

XL.DATES = 11689:@VM:9999

You will get this:

XL.DATES = 9999:@VM:11689

This is because 9 is greater than 1, so 9999, as a string, is greater than string 11689. This is incorrect because 11689 is greater than 9999, as well as 01/01/2000 is later than 5/17/1995. I also tested S.SORT.ASSOC.DL and it seems to behave the same way. 

This issue is more applicable when you work with historical data. It can happen again in 80k days when the date reach 100,000. That is more than 200 years from now, I wonder if Unidata still exists, but I am sure I won't be around to worry about it.

Wednesday, July 8, 2015

How to get/query the list of files in a folder from Envision

Say you have a list of file in HOLD_SHARED_MYFOLDER directory in Colleague, and you want to read in the list of files in MYFOLDER and do something with them, maybe read or write or both.

What you need is read/write access to MYFOLDER. Your admin should know how to set it up, and a VOC entry should already be created for it. 

In Colleague Studio, use the following code to get back a list of files inside MYFOLDER directory:

X.STMT = 'SELECT HOLD_SHARED_MYFOLDER'
CALL S.EXECUTE(X.STMT)
XL.FILES.NAME = ''
CALL S.READLIST(XL.FILES.NAME,0,X.STATUS)
CONVERT @FM:@SM:@VM:@AM TO @VM:@VM:@VM:@VM IN XL.FILES.NAME
Now you will have all the files' names in MYFOLDER populated in XL.FILES.NAME. To open each file up, you iterate them with S.OPEN.SEQ subroutine

FOR X = 1 to DCOUNT(XL.FILES.NAME, @VM)
   * Open the file
   CALL S.OPEN.SEQ("HOLD_SHARED_MYFOLDER", XL.FILES.NAME<1,X>, X, "R", X.ERROR.MSG)
   * Read from the file
   CALL S.READ.SEQ(X.TEXT, X.EOF, X, X.ERROR, X.MSG)
   * Close the file
   CALL S.CLOSE.SEQ(X, X.ERROR, X.MSG)
NEXT X


Wednesday, July 1, 2015

Notes on S.EXECUTE subroutine

S.EXECUTE will execute a sentence to perform operations, such as a select statement against the database. This is Datatel's version of the Unibasic EXECUTE command (you can type HELP EXECUTE at the colon prompt for additional information about EXECUTE). Since EXECUTE only works for Unidata clients, we encourage people to use S.EXECUTE in its place.

UniQuery-syntax statements can be used with S.EXECUTE on any underlying database. These statements, when used with S.EXECUTE, will be converted by Datatel's underlying MIO components to the native database query language for executing the select statement.

There is only one argument for this subroutine:
A.STMT Input only The statement to execute; the format of this statement should be:
[<options>] <command> [<arguments>]

<options> are optional; it is a list of zero or more options that are separated by spaces, each of which begins with a dash ('-') character. Valid options are:

-H = Hush the output that may be generated by the command being executed; for example, the 'n records selected' message when a select statement is executed
-NM = Do not map SELECT/SSELECT commands to MIOSEL/MIOSELS; this option is NOT recommended for use unless you are certain the file being selected exists on the application server AND you are certain that the -NM option is necessary
-C = Capture output from the command in the CAPTURED.OUTPUT common variable
-DB = Force debug mode ON for execution of S.EXECUTE; same effect as entering S.EXECUTE in UTDB screen
-DH = Only valid on Distributed UniData deployments; Execute command on database server ('datahome')

<command> is a query language command such as SELECT

<arguments> are optional; is a string that contains arguments for the command (if applicable)

Example:
X.STMT = 'MIOSEL PERSON WITH LAST.NAME = 'Smith''
CALL S.EXECUTE (X.STMT)
FOR_EACH SELECTED ID
<code>
END_EACH SELECTED ID

The X.STMT line sets up the 'sentence' to execute. The next line that calls S.EXECUTE executes the statement. We now have an active list of PERSON records, of which we can use in the following FOR_EACH loop.