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.