I am trying to write a procedure to verify if there was any issues during import so I can raise an error. So I wrote the following block of SQL inside of my stored procedure. But I always get a null value for all the fetched values(actualRowCount, skippedRowCount, importedRowCount, updatedRows, rejectedRows, committedRows) except for the msgs.
I am unable to find why would I get values only for the msgs but not for others. They all should have at least 0 as a value. Please Assume all necessary variables declared in the procedure already.
I get a DB2 SQL-Error: -438 when I do a RAISE_APPLICATION_ERROR outside of the If block for testing purpose and get a null error when I try to print using Put_LINE
Begin Atomic
CALL SYSPROC.ADMIN_CMD( 'IMPORT FROM /tmp/city.ixf OF ixf MESSAGES ON SERVER INSERT INTO city');
ASSOCIATE RESULT SET LOCATORS(resultSet) WITH PROCEDURE SYSPROC.ADMIN_CMD;
ALLOCATE C1 CURSOR FOR RESULT SET resultSet;
FETCH C1 INTO actualRowCount, skippedRowCount , importedRowCount, updatedRows, rejectedRows, committedRows, msgs;
IF actualRowCount <> importedRowCount THEN
CALL RAISE_APPLICATION_ERROR(-20040, 'import fail:' || msgs);
END IF;
Close C1;
End;
Sample message handler for IMPORT with ADMIN_CMD:
--#SET TERMINATOR #
SET SERVEROUTPUT ON#
BEGIN
DECLARE actualRowCount, skippedRowCount, importedRowCount, updatedRows, rejectedRows, committedRows BIGINT;
DECLARE msg_sel, msg_del VARCHAR(128);
DECLARE SQLSTATE CHAR(5);
DECLARE V_SQLCODE VARCHAR(10);
DECLARE V_MSG VARCHAR(1024);
DECLARE resultSet RESULT_SET_LOCATOR VARYING;
DECLARE C2 CURSOR FOR S2;
CALL SYSPROC.ADMIN_CMD('IMPORT FROM /tmp/city.ixf OF ixf MESSAGES ON SERVER INSERT INTO city');
ASSOCIATE RESULT SET LOCATORS (resultSet) WITH PROCEDURE SYSPROC.ADMIN_CMD;
ALLOCATE C1 CURSOR FOR RESULT SET resultSet;
FETCH C1 INTO actualRowCount, skippedRowCount , importedRowCount, updatedRows, rejectedRows, committedRows, msg_sel, msg_del;
CLOSE C1;
IF COALESCE(msg_sel, '') <> '' THEN
CALL DBMS_OUTPUT.PUT_LINE('msg_sel: ' || msg_sel);
PREPARE S2 FROM msg_sel;
OPEN C2;
L2: LOOP
FETCH C2 INTO V_SQLCODE, V_MSG;
IF SQLSTATE = '02000' THEN LEAVE L2; END IF;
CALL DBMS_OUTPUT.PUT_LINE(V_SQLCODE || ': ' || V_MSG);
END LOOP L2;
CLOSE C2;
END IF;
CALL DBMS_OUTPUT.PUT_LINE('msg_del: ' || msg_del);
EXECUTE IMMEDIATE msg_del;
END#
Related
The requirement is to get the log of all the DML statements executed inside a Stored Procedure in teradata. This Stored procedure is being called inside a shell script using BTEQ. The ask is to capture the log of all activities performed inside the shell into a log file in unix. If any error occurs, that also needs to be captured.
The Stored Procedure contains 20 Merge SQLs and i want to see how many rows got affected and how long each statement took. I tried calling the individual merges through BTEQ(instead of calling it in a Stored Procedure), but there is significant time gain if its called inside an SP. Right now, all i can see is that the Stored procedure has been completed successfully.
replace procedure SP_Test()
BEGIN
MERGE INTO T1 using T2 on T1.C1 = T2.C1
WHEN NOT MATCHED THEN INSERT (C1,C2,C3) VALUES (T2.C1,T2.C2,T3.C3)
WHEN MATCHED
THEN UPDATE
SET
C1 = CASE statement 1
C2 = CASE statement 2
c3 = CASE statement 3 ;
END;
inside the BTEQ block of test.sh shell script,
bteq << EOF >>LOgFILE.txt 2>&1
.LOGON source/user,password;
.COMPILE FILE = sp_merge.txt;
.IF ERRORCODE <> 0 THEN .GOTO QUITNOTOK
call SP_Test();
.IF ERRORCODE <> 0 THEN .GOTO QUITNOTOK
.LABEL QUITOK
.LOGOFF
.QUIT 0
.LABEL QUITNOTOK
.QUIT 2
EOF
Log File currently
**** Procedure has been executed.
**** Total elapsed time was 2 minutes and 47 seconds.
Expected Output
**** Merge completed. 5641191 rows affected.
5641191 rows inserted, no rows updated, no rows deleted.
**** Total elapsed time was 2 minutes and 45 seconds.
You can do one thing.
Write another procedure and keep an insert statement like this below :
REPLACE PROCEDURE <DB_USER>. log_process_run_message ( IN in_n_process_run_id DECIMAL(18,0) ,
IN in_v_process_name VARCHAR(30) ,
IN in_v_message_txt VARCHAR(50000) ,
IN in_d_message_ts TIMESTAMP(6)
)
BEGIN
BT; -- Begin Transaction
INSERT INTO <SCHEMA_NAME>.cop_process_run_message_op
(
process_name ,
message_txt ,
message_ts
)
VALUES (
in_v_process_name ,
in_v_message_txt ,
in_d_message_ts
);
ET; -- End Transaction
END;
In your main procedure include an exit handler;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET lv_sql_state = SQLSTATE;
SET ln_sql_code = SQLCODE;
SET out_status = 'FAILED';
ROLLBACK;
SET lv_my_mesg = 'Error in : ' || lv_my_mesg || ' - SQLSTATE: ' || lv_sql_state || ', SQLCODE: ' || CAST(ln_sql_code AS CHAR);
CALL <DB_USER>.log_process_run_message (ln_run_id,lv_err_component,lv_my_mesg,CURRENT_TIMESTAMP(6));
END;
Also define the below variable in your main procedure
SET lv_err_component='ur proc name'
Now call this procedure inside your main procedure after every merge statement:
SET lv_my_mesg ='Merge 1 completed '||CAST(CURRENT_TIMESTAMP(0) AS CHAR(19));
CALL <DB_USER>.log_process_run_message (lv_err_component,lv_my_mesg,CURRENT_TIMESTAMP(6));
What this will do is, it will insert a record after successful execution of your merge statements and in case there is an error it will
execute the call statement in the exit handler and will document your error message as well in case there is any.Let me know if this helps.
I have a Sql File named procedure.sql with a procedure.
Maria DB Version: Server version: 10.0.29-MariaDB-0ubuntu0.16.04.1 Ubuntu 16.04
But I am getting ERROR AS Follows:
>mysql -u root -p XXX < /home/azure/Downloads/procedure.sql
>Enter password:
>ERROR 1064 (42000) at line 2: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '();
>USE XXX;
>CREATE OR REPLACE PROCEDURE XXX.updateDoc_StorageID ()
>BEGIN' at line 1
Can anyone help me please?
procedure.sql Code:
DELIMITER //
DROP PROCEDURE IF EXISTS XXX.updateDoc_StorageID;
USE XXX;
CREATE OR REPLACE PROCEDURE XXX.updateDoc_StorageID ()
BEGIN
DECLARE myTransacID INT DEFAULT 0;
DECLARE myTransProductId INT DEFAULT 0;
DECLARE myDocStoreID VARCHAR(500) DEFAULT '0';
DECLARE my_count INT DEFAULT 0;
DECLARE trans_csr CURSOR FOR SELECT 1,2 FROM MainTable ORDER BY TransactionID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET my_count=1;
SET my_count=0;
OPEN trans_csr;
trans_loop:LOOP
FETCH trans_csr INTO myTransacID,myTransProductId;
IF my_count=1 THEN
LEAVE trans_loop;
END IF;
If(myTransProductId=8)
then
if exists(....)
then
.......
end if;
elseif (myTransProductId=11)
then
if exists(........)
then
.......
END IF;
END IF;
END LOOP trans_loop;
CLOSE trans_csr;
SET my_count=0;
END;
//
DELIMITER ;
The Reference I got is from :
https://mariadb.com/kb/en/mariadb/create-procedure/
The syntax error is not for CREATE PROCEDURE, it's for the preceding DROP PROCEDURE, you shouldn't have brackets there.
DROP PROCEDURE IF EXISTS XXX.updateDoc_StorageID;
The second error follows, since the procedure hasn't been dropped, it still exists.
Also, fix the delimiters -- if you set $$ at the start, then every further query should end with $$, not with semicolon.
The right syntax for version 10.0.x StoredProcedure will be:
DELIMITER //
DROP PROCEDURE IF EXISTS XXX.updateDoc_StorageID;
USE XXX;
CREATE OR REPLACE PROCEDURE XXX.updateDoc_StorageID ()
BEGIN
DECLARE myTransacID INT DEFAULT 0;
DECLARE myTransProductId INT DEFAULT 0;
DECLARE myDocStoreID VARCHAR(500) DEFAULT '0';
DECLARE my_count INT DEFAULT 0;
DECLARE trans_csr CURSOR FOR SELECT 1,2 FROM MainTable ORDER BY TransactionID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET my_count=1;
SET my_count=0;
OPEN trans_csr;
trans_loop:LOOP
FETCH trans_csr INTO myTransacID,myTransProductId;
IF my_count=1 THEN
LEAVE trans_loop;
END IF;
If(myTransProductId=8)
then
if exists(....)
then
.......
end if;
elseif (myTransProductId=11)
then
if exists(........)
then
.......
END IF;
END IF;
END LOOP trans_loop;
CLOSE trans_csr;
SET my_count=0;
END;
//
DELIMITER ;
Gurus, I have stored procedure to has to executed on a dynamic table. Here is how the stored procedure looks like.
create or replace PROCEDURE EFX_RECON_UPDATE_SPROC(
FILENAME IN VARCHAR2 ,
SOURCE IN VARCHAR2 )
AS
TABLE_NAME VARCHAR2(200);
query_str VARCHAR2(500);
cnt NUMBER(10);
BEGIN
-- Create dynamic table for each fullfilment system.
TABLE_NAME := SOURCE||'_BRM_OMC_RECON_T';
query_str :='SELECT count(*) from ' || SOURCE || '_BRM_OMC_RECON_T where PROCESSINGFILENAME='''||FILENAME||''';';
EXECUTE IMMEDIATE query_str;
query_str:='MERGE INTO '||TABLE_NAME||' T
USING (
SELECT
ERRORCODE, PROCESSINGFILENAME,
RECORDNUMBER from ERROR_UPLOAD_T
) TMP
ON (T.RECORDNUMBER = TMP.RECORDNUMBER and
T.PROCESSINGFILENAME= TMP.PROCESSINGFILENAME and
T.PROCESSINGFILENAME='''||FILENAME||''')
WHEN MATCHED THEN
UPDATE SET
T.STATUS = ''ERROR'',
T.ERRORSOURCE = ''BRM'',
T.ERRORCODE = TMP.ERRORCODE';
EXECUTE IMMEDIATE query_str;
COMMIT;
END EFX_RECON_UPDATE_SPROC;
I get this error while executing the stored procedure. The problem is with FILENAME and I have enclosed it in ' quot.
ORA-00933: SQL command not properly ended
ORA-06512: at "PIN149.EFX_RECON_UPDATE_SPROC", line 12
According to the error message the problem is on this line:
EXECUTE IMMEDIATE query_str;
It should be:
EXECUTE IMMEDIATE query_str INTO cnt;
And the semicolon should be removed from the SELECT string.
Although the variable cnt is not used elsewhere so I'm not sure what that statement is supposed to accomplish.
How to Execute Dynamic DDL statements IN TERADATA?
CREATE PROCEDURE DROP_INDEXES(IN indexs varchar(1000),IN p_database VARCHAR (8000),IN p_table varchar(8000))
BEGIN
DECLARE L_SQL VARCHAR(400);
SET L_SQL= 'DROP INDEX '||trim(indexs)||' ON '||trim(db_name)|| '.'|| trim(tablename);
EXECUTE IMMEDIATE L_SQL;
END ;
I need to call this child_procedure(DROP_INDEXES) from parent procedure, but during executing of the parent_procedure, after executing this procedure
CALL DROP_INDEXES(indexs,db_name,tablename);
automatically gets exit from the parent_procedure, the next statement is not executing from parent_procedure.
This is the error i'm getting:
Executed as Single statement. Failed [3722 : HY000] SP_DROP_INDEXES:
Only a COMMIT WORK or null statement is legal after a DDL Statement.
Elapsed time = 00:00:00.326
Kindly do help me regarding my issue.
Thanks in advance.
In Teradata each DDL must be committed individually. Your session is running in ANSO mode, thus you need to add ;COMMIT; to the SQL string.
This should work:
SET L_SQL= 'DROP INDEX '||trim(indexs)||' ON '||trim(db_name)|| '.'|| trim(table name) || ';COMMIT;'
Try a different syntax:
REPLACE PROCEDURE DROP_INDEXES(IN indexs varchar(1000), IN p_database VARCHAR (8000),IN p_table varchar(8000))
BEGIN
DECLARE L_SQL VARCHAR(400);
SET L_SQL= 'DROP INDEX '||trim(indexs)||' ON '||trim(p_database)|| '.'|| trim(p_table);
--EXECUTE IMMEDIATE L_SQL;
CALL DBC.SysExecSQL( L_SQL );
END ;
REPLACE PROCEDURE PROC_TEST1 (IN db_name varchar(30),IN tablename varchar(30),IN indexs varchar(30))
BEGIN
CALL DROP_INDEXES(indexs,db_name,tablename);
insert into test2 (charcol) select user;
END;
call proc_test1(DATABASE,'test2','idx_test2');
I have a db2 stored proc which contains a select query. I want to abort or fail this stored proc if the select query is returning any value. Please help.
SET CURRENT SCHEMA = abc;
SET CURRENT PATH = abc,pqr;
CREATE OR REPLACE PROCEDURE abc.VALID_xyz ( )
SPECIFIC SQL150421070712734
LANGUAGE SQL
NOT DETERMINISTIC
EXTERNAL ACTION
MODIFIES SQL DATA
CALLED ON NULL INPUT
INHERIT SPECIAL REGISTERS
OLD SAVEPOINT LEVEL
begin
DECLARE C1 CURSOR WITH RETURN
FOR select * from xy_table;
open C1;
RETURN;
END;
SET CURRENT SCHEMA = abc;
If xy_table has any rows , I need to fail this stored proc.
The SIGNALcommand can trigger a predefined or custom SQLSTATE that will abort the current SQL procedure (or atomic block of SQL statements) as if an actual error had occurred.
SET CURRENT SCHEMA = abc;
SET CURRENT PATH = abc,pqr;
--#SET TERMINATOR #
CREATE OR REPLACE PROCEDURE abc.valid_xyz()
SPECIFIC valid_xyz
NO EXTERNAL ACTION
LANGUAGE SQL
BEGIN
IF EXISTS ( SELECT 1 FROM xy_table FETCH FIRST ROW ONLY )
THEN
SIGNAL SQLSTATE '75002'
SET MESSAGE_TEXT =
'Table XY_TABLE contained data when it was expected to be empty.';
END IF;
END#
--#SET TERMINATOR ;
CALL valid_xyz();
SQL0438N Application raised error or warning with diagnostic text:
"Table XY_TABLE contained data when it was expected to be empty.". SQLSTATE=75002