× 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 Charles,

Although using *OMIT is nicely self-documenting, I don't like using *OMIT because it results in a lot of code like this:

If %nullind(FILEDATE);
MyCoolProcedure(somedata:*omit);
else;
MyCoolProcedure(somedata:myDate);
endif;

I find that to be cumbersome, because it's 5 lines vs 1, plus you end up calling the procedure from two places. Granted, it's hard to see why that's cumbersome with such a simple example, but imagine if you had 3 different nullable parameters:

select;
when not %nullind(PARM1)
and not %nullind(PARM2);
MyCoolProcedure(somedata:*omit:*omit:*omit);
when not %nullind(PARM1)
and %nullind(PARM2);
MyCoolProcedure(somedata:*omit:PARM2);
when %nullind(PARM1)
and not %nullind(PARM2);
MyCoolProcedure(somedata:PARM1:*omit);
other;
MyCoolProcedure(somedata:PARM1:PARM2);
endsl;

That's with only 2 nullable parameters. If you had 4 parameters, you'd need 16 different calls to your procedure. It gets ugly really fast.

The other alternative with the *OMIT scheme is to use based() variables and set their basing pointers to *NULL. That's a little nicer, but it's still very cumbersome.

D bPARM1 s like(PARM1) based(p_bPARM1)
D bPARM2 s like(PARM2) based(p_bPARM2)

if %nullind(PARM1);
p_bPARM1 = *null;
else;
p_bPARM1 = %addr(PARM1);
endif;

if %nullind(PARM2);
p_bPARM2 = *null;
else;
p_bPARM2 = %addr(PARM2);
endif;

MyCoolProcedure(somedata: bPARM1: bPARM2);

All that every time I want to call my procedure? Yuck.

Your second option of building the DS is also too cumbersome for me. (Again, this is just my opinion)

d parm1 ds likeds(NullableDate_t) inz(*LIKEDS)
d parm2 ds likeds(NullableWhatever_t) inz(*LIKEDS)

parm1.value = FILEDATE;
parm1.isNull = %nullind(FILEDATE);

parm2.value = whatever;
parm2.isNull = %nullind(whatever);

MyCoolProcedure(somedata: parm1: parm2);

For sure, it's not nearly as ugly as the *OMIT scheme, but it's still too ugly... and with this scheme, if the parameter can be used for output, you have to move the data back afterwards...

Instead, I suggest that you use options(*nullind) if you know the field will always come from a database file:

D MyCoolProc PR
D somedata 123a const
D parm1 d options(*nullind) const
D parm2 9p 2 options(*nullind)

MyCoolProc(somedata:FILEDATE:FILENUM);

In a previous message in this thread, I described why that's not always a good idea (since not all data always comes from a database directly). The other approach I recommend is the one that someoen else already suggested, pass a separate parameter with the null indicator:

That way, if you want to use a non-nullable field, or pass a literal, or field defined in D-specs, you can do:

MyCoolProc( somedata
: FILEDATE
: %nullind(FILEDATE)
: FILENUM
: %nullind(FILENUM));

Not as nice as options(*nullind), but when you have a parameter that you don't want to supply from a database, you can just pass a literal for the null fields

MyCoolProc(somedata:parm1:*OFF:parm2:*OFF);

Plus, we should be trying to move our file access to SQL, and in that environment, the indicator is already specified as a separate parameter. That's relatively easy to adapt to the separate parameter scheme that I'm suggesting:

D SQLNULL C -1

exec sql
select FILEDATE, FILENUM
into :FILEDATE :n_FILEDATE,
:FILENUM :n_FILENUM
from MYFILE
where WHATEVER;

MyCoolProc( somedata
: FILEDATE
: n_FILEDATE = SQLNULL
: FILENUM
: n_FILENUM = SQLNULL);

That's just my two cents.


Charles Wilt wrote:
Doug,

You could always define the parameter with *OMIT and/or *NOPASS. But
then your calling routine would have to make a check and omit the
parm.

Another option I've use to work around the fact that RPG doesn't have
full NULL support is to use data structures with a value field and a
null indicator field instead of variables made up of simple types.

d t_NullableDate ds TEMPLATE
d value d inz(*LOVAL)
d isNull n inz(*ON)

d myDate ds likeds(t_NullableDate) inz(*LIKEDS)

/free
chain key myFile;
myDate.value = FILEDATE;
myDate.isNull = %nullind(FILEDATE);

MyCoolProcedure(somedata:myDate);
/end-free

It works pretty well if you have the file i/o encapsulated, as you
only need to worry about converting between a simple date and a
"nullable date" and back once.

I've done the same thing with numerics and strings. Though with a
string you can simply use VARYING such that an empty string is NULL.

HTH,
Charles


As an Amazon Associate we earn from qualifying purchases.

This thread ...

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.