Re: SQL UDF to call RPG without service program

Charles Wilt <[email protected]> Tue, 3 Mar 2026 08:28:39 -0700
Newsgroups gmane.comp.lang.as400.rpg
Message-ID <CAJ=Tnc5BdPdMPLn7qqKAH22rvaQq1kAjwJwKU9WWL3igbMpqNQ@mail.gmail.com>
No, CREATE FUNCTION...

Here's an quick (AI generated) example...

CREATE OR REPLACE FUNCTION MYLIB.GET_TOTAL_PGM (
    qty INT,
    unit_price DECIMAL(9, 2)
) RETURNS DECIMAL(11, 2)LANGUAGE RPGLE
PARAMETER STYLE SQLDETERMINISTICNO EXTERNAL ACTIONEXTERNAL NAME
'MYLIB/TOTALPGM' -- Points to *PGM object
PROGRAM TYPE MAIN

RPG code:

**FREE
ctl-opt dftactgrp(*no) actgrp(*caller);

dcl-pi *n;
  -- 1. Input Parameters (Matched to SQL types)
  inQty      int(10) const;
  inPrice    packed(9: 2) const;
  -- 2. Result Parameter (This is where you "return" the value)
  outTotal   packed(11: 2);
  -- 3. Input Indicators (2-byte integers)
  indQty     int(5) const;
  indPrice   int(5) const;
  -- 4. Result Indicator
  indTotal   int(5);
  -- 5. Housekeeping (Mandatory for Style SQL)
  sqlState   char(5);
  fName      varchar(139) const;
  specName   varchar(128) const;
  diagMsg    varchar(70);
end-pi;

-- Logic
sqlState = '00000';
indTotal = 0;

if (indQty < 0 or indPrice < 0);
  indTotal = -1;
else;
  outTotal = inQty * inPrice;
endif;

return;




On Tue, Mar 3, 2026 at 7:55 AM Vern Hamberg via RPG400-L <
[email protected]> wrote:

