Server modules live separate lives

As much of the other posts I write here, this relates to something that surprised me.

Currently I write a lot of server modules as APIs, and this time I needed to submit a job for some processing. But for some reason this failed and I couldn’t find a reason.

That wasn’t really a problem, because I could just save the data I needed to process in a saved list and have a batch job read the list and do the processing.

Except, that didn’t work either.

Maybe that’s what Lansa means by

SAVE_LIST and RESTORE_SAVED_LIST should be used in the same context. That is, you should not use SAVE_LIST from within a function run on the WEB and later restore the saved list from within a function run as a Visual LANSA function.

Because even though the saved list was stored in DC@F80, the F80P#I field was not set to the partition I was using. It was set to “SYS”. So, in the batch job I couldn’t read the saved list, because the batch job was a regular function.

Adjust for a Datetime

The Date type has an Adjust intrinsic, which I commonly use for numbers as

#FAKYMD := #FAKYMD.AsDate( CCYYMMDD ).Adjust( -30 ).AsNumber( CCYYMMDD )

The Datetime type has no such intrinsic, but when I end up with a datetime stored in a number, I have used this roundabout way:

#FAKTIME := ((#FAKTIME / 1000000).AsDate( CCYYMMDD ).Adjust( -30 ).AsNumber( CCYYMMDD ) * 1000000) + (#FAKTIME.Mod( 1000000 ))

#FAKYMD is 8 digits, YYYYMMDD, #FAKTIME is 14 digits, YYYYMMDDhhmmss, in my examples.

 

Writing space to a file

This should be easy, but it’s not in RDML. The current solution I have is using HEXTOBIN and binary writing.

I am writing to a file and need to write a space character in certain situations. The codepage of the file is Windows-1252 (mostly equivalent to Latin1 or ISO-8859-1).

I opened the file with

