I'm trying to see if the following would be possible.
it all hinges on creating Policies and Procedures for each row..
Is it possible to create a dynamically named Procedure and pass that name to a dynamically
named policy?
So as following create these in a loop ??
I have an email alert
CREATE OR REPLACE PROCEDURE caps_email_alert (sch varchar2, tab varchar2, pol varchar2)
AS
msg varchar2(20000) := 'CAPS.ME_PAYEE table violation. The time is: ';
BEGIN
msg := msg||to_char(SYSDATE, 'Day DD MON, YYYY HH24:MI:SS');
UTL_MAIL.SEND (
sender => 'me#somewhere.com',
recipients => 'me#somewhere.com',
subject => 'Table modification on caps.me_payee',
message => msg);
END caps_email_alert;
/
and a policy that will call it...
BEGIN
DBMS_FGA.ADD_POLICY (
object_schema => 'CAPS',
object_name => 'ME_PAYEE',
policy_name => 'CHK_CAPS_ME_PAYEE',
audit_column => 'CARRIER_NO',
audit_condition => 'CARRIER_NO = ''20'' ',
handler_schema => 'SYSADMIN_FGA',
handler_module => 'CAPS_EMAIL_ALERT',
enable => TRUE,
statement_types => 'SELECT, UPDATE',
audit_trail => DBMS_FGA.DB + DBMS_FGA.EXTENDED);
END;
/
I would need to write a subprogram that would execute as follows...
( to create a Procedure and Policy for each row )
BEGIN
FOR c IN (SELECT schema as sch, table as tab, cond as pred FROM slac_red_table) LOOP
--here need to create dynamically named procedure and pass it to a dynamically named policy
--so a function that creates a dynamically named procedure
emailerProcedureName emailerProcedureName%TYPE := emailerFunction(c.sch, c.tab)
createPolicyFunction(c.sch, c.tab, c.cond,emailerProcedureName)
END LOOP;
END;
Maybe I can accomplish the same some other way... have you encountered something similar ?
Related
The following tries to APPEND data to the CLASS table from a dmp that contains several hundred records for that table. There is 1 record already in database and that record also exists in the .dmp. The job completes but no data is appended.
If i switch the parameter to TRUNCATE, the single value is removed and replacedw ith the content of the .dmp i.e .works correctly.
Can anyone tell me what's wrong with this proc that's causing APPEND to fail?
The documentation doesn't seem to offer much beyond a reference to metadata (https://docs.oracle.com/database/121/ARPLS/d_datpmp.htm#ARPLS66059)... i have tried removing the metadata filter included in the code below, but with no +ve result.
Thanks
create or replace procedure import_backup (in_file_name in varchar2,
in_job_name in varchar2,
in_export_filename in varchar2)
is
l_dp_handle number;
l_status varchar2(200); -- Data Pump Status
l_file_name varchar2(100) := nvl(in_file_name,'IMPORTBACKUP');
l_job_name varchar2(100) := nvl(in_job_name,'IMPORTBACKUP20');
l_ipaddress VARCHAR2(20);
l_time VARCHAR2(20);
PROCEDURE_NAME VARCHAR2(30) := 'export_backup';
begin
select PARAM_VALUE
into l_ipaddress
from PARAMETER
where PARAM_NAME = 'DATABASE_SERVER';
select to_char(sysdate, 'YYYYMMDDHHMISS')
into l_time
from dual;
--Log_Message(PROCEDURE_NAME,'Starting with in_file_name: ' || l_file_name || ' and in_job_name: ' || l_job_name);
-- Open a table export job.
l_dp_handle := dbms_datapump.open(operation => 'IMPORT',
job_mode => 'TABLE',
remote_link => NULL,
job_name => l_job_name,
version => 'LATEST');
-- Specify the dump file name and directory object name.
dbms_datapump.add_file(handle => l_dp_handle,
filename => in_export_filename,
directory => 'EXPORT_DIR');
--Specify Truncate mode (to remove table contents and replace with file's contents
DBMS_DATAPUMP.SET_PARAMETER (
handle => l_dp_handle,
name => 'TABLE_EXISTS_ACTION',
value => 'APPEND' );
-- Specify the log file name and directory object name.
dbms_datapump.add_file(
handle => l_dp_handle,
filename => in_export_filename || l_time ||'expdp_XYZ.log',
directory => 'EXPORT_DIR',
filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE);
-- Specify the table to be imported, filtering the schema and table.
dbms_datapump.metadata_filter(handle => l_dp_handle,
name => 'NAME_EXPR',
value => 'IN (''CLASS'')',
object_type => 'TABLE');
-- Exclude table stats
dbms_datapump.metadata_filter(handle => l_dp_handle,
name => 'EXCLUDE_PATH_EXPR',
value => 'IN (''STATISTICS'')');
dbms_datapump.start_job(l_dp_handle);
-- Wait for job
dbms_datapump.wait_for_job(handle => l_dp_handle,job_state => l_status );
dbms_output.put_line( l_status );
--Log_Message(PROCEDURE_NAME,'Completed DataPump Job');
-- Job will continue running the background until it completes or errors
--dbms_datapump.detach(l_dp_handle);
exception
when others then
--Log_Message(PROCEDURE_NAME,'Datapump job failed');
begin
dbms_datapump.detach(l_dp_handle);
execute immediate 'Drop table ' ||l_job_name ;
end;
end import_backup;
Have attempted using 1 record in exiting table and using APPEND - no results
Have attemped using 1 record in exiting table and using using TRUNCATE - the 1 record is deleted and replaced with the content of the dmp's CLASS table
If was ok when i create a function and add a policy in Oracle. Error happen when i want to select a table (OBJECT_NAME). It seems like error happen in the select into variable, but i dont know how to fix it (I make sure that select into 1 variable only and the same type as variable)
CREATE OR REPLACE FUNCTION TC6_NHANVIEN(P_SCHEMA VARCHAR2, P_OBJ VARCHAR2)
RETURN VARCHAR2
AS
USERCHECK VARCHAR2(100);
VAITROCHECK VARCHAR(100);
BEGIN
USERCHECK := SYS_CONTEXT('USERENV', 'SESSION_USER');
VAITROCHECK :='';
IF (USER LIKE 'NV%') THEN --i want to check a variable. Error maybe right here
SELECT VAITRO INTO VAITROCHECK
FROM SYSTEM.NHANVIEN
WHERE MANV=USER;
END IF;
IF (USERCHECK LIKE 'NV%'AND VAITROCHECK!='THANHTRA') THEN
RETURN 'MANV = '''||USERCHECK||'''';
ELSE
RETURN '1=1';
END IF;
END;
BEGIN
dbms_rls.add_policy(
OBJECT_SCHEMA => 'SYSTEM',
OBJECT_NAME => 'NHANVIEN',
POLICY_NAME => 'PC_2',
POLICY_FUNCTION => 'TC6_NHANVIEN',
STATEMENT_TYPES => 'SELECT,UPDATE',
UPDATE_CHECK => TRUE
);
END;
grant select on SYSTEM.NHANVIEN to NV001;
select * from SYSTEM.NHANVIEN --LOG IN AS NV001
i have some code
create or replace function policy_test (p_schema varchar2, p_object varchar2)
return varchar2 is
v VARCHAR2(30);
begin
v := USER;
return 'name = ' || v;
end;
Begin
DBMS_RLS.add_policy (
object_schema => 'system',
object_name => 'WORKMAN',
policy_name => 'WORKMAN_policy_test2',
function_schema => 'system',
policy_function => 'policy_test',
statement_types => 'select',
update_check => true
);
End;
and i'd like to ruturn 'name=system' or 'name=Jack' from function policy_test, but i get some error :
[28113] ORA-28113 policy predicate has error
How can i get current user name in policy_test and return sting like 'name=Jack' ?
Your particular VPD policy will append the return value to an implicit WHERE clause. The problem lies in your desired behavior. You stated, "and i'd like to return 'name=system' or 'name=Jack' from function policy_test"
If you were to write out an SQL statement like this: SELECT * FROM mytable WHERE name=system or SELECT * FROM mytable WHERE name=Jack, what would happen? The query will fail every time. When doing string comparison in a WHERE clause, you must enclose the string literal with single tick marks. Change it to WHERE name = 'Jack' and you have valid SQL.
Back to your function. Your function is returning a string, name=Jack and so WHERE name=Jack is what Oracle is generating. You haven't quoted the string literal so the SQL fails. The nature of VPD hides the exception raised (very frustrating) but Oracle does log it in the trace file.
I have a collection (associative array or nested table) of NUMBER variables. I want to initiate a job which invokes a stored procedure which in turn receives this very custom type and does something for each element. Now my job takes a program where I set arguments. How do I set the argument of my custom data type (associative array or table of Number) into the scheduler program? Or any alternative ways? Thanks in advance
Custom types can be passed to scheduler programs using ANYDATA. But the process is complicated, so it might be easier to create a new job with a hard-coded PL/SQL block instead of re-using a program with arguments.
--Create a nested table of NUMBERs.
create or replace type number_nt is table of number;
--Create a procedure that accepts a nested table of numbers.
create or replace procedure test_procedure(p_numbers in number_nt) is
begin
if p_numbers is not null then
for i in 1 .. p_numbers.count loop
dbms_output.put_line(p_numbers(i));
end loop;
end if;
end;
/
--Create a PROGRAM to run the stored procedure.
begin
dbms_scheduler.create_program
(
program_name => 'TEST_PROGRAM',
program_type => 'STORED_PROCEDURE',
program_action => 'TEST_PROCEDURE',
number_of_arguments => 1
);
end;
/
--Define the argument that will be passed into the stored procedure and enable the program.
begin
dbms_scheduler.define_anydata_argument
(
program_name => 'TEST_PROGRAM',
argument_position => 1,
argument_type => 'SYS.ANYDATA',
default_value => null
);
dbms_scheduler.enable('TEST_PROGRAM');
end;
/
--Create the nested table of numbers, convert it into an ANYDATA, create a job,
--pass the ANYDATA to the job, and then enable the job.
declare
v_numbers number_nt := number_nt(1,2,3);
v_anydata anydata;
begin
v_anydata := anydata.convertCollection(v_numbers);
dbms_scheduler.create_job
(
job_name => 'TEST_JOB',
program_name => 'TEST_PROGRAM',
enabled => false
);
dbms_scheduler.set_job_anydata_value
(
job_name => 'TEST_JOB',
argument_position => 1,
argument_value => v_anydata
);
dbms_scheduler.enable('TEST_JOB');
end;
/
--Check the results.
--STATUS = "SUCCEEDED", OUTPUT = "1 2 3"
select status, output
from dba_scheduler_job_run_details where job_name = 'TEST_JOB';
I've created a new function called GET_FILENAME inside my Oracle APEX database. I'd like to call this function from within a APEX PL/SQL code block and pass it the filename. Below is the function I created in my APEX DB with SQL Dev.
create or replace function get_filename
(p_path IN VARCHAR2)
RETURN varchar2
IS
v_file VARCHAR2(100);
BEGIN
-- Parse string for UNIX system
IF INSTR(p_path,'/') > 0 THEN
v_file := SUBSTR(p_path,(INSTR(p_path,'/',-1,1)+1),length(p_path));
-- Parse string for Windows system
ELSIF INSTR(p_path,'\') > 0 THEN
v_file := SUBSTR(p_path,(INSTR(p_path,'\',-1,1)+1),length(p_path));
-- If no slashes were found, return the original string
ELSE
v_file := p_path;
END IF;
RETURN v_file;
END;
APEX side of things....
Below is the code I'd like to put in when calling the process.
TO_DATE(SUBSTR(GET_FILENAME(file_date),21,8),'YYYY-MM-DD')
Below is the apex process code and the comments are where I'd like to put it in.
BEGIN
APEX_COLLECTION.ADD_MEMBER
(
p_collection_name => 'PARSE_COL_HEAD',
p_c001 => 'C031',
p_c002 => 'FILE_DATE');
FOR UPLOAD_ROW IN (SELECT SEQ_ID FROM APEX_COLLECTIONS
WHERE COLLECTION_NAME = 'SPREADSHEET_CONTENT')
LOOP
APEX_COLLECTION.UPDATE_MEMBER_ATTRIBUTE (
p_collection_name => 'SPREADSHEET_CONTENT',
p_seq => UPLOAD_ROW.SEQ_ID,
p_attr_number => '31',
p_attr_value => :P25_FILE_NAME -- I want to call the process here
);
END LOOP;
END;
I don't normally answer my own question. But this was easier than I thought :). Below is the code I used to get this working....
BEGIN
APEX_COLLECTION.ADD_MEMBER
(
p_collection_name => 'PARSE_COL_HEAD',
p_c001 => 'C031',
p_c002 => 'FILE_DATE');
FOR UPLOAD_ROW IN (SELECT SEQ_ID FROM APEX_COLLECTIONS
WHERE COLLECTION_NAME = 'SPREADSHEET_CONTENT')
LOOP
APEX_COLLECTION.UPDATE_MEMBER_ATTRIBUTE (
p_collection_name => 'SPREADSHEET_CONTENT',
p_seq => UPLOAD_ROW.SEQ_ID,
p_attr_number => '31',
p_attr_value => TO_DATE(SUBSTR(GET_FILENAME(:P25_FILE_NAME),21,8),'YYYY-MM-DD')
);
END LOOP;
END;