Within HSQLDB, I'm trying to create a stored procedure that executes a commit after having updated the database.
Something like:
CREATE PROCEDURE MY_PROC(IN p_id INTEGER)
MODIFIES SQL DATA
BEGIN ATOMIC
...
UPDATE ...
...
COMMIT;
END
Creating this procedure, by means of a call to the JDBC Statement.execute() method, I get an error:
SQLSyntaxErrorException: unexpected token: COMMIT required: END
Without the COMMIT statement, the procedure is compiled correctly.
Any idea what I'm doing wrong?
You cannot commit the transaction inside a procedure.
You can commit after calling the procedure.
Related
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.
I am getting below error message while executing a Snowflake stored procedure from tDBrow in Talend.
The same stored procedure executes fine when executed from Snowflake Web UI. Could you advise why I am getting scoped transaction error when executing from Talend but not from Web UI.
ERROR:
Stored procedure execution error: Scoped transaction started in stored procedure is incomplete and it was rolled back.
The problem is solved. When the procedure is called from Talend, the transaction starts before execution of the procedure and it finishes after the execution.
I should have explicitly defined the scope of transaction inside the procedure. Therefore, I added these two lines at the beginning and end of the procedure (before return) respectively:
snowflake.createStatement({sqlText: "BEGIN TRANSACTION"}).execute();
snowflake.createStatement({sqlText: "COMMIT"}).execute();
I am working with Oracle SQL Developer and I am trying get the below code to work and just can't figure it out. I have tried multiple different methods including implementing for loops, execute immediate's, scheduling and recompiling.
BEGIN
ORDER_STATUS_1_DROP_TABLE; -- If the table exist, drop it
ORDER_STATUS_2_CREATE_TABLE; -- Create the table
GRANT_NEWANALYTICS; -- Grant users select access
ORDER_STATUS_3_SCRIPT; -- Run script to insert data into table
END;
What the code is trying to do is this:
Procedure 1: Drop if exist, otherwise skip. I don't want to see any warning errors stating that no table exist if this procedure is run when there is no table. This procedure by itself does work as intended.
create or replace PROCEDURE ORDER_STATUS_1_DROP_TABLE IS
table_does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE <Table Name>';
EXCEPTION
WHEN table_does_not_exist then
dbms_output.put_line( 'table dose not exist');
END ORDER_STATUS_1_DROP_TABLE;
Procedure 2: Once the table is dropped, this procedure recreates it with the correct . I don't want to see any errors for "this table already exist" and that is why, in part, procedure 1 exists. This by itself works as intended.
create or replace PROCEDURE ORDER_STATUS_2_CREATE_TABLE IS
v_sql LONG;
BEGIN
v_sql:= 'create table <Table Name>
(<parameters>)';
EXECUTE IMMEDIATE v_sql;
END ORDER_STATUS_2_CREATE_TABLE;
Procedure 3: This just gives users select access to the table created in the last procedure. This procedure works as it was intended.
create or replace PROCEDURE GRANT_NEWANALYTICS IS
BEGIN
EXECUTE IMMEDIATE
'GRANT SELECT ON <Table Name> TO <UserID>';
END;
Procedure 4: This is a complicated query. It is an insert select all from (table left join to a few other tables based upon fields and conditions, etc). After procedures 1-3 are run, this procedure by itself has not issue running, but by itself.
create or replace PROCEDURE ORDER_STATUS_3_SCRIPT IS
BEGIN
DELETE FROM <Table Name>;
INSERT INTO <Table Name>
SELECT * FROM(<Multiple Table Joins>);
END ORDER_STATUS_3_SCRIPT;
When I run the procedures like this:
BEGIN
ORDER_STATUS_1_DROP_TABLE; -- If the table exist, drop it
ORDER_STATUS_2_CREATE_TABLE; -- Create the table
GRANT_NEWANALYTICS; -- Grant users select access
ORDER_STATUS_3_SCRIPT; -- Run script to insert data into table
END;
I get the following error report:
Error report -
ORA-04068: existing state of packages has been discarded
ORA-04065: not executed, altered or dropped stored procedure "<user>.ORDER_STATUS_3_SCRIPT"
ORA-06508: PL/SQL: could not find program unit being called: "<user>.ORDER_STATUS_3_SCRIPT"
ORA-06512: at line 5
04068. 00000 - "existing state of packages%s%s%s has been discarded"
*Cause: One of errors 4060 - 4067 when attempt to execute a stored procedure.
*Action: Try again after proper re-initialization of any application's state.
Now, If I run these separately, it works. So if I first run this:
BEGIN
ORDER_STATUS_1_DROP_TABLE; -- If the table exist, drop it
ORDER_STATUS_2_CREATE_TABLE; -- Create the table
GRANT_NEWANALYTICS; -- Grant users select access
END;
<OUTPUT> PL/SQL procedure successfully completed.
And then this:
BEGIN
ORDER_STATUS_3_SCRIPT; -- Run script to insert data into table
END;
<OUTPUT> <Query runs>
I have not issues. I want to run these set of procedures in ones sweep and could use some help on the idea of such. Anyone have any ideas?
If you want to run all these procedures as a part of a single PL/SQL block then every reference to your table would need to be via dynamic SQL. So ORDER_STATUS_3_SCRIPT would need to use dynamic SQL to build the insert statement(s) to populate the table rather than using simple static SQL. That's obviously possible but it does increase the complexity of the script. Potentially substantially.
Having two PL/SQL blocks, which you've demonstrated works, seems much simpler.
I'm trying to create a stored procedure in a DB2 database using RazorSQL Client but I'm getting this error:
Blockquote
ERROR: A character, token, or clause is invalid or missing.
DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=SELECT
The stored procedure code is:
CREATE PROCEDURE GENERAL.sp_checkemp
(IN emp_code VARCHAR(20))
LANGUAGE SQL
READS SQL DATA
BEGIN
SELECT "name_emp" FROM GENERAL."employee" WHERE "code_emp" = 'abc';
END
SELECT statements in the SQL PL context must have an INTO clause -- you have to put the query results somewhere. If your query returns more than one row, which I suspect it is, you must use a cursor instead.
I am trying to create a simple stored procedure in DB2 that performs the following actions:
Drop table "DELETE_ME"
Create table "DELETE_ME"
Insert into table "DELETE_ME"
Basically, if the table DELETE_ME already exists, the stored procedure executes fine. If it does not exist, then the Stored Procedure fails with the following error:
Lookup Error - DB2 Database Error: ERROR [42704] [IBM][DB2/LINUXX8664] SQL0204N "SARTS02T.DELETE_ME" is an undefined name.
I completely understand this. However, I was hoping to set the procedure up to ignore this error (and all errors) that way the procedure can work as a deployment script as well. On the first deployment, it will ignore the drop table line and jump right to building the table.
I found a CREATE PROCEDURE option called CONTINUE AFTER FAILURE however I am receiving an error. Please see my code and error below. Thanks for your help!!!
CODE:
CREATE OR REPLACE PROCEDURE TEST_PROC LANGUAGE SQL CONTINUE AFTER FAILURE
BEGIN
DROP TABLE DELETE_ME;
CREATE TABLE DELETE_ME (
COLUMN_A DECIMAL(5)
);
INSERT INTO DELETE_ME (COLUMN_A) VALUES (69);
COMMIT;
END;
ERROR:
Lookup Error - DB2 Database Error: ERROR [42601] [IBM][DB2/LINUXX8664] SQL0104N An unexpected token "CONTINUE AFTER FAILURE" was found following "ST_PROC LANGUAGE SQL". Expected tokens may include: "<space>".
The BEGIN ... END section is called a compound statement which allows various declarations and other statements, including other compound statements, to be included inside it.
You'll want to declare a condition handler. You could do it something like this.
CREATE OR REPLACE PROCEDURE TEST_PROC
LANGUAGE SQL
COMMIT ON RETURN YES
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' -- or SQLEXCEPTION
BEGIN
-- insert any code here when DROP fails
END;
DROP TABLE DELETE_ME;
CREATE TABLE DELETE_ME
( COLUMN_A DECIMAL(5)
);
INSERT INTO DELETE_ME (COLUMN_A)
VALUES (69);
END;