Use Builtin(STM_FILE_OPEN) With_Args(#FILENAME 'APPEND TEXT LINETERMINATOR=NONE CODEPAGE=1252') To_Get(#FILENO #RETNCODE)

but if try to output a space character it gets trimmed and no space is added to the file. Instead I close, open, close and re-open:

Use Builtin(STM_FILE_OPEN) With_Args(#FILENAME 'APPEND BINARY LINETERMINATOR=NONE') To_Get(#FILENO #RETNCODE)
Use Builtin(HEXTOBIN) With_Args('20' Y) To_Get(#WCHAR1)
Use Builtin(STM_FILE_WRITE) With_Args(#FILENO2 #WCHAR1) To_Get(#RETNCODE)
Use Builtin(STM_FILE_CLOSE) With_Args(#FILENO2)
Use Builtin(STM_FILE_OPEN) With_Args(#FILENAME 'APPEND TEXT LINETERMINATOR=NONE CODEPAGE=1252') To_Get(#FILENO #RETNCODE)

This paradoxically only worked because I am running on a different codepage than Windows-1252, so the binary value 0x20 is not considered a space character (it’s Digit Select, whatever that is).

No, it’s not efficient.

Length of string

In RDMLX, easy, just

#LEN := #STR.CurChars

But in RDML it’s not so easy and for some reason there’s not even a buit-in function to return the length of a string.

So I made this:

Define Field(#W_C256) Type(*CHAR) Length(256)
Define Field(#W_C256_B) Type(*CHAR) Length(256)
Define Field(#W_C1) Type(*CHAR) Length(1)
Define Field(#W_D3_0) Type(*DEC) Length(3) Decimals(0)

Subroutine Name(LENGTH) Parms((#W_C256 *RECEIVED) (#W_D3_0 *RETURNED))
  Use Builtin(RIGHT) With_Args(#W_C256) To_Get(#W_C256_B)
  Substring Field(#W_C256_B 256 1) Into_Field(#W_C1)
  Use Builtin(REVERSE) With_Args(#W_C256) To_Get(#W_C256_B)
  Use Builtin(SCANSTRING) With_Args(#W_C256_B #W_C1) To_Get(#W_D3_0)
  Change Field(#W_D3_0) To('(256 + 1) - #W_D3_0')
Endroutine

which I then include when necessary.

Select_Sql does not validate SQL source

I made this error and spent a long time trying to spot it:

Select_Sql Fields((#ANTAL 'SUM(ANTAL')) From_Files(TRANS) Where(...)
...
Endselect

That is how I learned that the optional SQL source for a field is not validated in the editor or during compilation. Adding the missing end-parenthesis fixed my error:

                                    |
                                    V
Select_Sql Fields((#ANTAL 'SUM(ANTAL)')) From_Files(TRANS) Where(...)
...
Endselect

You got me there

Working with CONDCHECK I got confused. The condition check works to mark a field that is filled out incorrectly, but the condition is to be read as “these conditions should be satisfied, if not…”.

Which makes sense; you write the condition that you want satisfied. If it isn’t you get the message.

My problem was that I thought of it in the context of if … then; if this condition is satisfied, I should get the message. Which I now realise was wrong.

An XSLT example

I needed this, so here it is for posterity:

In the list BUTLST, I wanted to select the value from the field WCHAR36, on the entry where the value from the field BUTNR matched the mapped field IZBUTNR.

So, in sequence, I wanted

the list BUTLST

/lxml:data/lxml:lists/lxml:list[@name='BUTLST'] ...

the value from the field WCHAR36

... lxml:column[@name='WCHAR36']

on the entry where the value from the field BUTNR

... lxml:list-entries/lxml:entry/lxml:column[@name='BUTNR'][text() ... ]

matched the mapped field IZBUTNR

... = key('field-value', 'IZBUTNR') ...

Completed that is

/lxml:data/lxml:lists/lxml:list[@name='BUTLST']/lxml:list-entries/lxml:entry/lxml:column[@name='BUTNR'][text() = key('field-value', 'IZBUTNR')]/../lxml:column[@name='WCHAR36']

with

Def_List Name(#BUTLST) Fields(#BUTNR #BUNAVN #WCHAR36) Type(*WORKING) Entrys(*MAX)
Web_Map For(*BOTH) Fields(#IZBUTNR #BUTLST )

 

8 characters is the limit

I keep forgetting this, cause I do development in other languages and frameworks as well, and nothing in the LANSA editor stops me. But WAM command handlers must not have a name of more than 8 characters.

Or rather, it can and it will work, but then when you try to set it up in the VLF, you, again without warning, enter the more-than-8 character name and lo and behold, you end up with errors on your site.

Instead, a command handler named, for example, CH_FAKKOP, should be referenced in the VLF by the first 8 characters, CH_FAKKO, even though the WAM component is 9 characters.


Edit: This also applies to the WAM name in XSLT, like

<xsl:with-param name="on_change_wrname" select="'UHandleEvent'" />
<xsl:with-param name="on_change_wamname" select="'CH_FAKKO'" />

Decimal points and functions

This is one of those issues that arise from me coming from a different background than what I imagine a typical Lansa developer, indeed a typical i series developer, come from. It is a useful reminder what decimals actually mean.

For example, I have a repository field that is defined like this:

Define Field(#JSN) Type(*SIGNED) Length(4) Decimals(2)

That means, a signed decimal value with 2 digits before the decimal point and 2 digits after the decimal point. In a function, I calculate the value and exchange it back to application calling. In that application, I (unfortunately) have an override, changing the number of decimals.

Override Field(#JSN) Decimals(1)

This was probably done to format the display of the value but where I imagined the value would be passed in a lower level format and then parsed in relation to the definition, this is not what happens.

Instead, the value is still the same 4 digits, but one of those that was after the decimal point is now before the decimal point. The value has been multiplied by 10^1; a value of 0.21 is now 2.1.

Because the override only moved the decimal point.