Showing posts with label subroutine. Show all posts
Showing posts with label subroutine. Show all posts

Saturday, January 13, 2018

Writing records to disk immediately using MIO

Last week, I ran into a scenario where I needed to create two subroutines that are called sequentially by another subroutine. The first sub creates a record and then the second sub queries the database for the record and performs extra processing. The workflow looks like this:
Overall Subroutine Begins
   Subroutine 1: creates a record
   Subroutine 2: does a select to obtain the record created in subroutine 1
Overall Subroutine Ends
There was a problem with this workflow that I was using just a FOR_THE command to create the record in sub 1. Since the record created in sub 1 stays in the running buffer, it never gets written back to disk until the overall sub ends. Because of that, sub 2 never finds the new record.

To get around this, my colleagues at Ferrilli suggested manually changing the MIO level so that sub 1's record is written to disk immediately. The code to be added is:

CALL @MIO.TRANSACTION(MIO.TX.SUSPEND)
FOR_THE record_id
  * set field values
END_THE record_id
CALL @MIO.TRANSACTION(MIO.TX.RESUME)

The two MIO calls modify the level of the buffer and that's where the magic happens. Using MIO.TX.SUSPEND, in effect, temporarily starts a new process level at level 0.  All I/O that is performed after the call to MIO.TRANSACTION using MIO.TX.SUSPEND will be held in MIO's buffers until the call to MIO.TRANSACTION using MIO.TX.RESUME is reached. In our case, as MIO.TX.RESUME is reached, the buffer of the transaction is flushed and the record is written to disk. Afterward, the MIO level returns to the normal running state. So my pseudo code looks like this at the end:

Overall Subroutine Begins
   Subroutine 1: creates a record
      CALL @MIO.TRANSACTION(MIO.TX.SUSPEND)
      FOR_THE record_id
          * set field values
      END_THE record_id
      CALL @MIO.TRANSACTION(MIO.TX.RESUME)
   Subroutine 2: does a select to obtain the record created in subroutine 1
Overall Subroutine Ends
Thanks Neal, Lea, and Geoff for the documentation, and Thomas Mantooth for verifying the code. GO FIGTEAM!

Thursday, July 6, 2017

Check if a record exists

There are a few ways to check if a record exists in a file.

1. Call the S.VERIFY.RECORD.EXISTS subroutine:

X.RECORD.ID = record ID to check

CALL S.VERIFY.RECORD.EXISTS(X.EXISTS, X.FILE.NAME, X.RECORD.ID)

IF X.EXISTS = 0 THEN // record doesn't exists
END
2. Use  CONFIRMED command (this is good for when the subroutine can't be called, such as in IS sub):

X.FILE.NAME = A.FILE.NAME
X.RECORD.ID = A.RECORD.ID
A.EXISTS = 0
IF LEN(X.FILE.NAME) AND LEN(X.RECORD.ID) THEN
CONFIRM X.RECORD.ID IN_FILE(X.FILE.NAME)

IF CONFIRMED THEN
A.EXISTS = 1
END
END
Source: Neal Webb

Wednesday, October 1, 2014

Check for record lock

XKV.FILE = Table ID / Record Key
XFV.FILE = Table/File Name
XR.FILE = ""
CALL @MIO.READ.RECORD(MIO.READU.EXIT.ON.LOCKED,XFV.FILE,XKV.FILE,XR.FILE)
IF MIO.STATUS = MIO.STAT.LOCKED THEN
   // File is locked
END ELSE
   // File is not locked
END

RETURN

Thursday, July 31, 2014

Check to see if a date is already converted to internal format

IF NOT(NUM(A.DATE)) THEN
      * date is not in internal format, needs converting
      A.DATE = ICONV(A.DATE,X.SN.DATE2)

END

Useful for input validation of dates on things like subroutines and ELF

* from Trevyn Bowden.

Monday, May 6, 2013

How to write to a file in Hold directory


============================================
Sequential I/O Subroutines
============================================

Each subroutine in the sequential I/O sub-system allows for up to 10 separate open files in a single session, each of which is represented by a file position number. All of these subroutines pass in a position number that represents the file you are opening. The sequence of calls must be done in the proper order.

When modifying a program that uses UniData Sequential I/O, you simply replace the functions for I/O with subroutine calls passing in the appropriate arguments. First, you need to open a sequential file, and then you may either read or write to the file. You can never perform a "read" function AND a "write" function on the same open sequential file. In other words, if you open a file for writing, then you may only write to that file. If you open it for reading, you may only read. You can also open the file to "append" but this is simply another form of writing. You can also use S.WRITE.EOF to truncate a file. You must finish by calling S.CLOSE.SEQ. (All of these rules and nomenclature are the same as when you are using the UniData functions for sequential I/O, but in this case are representative of a Unix environment).

----------------------------------------------------
The Subroutines
----------------------------------------------------

S.OPEN.SEQ: This routine is called first, and takes the following arguments:

-- A.FILE.NAME -- the directory path where the sequential file resides or will be created
-- A.RECORD.NAME -- the file to create in the directory path or the file to read.
-- A.POS -- is a number between 1 and 10. You must pass in the number of the file position you are manipulating. This allows you to manipulate up to 10 Sequential files at one time.
-- A.MODE -- is how you are opening the file. You can enter either "R", "W", or "A" (Read, Write or Append, respectively). If nothing is entered, this will default to "R".
-- A.ERROR.OCCURRED -- is what will be returned if there is an error; if the directory doesn't exist, if the file doesn't exist, etc...
-- A.MSG -- contains the exact reason for failure.

S.READ.SEQ or S.WRITE.SEQ, depending on the mode, is called next:

S.READ.SEQ: Arguments, in order, are:

-- A.OUTPUT.FILE -- contains the next record in the file.
-- A.EOF -- end of file flag
-- A.POS --
-- A.ERROR.OCCURRED --
-- A.MSG --

S.WRITE.SEQ: Arguments, in order, are:

-- A.OUTPUT.FILE -- the record to write into the sequential file
-- A.POS --
-- A.ERROR.OCCURRED --
-- A.MSG --

S.WRITE.EOF: Once you reach the end of a file or if you wish to truncate a file or overwrite the file contents, you call this. Its arguments, in order, are:

-- A.POS --
-- A.ERROR.OCCURRED --
-- A.MSG --

S.CLOSE.SEQ: You must always finish sequential I/O with a call to this. Its arguments, in order, are:

-- A.POS --
-- A.ERROR.OCCURRED --
-- A.MSG --

*--------------------------------------------------------------------------------------------------------------

Example:

*
GOSUB OPEN.FILE.WRITE
GOSUB WRITE.FILE
GOSUB CLOSE.FILE.WRITE

RETURN

*  ---------------------------------------------------------------*
*opens TestFile.txt in HOLD directory, write access, to buffer '1'
OPEN.FILE.WRITE:
CALL S.OPEN.SEQ("HOLD","TestFile.txt","1","W",X.ERROR,X.MSG)
RETURN

* Closes the file write buffer
CLOSE.FILE.WRITE:
CALL S.CLOSE.SEQ("1",X.ERROR,X.MSG)
RETURN

* write the text file to the directory
WRITE.FILE:
   CALL S.WRITE.SEQ("Something to write to the file here","1",X.ERROR,X.MSG)
RETURN
* ----------------------------------------------------------------*