How to call external stored procedure from SQL stored procedure and handle commitment control - stored-procedures

I am trying to call a external stored procedure from Sql stored procedure by passing two parameters. one of the parameters is expected to return back with a string value, which when arrives I need to stop the data to be committed in any file.
To explain the situation - SP1 (SQL stored procedure) will call SP2 (External stored procedure), which will call RPGLE program PGM1, which will call another RPGLE program PGM2.
Now I am tasked to handle commitment control of File1 and File 2 used in PGM2 from SP1. If at any point File1 is updated and File2 gives an error while updating any record, data from File 1 should also be rolled back. but this rollback should happen in SP1.
So far I have tried to split this issue in two parts-
PARTA - How to Call External stored procedure from SQL stored procedure.
PARTB - How to handle commitment in SQL stored procedure in essence, if PGM2 gives back error data should be rolled back.
Below is the piece of code so far I have tried. But have no luck.
CREATE OR REPLACE PROCEDURE MYLIB.SP1 (
IN PRINPUT CHAR(1200) ,
INOUT PRERR CHAR(50) )
SPECIFIC MYLIB.SP1
BEGIN
DECLARE SQLSTATE CHAR(5) DEFAULT ' ';
DECLARE SQLCODE INTEGER DEFAULT 0;
CALL MYLIB.SP2(PRINPUT, PRERR);
IF SQLCODE = 0 THEN
COMMIT;
ENDIF;
END
Any suggestion/Guidance is appreciated.

Try this my friend:
On SP1
BEGIN
DECLARE SQLSTATE CHAR(5) DEFAULT ' ';
DECLARE SQLCODE INTEGER DEFAULT 0;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
CALL MYLIB.SP2(PRINPUT, PRERR);
IF SQLCODE = 0 THEN
COMMIT;
ELSE
ROLLBACK;
ENDIF;
END
Answers:
PARTA: If the Ext Stored Proc exists, the way you're calling it, it's correct.
PARTB: The set transaction scopes all the rows changed from the moment is issued, to the execution of commit or rollback. Remember this, every SQL Stored proc runs on *caller actgrp, so, you need to check if your RPG program runs on *caller too.
Finally, last time I tested, dinos still walked the earth, the commit on SQL Stored Proc scoped the changes made with a RPG program called within, but the RPG STRCMTCTL doesn't get the changes made on SQL Stored Proc called within the RPG.
Have fun!
statements-set-transaction
control-example-using-transaction-logging-file-start-application
definition-example-jobs-commitment-definitions

Thank you #Jairo, I got it working.
Your solution was correct and it worked, only challenge was the SP2 didn't have any SQL statements which was causing issue, I converted the statements in SP2 to SQL statements and it worked completely fine.

Related

Use of variable SET statement in stored procedures compiles but fires exception at runtime

In a Snowflake SQL-stored procedure, I would like to SET value of a variable like the following:
DROP PROCEDURE IF EXISTS MY_DB.MY_SCHEMA.MY_SP_SQL();
CREATE PROCEDURE MY_DB.MY_SCHEMA.MY_SP_SQL()
RETURNS STRING NOT NULL
LANGUAGE SQL
AS
DECLARE
retValue VARCHAR;
BEGIN
SET retVal = '';
[...]
Everything rocks at compile time but fails at runtime with the following exception
Uncaught exception of type 'STATEMENT_ERROR' on line x at position y :
Stored procedure execution error: Unsupported statement type 'SET'.
despite documentation says this to be possible 🤨
Can someone gently explain to the noob of me? 😁
Thanks,
Within a SQL stored procedure use LET instead of SET. The syntax for stored procedures (also known as Snowflake Scripting) is different from interactive SQL. The valid commands in SQL scripting are described in the Snowflake Scripting Reference

Snowflake procedure is running as caller but not as owner even though both are same

The definition of the procedure is as follows
CREATE OR REPLACE PROCEDURE "EMPLOYEE_TREND_TMP"()
RETURNS VARCHAR(16777216)
LANGUAGE JAVASCRIPT
EXECUTE AS OWNER
AS '
var rs = snowflake.execute( { sqlText:
SELECT count(*) FROM "DATA_MART"."EMPLOYEE"."CCH_EMPLOYEE_COMP" ;
} );
';
The owner of the procedure is HR_ROLE. When I specify "execute as caller" and call the procedure using HR_ROLE, it works fine. But "execute as owner" throws an error:
"Execution error in store procedure EMPLOYEE_TREND_TMP: Stored procedure execution error: Requested information on the current user is not accessible in stored procedure. At Snowflake.execute, line 4 position 21"
This is strange because both the owner and caller of the procedure is HR_ROLE itself.
The query inside the procedure "SELECT count(*) FROM "DATA_MART"."EMPLOYEE"."CCH_EMPLOYEE_COMP" ;" is also running fine using the HR_ROLE.
I want to execute the procedure as owner but I am confused as to why it's throwing an error, when both the caller and the owner are the same exact role (HR_ROLE). I have checked all the privileges and access to objects, everything seems to be in place.
As I see, this error occurs usually happens when accessing information_schema or session parameters. Are you sure that the SP contains only 1 line, and it's just calling this statement? Could there be other statements to access session variables or information schema?
Have you checked the limitations of the Owner’s Rights Stored Procedures?
https://docs.snowflake.com/en/sql-reference/stored-procedures-rights.html#owner-s-rights-stored-procedures

