Using basic SQL, I'm populating a table from another DB. This uses basic Delete statements to remove old data and Insert statements with a FROM clause using a DBLink. I'm attempting to transfer this to a package and have come up with this:
Package:
CREATE OR REPLACE
PACKAGE LOADDATA AS
procedure POPULATETABLE;
END LOADDATA;
PL/SQL (Package Body):
CREATE OR REPLACE
PACKAGE BODY LOADDATA AS
procedure POPULATETABLE AS
BEGIN
DELETE FROM DATATRANSFER;
INSERT INTO DATATRANSFER
SELECT VALUENUM, DATACONTENT, sysdate AS TRANSFER_DATA
FROM TRANSFERTABLE#DATALINK;
COMMIT;
NULL;
END POPULATETABLE;
END LOADDATA;
And to run the command, I would run:
exec LOADDATA.POPULATETABLE();
My question is should the procedure have an input/output parameter or declared variables? It has compiled and worked correctly but I'm unsure if I'm following PL/SQL methodology.
There is no rule to provide parameters.
Additonally you can insert record to log table which will store the start date, end date, number of records inserted and number of records deleted in case you need to track the batch execution periodically.
Also if this package is called by some web page or some application then you may need to create an exception block and send a Error Message as an output parameter in a User Readable Form.
EDIT:
Package Specification
CREATE OR REPLACE
PACKAGE LOADDATA AS
procedure POPULATETABLE(out_variable OUT VARCHAR2);
END LOADDATA;
Package Body
CREATE OR REPLACE
PACKAGE BODY LOADDATA AS
procedure POPULATETABLE(out_variable OUT VARCHAR2) AS
BEGIN
DELETE FROM DATATRANSFER
-- <TODO:INSERT records deleted and date into a log table>
INSERT INTO DATATRANSFER
SELECT VALUENUM, DATACONTENT, sysdate AS TRANSFER_DATA
FROM TRANSFERTABLE#DATALINK;
-- <TODO:INSERT records inserted and date into a log table>
COMMIT;
NULL;
-- Assign out_variable as success if comletes successfully
out_variable := 'SUCCESS';
EXCEPTION
-- WHEN OTHERS catches all exceptions Oracle error message is displayed in SQLERRM
WHEN OTHERS THEN
-- Assign out_variable with Error message if errors out
out_variable := 'Error :'||SQLERRM;
END POPULATETABLE;
END LOADDATA;
Related
I have some MariaDb maintenance scripts that have the form:
DELIMITER //
CREATE PROCEDURE SAMPLE_TASK(OUT RESULT BOOLEAN)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Error running SAMPLE_TASK';
SHOW ERRORS;
SET RESULT=FALSE;
END;
-- DO SOMETHING HERE
SET RESULT=TRUE;
END //
DELIMITER ;
DELIMITER //
CREATE PROCEDURE RUN_TASKS()
BEGIN
DECLARE SUCCESS BOOLEAN DEFAULT TRUE;
IF (SUCCESS) THEN
CALL SAMPLE_TASK(SUCCESS);
END IF;
IF (SUCCESS) THEN
CALL SAMPLE_TASK2(SUCCESS);
END IF;
END //
DELIMITER ;
CALL RUN_TASKS();
The gist of it is that there are a series of tasks that are broken out into stored procedures. We want to execute each in turn aborting if we encounter an error.
This has worked well for us until now due to the fact one of our tasks we want to add will modify triggers, and it seems that creating a trigger within a stored procedure is not supported.
Since we can't add triggers in the stored procedures we are looking to do it outside of them, such as by adding a CREATE TRIGGER statement after the call to RUN_TASKS. The problem we have with that is that we can't find a way to handle errors at that level. From what I've been able to find declaring handlers can only be done at the procedure level, and MariaDb doesn't seem to offer try/catch like some some other DB products.
So the questions are: 1) Does anyone know how to create a trigger from within a stored procedure? 2) How do you add error handling outside of a stored procedure? Thanks
I am trying to create a procedure to do a blanket revoking of executeauth for procedures from a schema. This is in line with trying to secure a non-restricted database.
CREATE PROCEDURE PROC_REV
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
DECLARE v_NAME VARCHAR(400);
FOR v1 AS
c1 CURSOR FOR
select specificname from SYSCAT.ROUTINEAUTH where grantee='PUBLIC' and schema='SYSPROC' and routinetype='P'
DO
SET v_NAME = specificname;
SET v_GrantQuery = 'revoke execute on specific procedure '|| v_NAME ||' from PUBLIC';
EXECUTE IMMEDIATE v_GrantQuery;
END FOR;
END#
and this is the command I run to process the file with the code above.
db2 -td# -svf RoutineAuthRevoke.db2
However, I keep running into this error
SQL0553N An object cannot be created with the schema name "SYSFUN ". LINE NUMBER=1. SQLSTATE 42939
I'm fairly new to DB2 and this is my first foray into writing db2 procedure scripts. Would anyone be able to spot the "SYSFUN " because I sure as hell can't. The only other way I can revoke 310 entries from SYSPROC for PUBLIC is through a batch file and I figured, procedures might be a cleaner way of achieving this. I would really appreciate any help with either this error or with the code itself.
A number of problems.
You can't create a routine in the SYSFUN schema as the error message shows. You get this message because the statement VALUES CURRENT SCHEMA returns SYSFUN in your session. You must either run the SET SCHEMA SOME_VALID_SCHEMA_NAME statement before CREATE or use fully qualified routine name like SOME_VALID_SCHEMA_NAME.PROC_REV.
Variable v_GrantQuery is not defined in the routine.
According to the syntax of REVOKE (routine privileges) statement, you should generate the REVOKE statement using fully qualified routine name and with RESTRICT clause at the end. The easiest way to do it with a compound statement (you don't need to create a routine for that):
BEGIN
FOR v1 AS
select 'REVOKE EXECUTE ON SPECIFIC PROCEDURE "' || schema ||'"."'|| specificname || '" FROM PUBLIC RESTRICT' AS STMT
from SYSCAT.ROUTINEAUTH
where grantee='PUBLIC' and schema='SYSPROC' and routinetype='P'
DO
EXECUTE IMMEDIATE v1.STMT;
END FOR;
END#
I have an SP that needs to be called by an "after update" trigger. This Sp writes out a document to the mounted oracle directory for the host application to pick up. The SP has the following parameters :
CREATE OR REPLACE test_sp_mbinfo
(out_status OUT VARCHAR2,
out_dir OUT VARCHAR2,
in_contract IN VARCHAR2)
The in_contract parameter would be sent in by the triggering event. The trigger code i have so far that i have a hard time compiling is :
CREATE OR REPLACE TRIGGER mbinfo_trig
AFTER UPDATE OF tsta_cncontst ON kndtsta
FOR EACH ROW
BEGIN
IF (:new.tsta_cncontst IN ('02','06'))
THEN
test_sp_mbinfo(:new.tsta_cncclipu);
END IF;
END
;
How do i pass in the 2 out parameters to make the process work?
Thank you!
You could declare two local variables in the trigger and pass those for the OUT parameter. The question then becomes whether you care about the returned values, and if so what to do with them.
I have a software for creating especial reports that run procedures in oracle database but the problem is:
when we create a report it uses some procedures and truncate and fill some tables, if we create another report at the same time it caused an error because it needs my table information that are truncated with another procedure. So I am looking for a technique or query to handle this problem and create the second report just after the first report finishing all the procedures that it use in the state that user do not notice anything. In this case the time that the second report is going to be create is more than the first report that it is alright.
You can use DBMS_LOCK.ALLOCATE_UNIQUE package in order to synchronize your applications and enforcing sequential processing.
DECLARE
l_status number;
l_lock_handle varchar2(128);
l_lock_request integer;
BEGIN
DBMS_LOCK.ALLOCATE_UNIQUE ( lockname => 'NAME_OF_YOUR_LOCK', lockhandle => l_lock_handle);
l_status := DBMS_LOCK.REQUEST(lockhandle => l_lock_handle, timeout => 15);
if (l_status = 0) then
-- Plase your code here
-- Only one thread can work here
l_lock_request := DBMS_LOCK.release(l_lock_handle);
else
-- handle other lock statuses...
end if;
END;
You can read more about DBMS_LOCK here.
this main problem is to try to get the sql loader to execute inside the package.
procedure addGroup
is
num number;
name1 Varchar2(20);
load Varchar2(200);
begin
load := 'host sqlldr kevonia_workspace/pass123 control = C:\Users\Kevonia\Desktop\DBA\usernames.ctl log = C:\Users\Kevonia\Desktop\DBA\usernames.log';
Execute immediate(load);
for num in 1..10
loop
select username into name1 from loaded where userid=num;
DBA_PACKAGE.NewUser(name1);
dbms_output.put_line(name1|| ': was added' );
end loop;
end addGroup;
ORA-00900: invalid SQL statement
You have several options
Create external
table.
You can then manipulate the table as you would for a normal table.
This is the best option.
If you don`t have privileges to create a table and you insist on using host commands look at
this
(but really, don't do it).
Same as above but using a dbms_scheduler executable job.