How to Call a Pkg/Procedure Executing an API From a Pkg/Procedure. The API name needs to be Dynamic and Has In and Out Parms - stored-procedures

We use APIs, baninst1.PP_DEDUCTION.p_update and baninst1.PP_DEDUCTION.p_create, to maintain our payroll tables of benefit/deduction data. Numerous packages utilize the APIs. We would like to create a package containing the API call that all the existing packages can use and remove the code that is repeated in each package. I tried EXECUTE IMMEDIATE for the purpose of having a dynamic API name. However, I have not been able to get the syntax correct. I’m hoping you will help me.
create or replace PACKAGE BODY "ORBIT"."MM_BENEFITS_COMMON" AS
PROCEDURE PAY_P_EMPLOYEE_BENEFIT_ACTION(pi_benefit_action IN VARCHAR2,
                                                                               pi_pidm                   IN pdrbded.pdrbded_pidm%TYPE,
                                                                               pi_status                  IN pdrdedn.pdrdedn_status%TYPE,
                                                                               pi_bdca_code          IN pdrbded.pdrbded_bdca_code%TYPE,
                                                                               pi_effective_date     IN pdrdedn.pdrdedn_effective_date%TYPE DEFAULT NULL,                                                                               pi_user_id                IN pdrdedn.pdrdedn_user_id%TYPE DEFAULT NULL,                                                                               pi_data_origin          IN pdrdedn.pdrdedn_data_origin%TYPE DEFAULT NULL,
                                                                               po_base_rowid_out  OUT gb_common.internal_record_id_type,
                                                                               po_detail_rowid_out OUT gb_common.internal_record_id_type,
                                                                               pi_amount1              IN pdrdedn.pdrdedn_amount1%TYPE DEFAULT NULL,
                                                                               pi_opt_code1            IN pdrdedn.pdrdedn_opt_code1%TYPE DEFAULT NULL) IS
BEGIN
--Call the API for p_create or p_update.
baninst1.PP_DEDUCTION.pi_benefit_action(p_pidm                  => pi_pidm,
                                                                       p_status                 => pi_status,
                                                                       p_bdca_code          => pi_bdca_code,
                                                                       p_effective_date     => CASE
                                                                                                                 WHEN pi_benefit_action 'p_create' THEN
                                                                                                                       TRUNC(pi_begin_date)
                                                                                                                 ELSE
                                                                                                                       TRUNC(pi_effective_date)
                                                                                                             END,
                                                                      p_user_id                =>   pi_user_id,
                                                                      p_data_origin          =>   pi_data_origin,
                                                                      p_base_rowid_out   =>   po_base_rowid_out,
                                                                      p_detail_rowid_out  =>  po_detail_rowid_out,                                                                      p_amount1              =>  pi_amount1,
                                                                      p_opt_code1            => CASE
                                                                                                                 WHEN LENGTH(pi_opt_code1) = 1 THEN
                                                                                                                        '0' || pi_opt_code1
                                                                                                                 ELSE pi_opt_code1
                                                                                                            END);
END PAY_P_EMPLOYEE_BENEFIT_ACTION;
END MM_BENEFITS_COMMON;
create or replace PACKAGE BODY "ORBIT"."MM_BENEFIT_TEST" AS
PROCEDURE PAY_P_MM_BENEFIT_TEST IS
lv_base_rowid_out    gb_common.internal_record_id_type;
lv_detail_rowid_out   gb_common.internal_record_id_type;
BEGIN
--Pass data to the common benefits package for the api call
MM_BENEFITS_COMMON.PAY_P_EMPLOYEE_BENEFIT_ACTION('p_update', 9999999, 'A', 'VI1', '01-JAN-2022', 'MM_Test',     'MM_TEST', lv_base_rowid_out, lv_detail_rowid_out, 25.82, NULL);
END PAY_P_MM_BENEFIT_TEST;
END MM_BENEFIT_TEST;