DB2 SQL procedure - Calling initiate procedure before declaration

I am making an sql procedure (in lib EXTLIB) that will be called from an external system using JDBC. We have a user, EXTUSER, that is used for running all requests coming from there. The problem is that this user can only have a single starting library, which in our case is EXTLIB (if anyone knows how to add more, please do tell me and become a hero in my company). We have a procedure initiate that initiates the environment (i.e. adds all necessary libs to LIBL). This needs to be called at the start of all procedures in EXTLIB.
My procedure needs to fetch data from a view in our internal lib: INTERLIB. The problem is that we are using ARCAD for version/release/everything management, and ARCAD doesn't like qualifiers, so it automatically removes them, meaning that the declaration at the start can't find the view in INTERLIB, and thus it stops before reaching the initate call.
I need a way to run the call before the declaration, while retaining the functionality. I'm also open to any other alternative solutions. The only one I can think of is instead coding it in RPG, but we have a lot of simple procedures for which that would just be a waste of time. manually creating the procedure in STRSQL is not an option, because when ARCAD transfers a version to production it will recompile everything, thus removing any manual qualifiers we have put there.
Here's the code:
CREATE PROCEDURE MyProcedure ()
LANGUAGE SQL
SPECIFIC MYFILE
CALLED ON NULL INPUT
DYNAMIC RESULT SETS 1
BEGIN
declare c1 cursor with return to client for
select
id,
required
from INTERLIB.cus_CustomerPurpose_v3_0
call INITIATE();
open c1;
call DEINITIATE();
END;
I think you have two options:
1) To create an internal block in the stored procedure,
CREATE PROCEDURE MyProcedure ()
LANGUAGE SQL
SPECIFIC MYFILE
CALLED ON NULL INPUT
DYNAMIC RESULT SETS 1
BEGIN
call INITIATE();
BEGIN
declare c1 cursor with return to client for
select
id,
required
from INTERLIB.cus_CustomerPurpose_v3_0;
open c1;
END;
call DEINITIATE();
END #
2) To call another stored procedure
CREATE PROCEDURE MyProcedure ()
LANGUAGE SQL
SPECIFIC MYFILE
CALLED ON NULL INPUT
DYNAMIC RESULT SETS 1
BEGIN
call INITIATE();
call another_SP();
call DEINITIATE();
END #

How to define an Array of values (or a Column) into a Procedure Argument?

I am working on a Netezza SP and is stuck with a problem.
I have a SP, defined as say:
CREATE OR REPLACE PROCEDURE MY_PROC(VARCHAR(ANY)) RETURNS INTEGER LANGUAGE NZPLSQL
AS
BEGIN_PROC
DECLARE
v_temp ALIAS FOR $1;
/* Other decalarations */
result_ts INTEGER;
BEGIN
result_ts := 0;
/* Procedure Body */
RETURN result_ts;
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Exception Raised: %', SQLERRM;
END;
END_PROC;
If I am running this SP with one value, such as:
SELECT MY_PROC('TEST_INPUT');
But if I am trying to run it with a column value, such as:
SELECT MY_PROC(TEST_COLUMN) FROM TEST_TABLE;
Its giving me error as:
ERROR: Can't use a stored procedure in this context
I know that in the second scenario I am passing an Array (i guess) but this is not what the Procedure has expected.
Now I am trying to have a procedure that can accept these kind of values but could not succeeded so far, LOOPing and all I have taken care but only problem is the Argument which I don't know how to pass.
Any help would be appreciated, let me know if I need to provide any extra info on this.
Asif
Stored procedures in Netezza, as of v7.2, can only be called in the following ways, as documented here.
CALL sproc_name(...);
EXEC sproc_name(...);
SELECT sproc_name(...);
Note that the SELECT form does not allow a FROM clause.
If you want the stored procedure to act on a particular column from a particular table that changes from invocation to invocation, you could pass the names of those as arguments to the stored procedure and have the entirety of the SQL logic encoded within. You could even pass arbitrary code into the stored procedure to build a query internally.
The way you are trying to call it now is more like calling a user defined function, and that simply won't work with stored procedures here.

Calling an oracle stored procedure form COGNOS

In this link IBM they explain how to use an Oracle stored procedure with COGNOS.
They are doing :
create or replace package body project_pk as
procedure project_sp (tproj IN numeric, result1 in out project_type1) is
begin
open result1 for
select projects.projectid, projects.projecttype
from projects
where projects.projecttype=tproj;
end;
end;
/
With open result1 for they are opening the cursor explicitly. But, they do not seem to close it. Why is this?
You must return resuly set to Cognos. If you close the cursor then there are nor reuslts, right?
It's Cognos responsibility to close the cursor, once it finishes to pull the data from the SP.
In order to make you 100% sure that this is the case look at this link (totaly unrelated to Cognos):
Returning result Sets from SQL Server and Oracle
However, the sample you gave in your link, looks quite complex. Here is what I am using:
CREATE OR REPLACE PROCEDURE "COGNOS_SP" (
case_id in numeric,
po_refcur out sys_refcursor) is
BEGIN
open po_refcur for
select * FROM CASES WHERE CASE_ID = case_id;
END COGNOS_SP;

Resources