> Hi Charles
>
> In this technique, are you using CREATE PROCEDURE? I had posted that one
> could simply call a program, but it is PARAMETER STYLE GENERAL and all
> parameters are INOUT - does that line up with your knowledge?
>
> *Regards*
>
> *Vern Hamberg*
>
> IBM Champion 2025 <cid:[email protected]> CAAC
> (COMMON Americas Advisory Council) IBM Influencer 2023
>
>
> On 3/3/2026 8:45 AM, Charles Wilt wrote:
> > You can use a MAINLINE RPG program as an external scalar SQL UDF.
> > You simply need to use PARAMETER STYLE SQL. (note the 3rd line below,
> > emphasis mine)
> >
> > All applicable parameters are passed. The parameters are defined to be in
> > the following order:
> > n parameters for the input parameters that are specified for the
> function.
> > ****A parameter for the result of the function.****
> > n parameters for indicator variables for the input parameters.
> > A parameter for the indicator variable for the result.
> > A CHAR(5) output parameter for SQLSTATE. The SQLSTATE returned indicates
> > the success or failure of the function. The SQLSTATE returned can either
> be:
> > the SQLSTATE from the last SQL statement executed in the external
> program,
> > an SQLSTATE that is assigned by the external program.
> > The user may set the SQLSTATE to any valid value in the external program
> to
> > return an error or warning from the function.
> >
> >
> > A VARCHAR(517) input parameter for the fully qualified function name
> > A VARCHAR(128) input parameter for the specific name.
> > A VARCHAR(1000) output parameter for the message text.
> > When control is returned to the invoking program, the message text can be
> > found in the 6th token of the SQLERRMC field of the SQLCA. Only a portion
> > of the message text is available. For information on the layout of the
> > message data in the SQLERRMC, see the replacement data descriptions for
> > message SQL0443 in message file QSQLMSG. The complete message text can be
> > retrieved using the GET DIAGNOSTICS statement. For more information, see
> > GET DIAGNOSTICS.
> >
> >
> > Zero to three optional parameters:
> > A structure (consisting of an INTEGER followed by a CHAR(n)) input and
> > output parameter for the scratchpad, if SCRATCHPAD was specified on the
> > CREATE FUNCTION statement.
> > An INTEGER input parameter for the call type, if FINAL CALL was specified
> > on the CREATE FUNCTION statement.
> > A structure for the dbinfo structure, if DBINFO was specified on the
> CREATE
> > FUNCTION statement.
> >
> >
> > Yes, the interface is more complex, but you gain a lot of control.
> > Personally, I've gotten to the point of always using PARAMETER STYLE SQL.
> >
> > Of course, assuming an existing program called from other places, you
> could
> > add the additional parms as *OMIT and modify the code to see if the
> > additional parms where passed or not; thus allowing the program to
> > determine if it was called from RPG or SQL.  When called from SQL, you
> can
> > do the extra work to the additional parms,
> >
> > Charles
> >
> > On Mon, Mar 2, 2026 at 4:43 PM Reeve<[email protected]> wrote:
> >
> >> Rob, "regular" RPG programs (with a mainline, I guess) can't return a
> >> value.  A function implicitly returns a single value.  Service programs
> >> (ctl-opt *NOMAIN) can return a value.
> >>
> >> Two ideas:
> >> 1) Read up on parameter passing and overloading.  If the attributes of
> the
> >> caller's parameter list don't fit with the called parameter list, you
> get a
> >> Not Found; I think a returned value is not considered in signature
> >> matching.
> >> 2) Set up a dummy service program named GETUPCHARGEFUNC and see if your
> >> code works with it.  If so, your SQL is good.
> >>
> >> --reeve
> >>
> >> On Mon, Mar 2, 2026 at 12:28 PM Robert Rogerson<[email protected]>
> >> wrote:
> >>
> >>> Hi Reeve,
> >>>
> >>> I may be missing something but why not just call the RPG from the
> >>> function?  I'm not sure of the purpose of the procedure and if it's
> >> needed.
> >>> Here's an example of a function calling an RPG program.
> >>>
> >>> CREATE FUNCTION MYLIB.GETUPCHARGEFUNC (
> >>>      WHSENBR NUMERIC(3, 0) ,
> >>>      ITEMNBR NUMERIC(6, 0) )
> >>>      RETURNS NUMERIC(7, 2)
> >>>      LANGUAGE RPGLE
> >>>      SPECIFIC MYLIB.GETUPCHARGEFUNC
> >>>      NOT DETERMINISTIC
> >>>      MODIFIES SQL DATA
> >>>      CALLED ON NULL INPUT
> >>>      NOT FENCED
> >>>      EXTERNAL NAME 'MYLIB/GETUPCHRGF'
> >>>      PARAMETER STYLE SQL ;
> >>>
> >>> To call
> >>> SELECT
> >>>         ivwhid AS "Warehouse",
> >>>         ivitm# AS "Item Number",
> >>>         GETUPCHARGEFUNC(ivwhid, ivitm#) AS "Up Charge"
> >>>    FROM invmasp
> >>>   WHERE ivwhid = 90
> >>>     AND ivitm# = 5
> >>>   ORDER BY 1, 2;
> >>>
> >>> HTH,
> >>>
> >>> Rob
> >>>
> >>> On Mon, Mar 2, 2026 at 2:43 PM Reeve<[email protected]> wrote:
> >>>
> >>>> External name is FUNC00001A: shouldn't you be calling that object?
> >>>>
> >>>> On Mon, Mar 2, 2026 at 11:20 AM Eric Wesson<[email protected]>
> >>> wrote:
> >>>>> I am trying to create an SQL function that effectively calls an RPG
> >>>>> program and returns the result. I've read you can do it by creating a
> >>>>> service program and calling it but I'm trying to do it without the
> >>>> service
> >>>>> program.
> >>>>>
> >>>>> I have successfully created an sql stored procedure that calls the
> >> RPG
> >>>>> program and I've created a function that calls the stored procedure.
> >>>>>
> >>>>> When i try to use the function, I get an error saying "FUN0001 not
> >>>> found".
> >>>>> I can successfully call the function directly using "CALL
> >>>>> APPSTRPROC.FUNC0001(12345, 0)".
> >>>>> I've beat my head against the wall on this one. Any ideas?
> >>>>>
> >>>>>
> >>>>> Code that creates procedure and function
> >>>>> // Stored procedure to call rpg
> >>>>>           Exec sql
> >>>>>             Create or replace Procedure Appstrproc.FUNC0001(
> >>>>>                                           in SystemSku dec(15),
> >>>>>                                           out Retail dec(9,2))
> >>>>>             Language RPGLE
> >>>>>             Called on null input
> >>>>>             Not deterministic
> >>>>>             No external action
> >>>>>             Reads sql data
> >>>>>             External name FUNC00001A
> >>>>>             Parameter style general;
> >>>>>
> >>>>>           // Function to call stored procedure
> >>>>>           Exec Sql
> >>>>>             Create or Replace Function
> >>>>> Appstrproc.f_SkuGetCurrentRetail(SystemSku dec(15))
> >>>>>             Returns Decimal(9,2)
> >>>>>             Language SQL
> >>>>>             Return Appstrproc.FUNC0001(SystemSku, 0);
> >>>>>
> >>>>> Thanks,
> >>>>> Eric
> >>>>> --
> >>>>> This is the RPG programming on IBM i (RPG400-L) mailing list
> >>>>> To post a message email:[email protected]
> >>>>> To subscribe, unsubscribe, or change list options,
> >>>>> visit:https://lists.midrange.com/mailman/listinfo/rpg400-l
> >>>>> or email:[email protected]
> >>>>> Before posting, please take a moment to review the archives
> >>>>> athttps://archive.midrange.com/rpg400-l.
> >>>>>
> >>>>> Please [email protected] for any subscription
> >>> related
> >>>>> questions.
> >>>>>
> >>>>>
> >>>> --
> >>>> This is the RPG programming on IBM i (RPG400-L) mailing list
> >>>> To post a message email:[email protected]
> >>>> To subscribe, unsubscribe, or change list options,
> >>>> visit:https://lists.midrange.com/mailman/listinfo/rpg400-l
> >>>> or email:[email protected]
> >>>> Before posting, please take a moment to review the archives
> >>>> athttps://archive.midrange.com/rpg400-l.
> >>>>
> >>>> Please [email protected] for any subscription
> >> related
> >>>> questions.
> >>>>
> >>>>
> >>> --
> >>> This is the RPG programming on IBM i (RPG400-L) mailing list
> >>> To post a message email:[email protected]
> >>> To subscribe, unsubscribe, or change list options,
> >>> visit:https://lists.midrange.com/mailman/listinfo/rpg400-l
> >>> or email:[email protected]
> >>> Before posting, please take a moment to review the archives
> >>> athttps://archive.midrange.com/rpg400-l.
> >>>
> >>> Please [email protected] for any subscription
> related
> >>> questions.
> >>>
> >>>
> >> --
> >> This is the RPG programming on IBM i (RPG400-L) mailing list
> >> To post a message email:[email protected]
> >> To subscribe, unsubscribe, or change list options,
> >> visit:https://lists.midrange.com/mailman/listinfo/rpg400-l
> >> or email:[email protected]
> >> Before posting, please take a moment to review the archives
> >> athttps://archive.midrange.com/rpg400-l.
> >>
> >> Please [email protected] for any subscription related
> >> questions.
> >>
> >>
> --
> This is the RPG programming on IBM i (RPG400-L) mailing list
> To post a message email: [email protected]
> To subscribe, unsubscribe, or change list options,
> visit: https://lists.midrange.com/mailman/listinfo/rpg400-l
> or email: [email protected]
> Before posting, please take a moment to review the archives
> at https://archive.midrange.com/rpg400-l.
>
> Please contact [email protected] for any subscription related
> questions.
>
>
-- 
This is the RPG programming on IBM i (RPG400-L) mailing list
To post a message email: [email protected]
To subscribe, unsubscribe, or change list options,
visit: https://lists.midrange.com/mailman/listinfo/rpg400-l
or email: [email protected]
Before posting, please take a moment to review the archives
at https://archive.midrange.com/rpg400-l.

Please contact [email protected] for any subscription related questions.