× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



Hi Kurt,

I have a CL that submits a CL, and it appears two of the parameters
are sharing a location in memory. Is there a limitation on the size
of a field that can be submitted to a CL?

They aren't 'sharing a location'. The caller (The OS/400 QCMD program in this case) is defining the parameter to be 32 bytes long, and you are trying to read 45 bytes from it. So your program isn't stopping after 32 bytes, it's reading an additional 13 byes that doesn't belong to that parameter. You're reading whatever happens to be adjacent in memory.

In this case, that just happens to be the spot in memory where the other parameter is stored. There's no guarantee that this will always be the case.

I tried searching online but wasn't finding anything.

That surprises me, as this is one of the most frequently discussed issues in the world of IBM i programming.

I can get around this situation by putting the big parameter last,
but I wanted to understand why this is happening.

Noooooooo! Don't do that.... You aren't solving the problem if you do that. You are still reading more than the 32 bytes that are allocated to the parameter, you just (by luck) happen to be getting space that's not used for anything, so it's empty. This isn't solving your problem because there's no guarantee that it'll never be used for anything.

The solution isn't to rearrange the parameters, the solution is to make the parameter definitions match!

First of all, how do parameters work?

They work by sharing memory. Naturally a program that has variables has a space in memory where those variables are stored. When it calls another program and passes a parameter, it "shares" that variable. It says to that other program "hey other program... you can read my variable from memory location x'123456' -- whatever the memory location happens to be -- and the new program simply uses that same spot in the computer's memory for it's parameter.

For an RPG programmer, the easiest way to visualize this might be a data structure. Think of your computer's memory ("main storage") as one big huge data structure that's gigabytes long. All programs are sharing the data structure.

I realize you aren't deliberately coding it this way, but THIS is what you're ending up with:

PGM
DCL VAR(&VAR1) TYPE(*CHAR) LEN(32)
DCL VAR(&VAR2) TYPE(*CHAR) LEN(1)

CALL PGM2 PARM(&VAR1 &VAR2)
ENDPGM

PGM PARM(&PARM1 &PARM2)
DCL VAR(&VAR1) TYPE(*CHAR) LEN(45)
DCL VAR(&VAR2) TYPE(*CHAR) LEN(1)

... code here...
ENDPGM

Looking at your computer's main storage as one big data structure would give you something like this:

D Main_Storage DS
.. data from other programs here...
D Pgm1_var1 1000 1032a
D Pgm1_var2 1033 1034a
.. more data from more programs here...

When PGM1 calls PGM2, it says to PGM2 "Hey, my first parameter is in location 1000. My second parameter is in location 1033". So pgm2 uses that location for it's input parameters.

D Main_Storage DS
.. data from other programs here...

D Pgm1_var1 1000 1032a
D Pgm1_var2 1033 1034a

.. more data from more programs here...

D Pgm2_parm1 1000 1045a
D Pgm2_parm2 1033 1034a

.. more data from more programs here...

Now maybe you can see the problem. The only thing passed is the location of the variable, not the name, size or data type. just the location, the "memory address" (which corresponds to the DS start position in my analogy).

PGM1's first parameter was only 32 bytes long. But PGM2 defined it's first parameter as 45 bytes long. Since PGM2 shares teh same location (position 1000 in this example), it'll have the data from PGM1's variable -- but it doesn't stop there. It keeps going beyond position 1032.. all the way out to 1045. Since the second parameter is in 1033, it happens to include that data as well. It also includes more stuff in positions 1034-1045 that may be unused by the OS right now, but may end up getting used later, or in the future might be in use by another variable (most likely if PGM1 is enhanced), etc, etc. It's never safe to use a mismatched parameter in this way.


Now the obvious question is: WHY does it end up this way? Your program isn't actually coding the first parameter as 32 *char, so why is this happening?

The answer: Because that's the way the QCMD program interprets a command string. You can't simply share memory when you submit a program... it's too dangerous. The calling program might release the memory before the called job finishes. Or might reuse that memory for something else. It'd be a mess.

So SBMJOB doesn't work that way. Instead, it takes your parameters and builds a command string. It passes that command string to the new job, and the new job interprets the command string just like it would interpret it if you had typed it at the command-line.

So if your PGM1 looks like this:

PGM
DCL VAR(&VAR1) TYPE(*CHAR) LEN(32)
DCL VAR(&VAR2) TYPE(*CHAR) LEN(1)

SBMJOB CMD(CALL PGM2 PARM(&VAR1 &VAR2))
ENDPGM

The system builds a command string consisting of
CALL PGM2 PARM('your data here' 'X')

One major caveat is that it trims blanks off of the parameters when it does this.

In the newly created job, it interprets that command string. But it no longer knows how the variables were defined in the calling program. So it uses the same rules that it would use from the command-line. If the parameter is character and less than 32 bytes, it gets left-aligned in a 32A field, with the remaining bytes set to blank. If it's greater than 32A, then the system creates it with the exact length of the parameter data. (Which is really only useful if the length is provided somewhere else...) If the parameter appears to be numeric, the command line makes it a 15,5 packed. This is one of the general caveats of the CALL command...

The solution is to force the command line to provide a full 45 bytes for the first parameter. The easiest/best way to do that is to eliminate the CALL command (since you can't control it's variable sizes), and instead create your own command (*CMD object):

source:

CMD PROMPT('Kurt''s Nifty Command')

PARM KWD(PARM1) TYPE(*CHAR) LEN(45)
PARM KWD(PARM2) TYPE(*CHAR) LEN(1)


build it with:

CRTCMD CMD(RUNPGM2) PGM(PGM2)

Then change PGM1 to look like this:

PGM
DCL VAR(&VAR1) TYPE(*CHAR) LEN(32)
DCL VAR(&VAR2) TYPE(*CHAR) LEN(1)

SBMJOB CMD(RUNPGM2 PARM1(&VAR1) PARM2(&VAR2))
ENDPGM

Now the system knows the first parameter needs to be 45 long (instead of 32) and will set it appropriately.

As an Amazon Associate we earn from qualifying purchases.

This thread ...

Follow-Ups:
Replies:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.