I'm not sure what's bothering you, actually. You did post some code, but - I don't know what it represents.
Let's see what you said:
"We use APIs, baninst1.PP_DEDUCTION.p_update and baninst1.PP_DEDUCTION.p_create, to maintain our payroll tables of benefit/deduction data."
OK
"Numerous packages utilize the APIs."
it means that there are many packages and they call those p_update and p_create procedures; that's also OK
"We would like to create a package containing the API call that all the existing packages can use and remove the code that is repeated in each package."
that would be a new package; you'd cut that piece of code from all of your packages and paste it into a new one.
OK, makes sense. Instead of all that code (in every package), you'd put call to newly created procedures (that reside in a newly created package)
"I tried EXECUTE IMMEDIATE for the purpose of having a dynamic API name. However, I have not been able to get the syntax correct."
why dynamic SQL? There's nothing dynamic here. Instead of dozens of lines of code you currently have (that do something), you'd put one line - the one that calls that newly created procedure (and pass parameters)
From my point of view, there's nothing unusual in what you want to do and I can't imagine what problems you could have in doing it; it's pretty much straightforward.

Related

UI5-Application: Call to functionimport works ONLY in WebIDE but fails everywhere else

We are developing a custom UI5 application.
It is developed in the WebIDE, and therefore deployed as a BSP.
When we use the underlying model for calls ( currently 3, no CRUD ), we chose the path of using ONLY functionimports to communicate with the backend.
All of them work with the POST method.
And all of them work ONLY inside the WebIDE.
Once, I access the BSP URL otherwise, we get HTTP 500 error with "error while requesting the ressource.
We already created links, to enable special portfowarding, no result.
Let's stick to my URL from the BSP first.
I paste it into my 3 browsers: 500.
We also created a special non dialogue-user with proper roles and permissions, and in the SICF tree we assigned it .
Again, when calling from inside the WebIDE, the functionimport-calls work, otherwise not.
Error-Logs are empty.
Dumps do not happen.
ST05 trace shows where 500 is passed, deeply inside the HTTP framework, yet no chance to spot the code location, neither a breaktpoint.
In SICF logon-settings we have:
Types all, also flagged "all", SAML: inherited from parent node, sec-sessions Not limited, fix user and pw, sec: Standard, auth:Standard Sap user.
The gui-options contain ONLY one flag: ~CHECK_CSRF_TOKEN 0.
In my client I use :
Where the model is initialized as :
function initModelV2() {
var sUrl = "/sap/opu/odata/sap/Z_this_is_a_company_secret_service/";
var oModel = new sap.ui.model.odata.v2.ODataModel(sUrl);
sap.ui.getCore().setModel(oModel);
}
What else can I do to get "at least closer" to the reason, WHY ?
I could solve it, and believe it or not, sometimes simple logic helps.
I debugged the backend of CL_HTTP_RESPONSE, and once I saw, GET_STATUS, I thought to look for SET_STATUS.
There it was:
this.rModel.setHeaders( {"X-Requested-With" : "X" } );
Was missing.
Though I set it in the manifest of my model, it was not passed.
Once set in the code, it worked.
I wonder, why it is not accepted in manifest.
I have an assumption.
1st: I have this in my manifest ( yellow arrow shows, where i HAD it set up before):
But I also have an instantiation in my code, in servicebindings.js with this code
Can it be, that, in the end, I have accidently created 2 models ?

DB2-12 (Z/OS) - Create Alias for Stored Procedure

it's possible to define an alias for a stored procedure (sql-native)?
In the documentation, reference is made only to: SEQUENCE and TABLES
1) CREATE PROCEDURE OWXXCOLL.STORED1()
2) CREATE ALIAS DB2C.STORED1 FOR OWXXCOLL.STORED1;
3) CALL DB2C.STORED1();
EDIT 2021-05-14
The original question arises for the following problem (I was hoping to get away with using aliases)
Intro
I have defined a native SP
The OWXXCOLL schema is the same one I also use for tables/index...
(I noticed that the tables also have different aliases)
CREATE PROCEDURE OWXXCOLL.STORED1(...)
LANGUAGE SQL
ISOLATION LEVEL CS
WLM ENVIRONMENT FOR DEBUG MODE WLMENV1
ALLOW DEBUG MODE
BEGIN
...
END#
I also modified the cobol program (name:PGMSTO1) to call the Stored with the CALL statement (without qualifier)
EXEC SQL
CALL STORED1 (...)
END-EXEC.
The problem
The various table accesses (SELECT) work correctly BUT When I run the PGMSTO1 the call to the Stored ends with sqlcode -440
NO AUTHORIZED PROCEDURE BY THE NAME STORED1 HAVING COMPATIBLE ARGUMENTS WAS FOUND<
The error comes from the fact that it is not using the owner OWXXCOLL but DB2C (DB2C is user who scheduled the jcl/batch)
If I enter the qualifier (OWXXCOLL) the call it's OK.
I don't understand what to check and what configurations are missing.
Thanks
The cobol program (PGMSTO1) that calls the stored procedure has the following BIND parameters:
COLLID NAME OWNER CREATOR QUALIFIER DYNAMICRULES PATHSCHEMAS
OWXXCOLL PGMSTO1 DB2C DB2C FPXX B "DB2C"
"DB2C" path is used to resolve unqualified stored procedure
I will need to modify the bind parameter "PATH".
I will try to ask to add my schema as well (OWXXCOLL)
PATH("OWXXCOLL","DB2C")

