9.242.2 Other Parameters
Return Code - Error Handling and Error Activity
Invalid Character handling in Alpha, Char, String, BLOB, CLOB Fields
Must be formatted correctly for the operating system being used. For Windows either a fully qualified name in the format <drive>:\<path>\<file>.<suffix> may be used, or a shortened form such as <file>.<suffix>. The shortened form will replace or create the file in the current directory.
The <suffix> value DAT is conventionally used for permanent data files and TMP for temporary files. If the file exists it is opened and all existing data is erased. If the file does not exist it is created and then opened.
Invalid Character handling in Alpha, Char, String, BLOB, CLOB Fields
Some character values may corrupt the output file if they are inserted into the output data. This option specifies what should happen if an invalid character is encountered. The set of invalid characters that are scanned for varies by requested output format as follows:
|
Note: Only Alpha, Char, String, BLOB, CLOB fields are scanned for invalid characters.
The supported invalid character handling options are:
- B - Replace by Blank
The character is replaced by a blank character in the output stream.
- I - Ignore
The presence of the character is ignored. It is included into the output stream and may corrupt further processing of the file by other applications.
- R - Remove from Output
The character is removed from the output stream. This option effectively shortens the output field length by 1. You should not use this option when making "fixed format" output files.
This option is only required when the system is configured to use a comma (,) as the decimal point delimiter. By default, output numeric fields will use the comma but this may not be appropriate when other other products will not accept the comma. This option may be used to force this Built-In Function to use of the full stop/period character (.).
The other use for this parameter is the special 'R' (Remove) option that may be used when creating files for input to applications that use fixed record formats and "implied (by position)" decimal points.
The 'R' option can only be used with file formats 'C' and 'D'.
The Close Output File option prevents the Built-In Function from closing the output file when it has completed execution.
In normal use, a working list is loaded with data and passed to this Built-In Function. The list is read, written to the disk file, and then the disk file is closed. Subsequent use of this Built-In Function with the same file name will replace the existing file (and its data) with a new set of data.
By using the "do not close" option, much more complex processing may be performed such as in the following example.
To avoid using huge working lists which require a large amount of allocated memory, the following code will create any number of records in the output file even though the list being used is efficiently sized with just 100 entries. The list is acting like an output buffer for the application.
def_list #list fields(....) listcount(#count)
type(*working) entrys(100)
select fields(...) from_file(...)
add_entry #list
if (#count = 100)
use TRANSFORM_LIST #list (with "do not
close" option)
clr_list #list
endif
endselect
use TRANSFORM_LIST #list (with "close" option)
- To produce output files that have mixed record types. Consider an output file containing order details that has two different "record types". One for the order "header" and one for each "detail" item. A function to do this might be structured like this:
def_list #head fields(....) type(*working) entrys(1)
def_list #line fields(....) listcount(#count) type(*working) entrys(100)
select fields(...) from_file(orders)
inz_list #head num_entrys(1)
use TRANSFORM_LIST #head (with "do not close" option)
select fields(...) from_file(lines) with_key(...)
add_entry #line
if (#count = 100)
use TRANSFORM_LIST #line (with "do not
close" option)
clr_list #line
endif
endselect
use TRANSFORM_LIST #line (with "do not close"
option)
clr_list #line
endselect
use TRANSFORM_LIST #line (an empty list with "close"
option).
Some tips for using this option, and for using this Built-In Function are:
- This function is designed to be an interface between Visual LANSA applications and external applications. It is designed to open a file, write data to it, then, close it again. It is not designed to service more complex "system" level tasks such as maintaining an "always open" log file.
- Up to 50 output files may be open concurrently. The operating system you are using may have limitations or configuration options that lower this limit.
- There is no limitation on maximum record length. At the end of every record a New Line character will be added as an End Of Record delimiter.
- If the file created is to be read by TRANSFORM_FILE in version 10.0 of LANSA or prior, then the maximum record length must be 20000 bytes.
- Always place a final call to this Built-In Function to cause it to close the output file. Pass the working list as an empty or cleared list if you just want to close the file and not add any more data to it.
- This Built-In Function must check all arguments every time it is called, and also search through a list of currently opened output files looking for a match. Therefore it is most efficient when called just a few times with list(s) containing many entries, and least efficient when it is called many times with list(s) containing just a few entries.
With the introduction of RDMLX working list, which may contain up to 1000 fields, 2G (2147483647) entries with an entry length of up to 2Gb (2147483647 bytes ), in most of the cases you will not need the Appendage Lists. How ever if RDMLX appendage lists are used, the same rules as for RDML lists are applied (apart from the above). Note that when the primary working list is an RDMLX list, an appendage list cannot be used.
Up to 10 appendage working lists may be specified when invoking this Built-In Function. This Built-In Function uses a driving loop that can be represented like this:
-> do for each entry in the "primary" working list (ie: argument 1)
|
| map details of primary list entry "n" to output buffer
|
| -> do for each appendage working list that has been specified.
| | get a matching entry "n" from the appendage list.
| | -- if entry "n" can be found
| | | -- test the case of the entry's "appendage option"
| | | |----> when = A, Append this entry to the current record.
| | | |----> when = N, Write the existing buffer, ends the current record with a New Line
| | | | character . Clear the output buffer and map this entry into it to start a new | | | | record.
| | | |----> when = O, Omit (ie: skip) this list entry.
| | | |----> otherwise: Issue a fatal error and kill the function.
| | | -- endcase
| | -- endif
| -- enddo
|
| if the buffer is not empty, write output record from buffer.
|
-- enddo
Note the "appendage option". Any working list that is used as an appendage list must have an alphanumeric 1 field as its first defined field. This alphanumeric 1 field is the "appendage option" and indicates how the entry should be handled. The currently supported values are:
A |
Append this entry to the output buffer being built. |
N |
Write the existing buffer and make a new one with this entry. |
O |
Omit this entry from the output stream. |
The appendage option field is not really part of the list. Its value is tested, but it is not output to the output buffer, so it has no bearing in record layout and/or length calculations even though it is actually part of the working list definition.
So far the use of "appendage lists" may not be apparent. However, by using appendage lists you can solve the following problem:
- An RDML working list can contain at most 100 fields. However you may wish to output a file containing 120 fields (say). You can do this by using a primary RDML list of 100 fields and a single appendage list of 21 fields (including the appendage option field). The following example allows an output file with a record containing up to 199 fields to be created. Since up to 10 appendage lists can be specified this allows a theoretical total of 100 + (10 * 99) = 1090 fields in an output file record. Similarly some functions have their maximum RDML working list entry length restricted to 256 bytes (this is an IBM i limitation but it is imposed in Visual LANSA to maintain application portability). This limitation can also be easily overcome by using one or more appendage lists.
- If an RDMLX working list with 120 fields is used, the "appendage list" is not required.
The following example covers the "A" (append) option. However the "N" (new) and "O" (omit) appendage options can be effectively used to create "variable record files" in an efficient manner.
def_list #plist fields(....) type(*working)
def_list #alist1 fields(#aoption .....) type(*working)
change #aoption 'A'
select fields(...) from_file(....)
fetch fields(...) from_file(...)
fetch fields(...) from_file(...)
fetch fields(...) from_file(...)
add_entry #plist
add_entry #alist1
endselect
use TRANSFORM_LIST #plist (with appendage list #alist1)
Consider some sort of "transaction" output file that you must create for input to an existing mainframe application system.
Every customer must have a type "HDR" header record. There may be a type "ADR" address update record and there may be a type "BIL" billing record. Very old fashioned, but still very common.
By defining a primary list for the HDR data and two appendage lists for the ADR and BIL data (with appendage option fields) a "stream" of mixed format and optional records like this can be created by just one invocation of this Built-In Function. In this case the appendage options O (omit) and N (new) would be used.
HDR-HDR-ADR-HDR-BIL-HDR-ADR-BIL-HDR-HDR-ADR-BIL-HDR
If however, you wanted to create multiple BIL records for a single HDR record you would have to use the "do not close" option. See the reference in the Close Output File Option for more details of how this could be achieved.
Return Code - Error Handling and Error Activity
The following table indicates the types of errors that you can trap at the RDML level with an "ER" return code (User Trap) and those that will cause a complete failure of your application (System Error). System errors invoke Visual LANSA full error handling and cause the entire X_RUN "session" to end. They cannot normally be trapped at the RDML level.
|
Note:
It is very strongly recommended that you avoid building complex error handling schemes into your applications. Use a very simple trap like this at all levels of your application.
if (#retcode *ne OK)
abort msgtxt('Failed to .............................')
endif
Let the standard error handling Built-In Function to every generated application take care of the problem. Situations have arisen where user defined error handling logic has become so complex as to consume 40 - 50% of all RDML code (with no obvious benefit to the application). Do not fall into this trap.
The Julian Day Count is a uniform count of days from the past (-4712 January 1, 12 hours UTC (Universal Coordinated Time - the modern equivalent of Greenwich Mean Time) (Julian proleptic Calendar) = 4713 BCE January 1, 12 hours GMT (Julian proleptic Calendar) = 4714 BCE November 24, 12 hours GMT (Gregorian proleptic Calendar)). At this point, the Julian Day Number is 0.
The Julian Day Count is not related to the Julian Calendar introduced by Julius Caesar.
There are several algorithms of calculating the Julian Day Number. Although they are very similar to each other, the results may be different. The algorithm used by this Built-In Function calculates the Julian Day Number of any date given on the Gregorian Calendar. The Julian Day Number calculated will be for 0 hours, GMT, on that date.
1. Express the date as Y M D, where Y is the year, M is the month number (Jan = 1, Feb = 2, etc.), and D is the day in the month.
2. If the month is January or February, subtract 1 from the year to get a new Y, and add 12 to the month to get a new M. (Thus, we are thinking of January and February as being the 13th and 14th month of the previous year).
3. Dropping the fractional part of all results of all multiplications and divisions, let
A = Y/100
B = A/4
C = 2-A+B
E = 365.25x(Y+4716)
F = 30.6001x(M+1)
JD= C+D+E+F-1524
This is the Julian Day Number for the beginning of the date in question at 0 hours, UTC.
The following calculation is used to convert a Julian Day Number to a Gregorian date, assuming that it is for 0 hours, UTC. Drop the fractional part of all multiplicatons and divisions.
Note: This method will not give dates accurately on the Gregorian Proleptic Calendar, that is, the calendar you get by extending the Gregorian calendar backwards to years earlier than 1582 using the Gregorian leap year rules. In particular, this method fails if Y<400.
Z = JD
W = (Z - 1867216.25)/36524.25
X = W/4
A = Z+1+W-X
B = A+1524
C = (B-122.1)/365.25
D = 365.25xC
E = (B-D)/30.6001
F = 30.6001xE
Day of month = B-D-F
Month = E-1 or E-13 (must get number less than or equal to 12)
Year = C-4715 (if Month is January or February) or C-4716 (otherwise).
Also see