Why is COMMON_APPDATA returned as a null string on Windows XP

One of my users at a large university (with, I imagine, the aggressive security settings that university IT departments general have on their computers) is getting an empty string returned by Windows XP for CSIDL_COMMON_APPDATA or CSIDL_PERSONAL. (I'm not sure which of these is returning the empty string, because I haven't yet examined his computer to see how he's installed the software, but I'm pretty sure it's the COMMON_APPDATA...)
Has anyone encountered this or have suggestions on how to deal with this?
Here's the Delphi code I'm using to retrieve the value:
Function GetSpecialFolder( FolderID: Integer):String;
var
PIDL: PItemIDList;
Path: array[0..MAX_PATH] of Char;
begin
SHGetSpecialFolderLocation(Application.Handle, FolderID, PIDL);
SHGetPathFromIDList(PIDL, Path);
Result := Path;
end; { GetSpecialFolder }
ShowMessage(GetSpecialFolder(CSIDL_COMMON_APPDATA)); <--- This is an empty string
Edit:
Figuring out this API made me feel like I was chasing my tail - I went in circles trying to find the right call. This method and others similar to it are said to be deprecated by Microsoft (as well as by a earlier poster to this question (#TLama?) who subsequently deleted the post.) But, it seems like most of us, including me, regularly and safely ignore that status.
In my searches, I found a good answer here on SO from some time ago, including sample code for the non-deprecated way of doing this: what causes this error 'Unable to write to application file.ini'.
If you want to find out why an API call is failing you need to check the return values. That's what is missing in this code.
You need to treat each function on its own merits. Read the documentation on MSDN. In the case of SHGetSpecialFolderLocation, the return value is an HRESULT. For SHGetPathFromIDList you get back a BOOL. If that is FALSE then the call failed.
The likely culprit here is SHGetSpecialFolderLocation, the code that receives the CSIDL, but you must check for errors whenever you call Windows API functions.
Taking a look at the documentation for CSIDL we see this:
CSIDL_COMMON_APPDATA
Version 5.0. The file system directory that contains application data for all users. A typical path is C:\Documents and Settings\All
Users\Application Data. This folder is used for application data that
is not user specific. For example, an application can store a
spell-check dictionary, a database of clip art, or a log file in the
CSIDL_COMMON_APPDATA folder. This information will not roam and is
available to anyone using the computer.
If the machine has a shell version lower than 5.0, then this CSIDL value is not supported. That's the only documented failure mode for this CSIDL value. I don't think that applies to your situation, so you'll just have to see what the HRESULT status code has to say.

JEDI JVCL TJvProgramVersionCheck How to use HTTP

I'm wondering if someone has an example on how can be used the TJvProgramVersionCheck component performing the check via HTTP.
The example in the JVCL examples dir doesn't show how to use HTTP
thank you
The demo included in your $(JVCL)\Examples\JvProgramVersionCheck folder seems to be able to do so. Edit the properties of the JVProgramVersionHTTPLocation, and add the URL to it's VersionInfoLocation list (a TStrings). You can also set up any username, password, proxy, and port settings if needed.
You also need to add an OnLoadFileFromRemote event handler. I don't see anything in the demo that addresses that requirement, but the source code says:
{ Simple HTTP location class with no http logic.
The logic must be implemented manually in the OnLoadFileFromRemote event }
It appears from the parameters that event receives that you do your checking there:
function TJvProgramVersionFTPLocation.LoadFileFromRemoteInt(
const ARemotePath, ARemoteFileName, ALocalPath, ALocalFileName: string;
ABaseThread: TJvBaseThread): string;
So you'll need to add an event handler for this event, and then change the TJVProgramVersionCheck.LocationType property to pvltHTTP and run the demo. After testing, it seems you're provided the server and filename for the remote version, and a local path and temp filename for the file you download. The event handler's Result should be the full path and filename of the newly downloaded file. Your event handler should take care of the actual retrieval of the file.
There are a couple of additional types defined in JvProgramVersionCheck.pas, (TJvProgramVersionHTTPLocationICS and TJvProgramVersionHTTPLocationIndy, both protected by compiler defines so they don't exist in the default compilation. However, setting the ICS related define resulted in lots of compilation errors (it apparently was written against an old version of ICS), and setting the Indy define (and then setting it again to use Indy10 instead) allowed it to compile but didn't change any of the behavior. I'm going to look more into this later today.
Also, make sure that the VersionInfoLocation entry is only the URL (without the filename); the filename itself goes in the VersionInfoFileName property. If you put it in the URL, it gets repeated (as in http://localhost/Remote/ProjectVersions_http.iniProjectVersions_http.ini, and will fail anyway. (I found this while tracing through the debugger trying to solve the issue.)
Finally...
The solution is slightly (but not drastically) complicated. Here's what I did:
Copy JvProgramVersionCheck.pas to the demo folder. (It needs to be recompiled because of the next step.)
Go to Project->Options->Directories and Conditionals, and add the following line to the DEFINES entry:
USE_3RDPARTY_INDY10;USE_THIRDPARTY_INDY;
Delete the JvProgramVersionHTTPLocation component from the demo form.
Add a new private section to the form declaration:
private
HTTPLocation: TJvProgramVersionHTTPLocationIndy;
In the FormCreate event, add the following code:
procedure TForm1.FormCreate(Sender: TObject);
const
RemoteFileURL = 'http://localhost/';
RemoteFileName = 'ProjectVersions_http.ini';
begin
HTTPLocation := TJvProgramVersionHTTPLocationIndy.Create(Self); // Self means we don't free
HTTPLocation.VersionInfoLocationPathList.Add(RemoteFileURL);
HTTPLocation.VersionInfoFileName := RemoteFileName;
ProgramVersionCheck.LocationHTTP := HTTPLocation;
ProgramVersionCheck.LocationType := pvltHTTP;
VersionCheck; // This line is already there
end;
In the ProgramVersionCheck component properties, expand the VersionInfoFileOptions property, and change the FileFormat from hffXML to hffIni.
Delete or rename the versioninfolocal.ini from the demo's folder. (If you've run the app once, it stores the http location info, and the changes above are overwritten. This took a while to track down.)
Make sure your local http server is running, and the ProjectVersions_http.ini file is in the web root folder. You should then be able to run the demo. Once the form appears, click on the Edit History button to see the information retrieved from the remote version info file. You'll also have a new copy of the versioninfolocal.ini that has the saved configuration info you entered above.

Windows Shell and Citrix

I have this line of code in my Delphi app:
sh := CoShellWindows.Create;
When run through a Citrix session, this raises an exception "Not enough storage is available to complete this operation."
Can someone confirm my suspicion that I can't access this through Citrix? I'm running in Seamless mode if that makes any difference. Maybe there's something I need to change on the published icon to make it work?
I am guessing that there is no "Shell" in Citrix to create.
Thanks
EDIT
The CoShellWindows is simply a class which creates an object which implements the IShellWindows interface. This interface is then used to iterate through it's items looking for an instance of Internet Explorer (or more specifically, an item which implements the IWebBrowser2 interface).
There are a few other use case scenarios using the CoShellWindows, but all ultimately are used to interact with the IWebBrowser2 interface (Internet Explorer 8). My requirement is to obtain this IWebBrowser2 object.
The call, behind the scenes is calling the Windows API CoCreateInstance with the following parameters:
rclsid = {9BA05972-F6A8-11CF-A442-00A0C90A8F39} (CLSID of
IShellWindows)
pUnkOuter = null (nil)
dwClsContext = CLSCTX_ALL (I've tried various combinations of these
flags)
riid = {85CB6900-4D95-11CF-960C-0080C7F4EE85} (IID of IShellWindows)
ppv = a variable declared as type IShellWindows
eg:CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_ALL, IID_IShellWindows, sh)
Your exception "Not enough storage is available to complete this operation." should really read "Shell does not exist so no instance can be created"
Basically you are correct in your assumption that there is no shell to create in Citrix.
What are you using the shell for? as if you provide more information we may well be able to offer a full work around.

Resources