Oracle SQL FGA sys_context(‘userenv’,’current_sql’) truncated - sql

I want to log all statement against a specific table, using FGA and sys_context(‘userenv’,’current_sql’) I get close to what I need but it appears like current_sql is always truncated to 256 char.
I tried looking at current_sql1 to 7 but they are always empty. Here is the code I'm using to set this up :
create table emp_audit
( whodidit varchar2(40)
, whenwasit timestamp
, sql_executed varchar2(4000)
, sql_executed1 varchar2(4000)
, sql_executed2 varchar2(4000)
, sql_executed3 varchar2(4000)
, sql_executed4 varchar2(4000)
, sql_executed5 varchar2(4000)
, sql_executed6 varchar2(4000)
, sql_executed7 varchar2(4000)
);
create or replace
package AUDIT_HANDLER
is
PROCEDURE HANDLE_EMP_SAL_ACCESS
( object_schema VARCHAR2
, object_name VARCHAR2
, policy_name VARCHAR2
);
end;
create or replace
package body AUDIT_HANDLER
is
PROCEDURE HANDLE_EMP_SAL_ACCESS
( object_schema VARCHAR2
, object_name VARCHAR2
, policy_name VARCHAR2
) is
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert into emp_audit
( whodidit, whenwasit, sql_executed, SQL_EXECUTED1, SQL_EXECUTED2, SQL_EXECUTED3, SQL_EXECUTED4, SQL_EXECUTED5, SQL_EXECUTED6, SQL_EXECUTED7)
values
( user, systimestamp, sys_context('userenv','current_sql'),sys_context('userenv','current_sql1'),sys_context('userenv','current_sql2'),sys_context('userenv','current_sql3'),sys_context('userenv','current_sql4'),sys_context('userenv','current_sql5'),sys_context('userenv','current_sql6'),sys_context('userenv','current_sql7'))
;
commit;
end HANDLE_EMP_SAL_ACCESS;
end;
begin
dbms_fga.add_policy
( object_schema=>'EPAT'
, object_name=>'PERSON'
, policy_name=>'PHI_ACCESS_HANDLED'
, handler_schema => 'SBOUCHAR'
, handler_module => 'AUDIT_HANDLER.HANDLE_EMP_SAL_ACCESS'
);
end;

It appears like you have to specify the length in the call to sys_context :
sys_context('userenv','current_sql',4000)

Related

ORA-06553: PLS-801:Internal Error [55018]

I want to make a function call like SELECT URUN_GETIR('test1') FROM DUAL; but i got ORA-06553: PLS-801: Internal Error [55018].
I tried ORA-06553: PLS-801: internal error [55018] when testing function returning ROWTYPE this like for ex URUN_GETIR('test1').KULUSERNAME but getting same error. It didn't work for me.Thanks in advance.
My db table :
My plsql function code :
create or replace FUNCTION URUN_GETIR(KULADI VARCHAR2)
RETURN URUN%ROWTYPE
AS
URUN_TABLO URUN%ROWTYPE;
BEGIN
SELECT * INTO URUN_TABLO FROM URUN ur WHERE ur.kulusername = KULADI;
RETURN URUN_TABLO;
END;
You can achieve your goal with using table functions. Other than that you can not call directly your function like you wanted. Here is another choice for you Use Stackoverflow Wisely
CREATE TABLE URUN
(
CREATED_BY VARCHAR2 (50 CHAR),
CREATED_DATE DATE,
UPDATED_BY VARCHAR2 (50 CHAR),
KULUSERNAME VARCHAR2 (50 CHAR),
ID NUMBER (10)
);
INSERT INTO URUN (CREATED_BY, CREATED_DATE, UPDATED_BY, KULUSERNAME, ID) VALUES('TEST1',TO_DATE('19000101','YYYYMMDD') ,'TTEST1','USER1',1);COMMIT;
INSERT INTO URUN (CREATED_BY, CREATED_DATE, UPDATED_BY, KULUSERNAME, ID) VALUES('TEST2',TO_DATE('19000102','YYYYMMDD') ,'TTEST2','USER2',2);COMMIT;
INSERT INTO URUN (CREATED_BY, CREATED_DATE, UPDATED_BY, KULUSERNAME, ID) VALUES('TEST3',TO_DATE('19000103','YYYYMMDD') ,'TTEST3','USER3',3);COMMIT;
INSERT INTO URUN (CREATED_BY, CREATED_DATE, UPDATED_BY, KULUSERNAME, ID) VALUES('TEST4',TO_DATE('19000104','YYYYMMDD') ,'TTEST4','USER4',4);COMMIT;
CREATE OR REPLACE TYPE URUN_OBJ AS OBJECT
(
CREATED_BY VARCHAR2 (50 CHAR),
CREATED_DATE DATE,
UPDATED_BY VARCHAR2 (50 CHAR),
KULUSERNAME VARCHAR2 (50 CHAR),
ID NUMBER (10)
);
CREATE OR REPLACE TYPE URUN_OBJ_TAB AS TABLE OF URUN_OBJ;
CREATE OR REPLACE FUNCTION URUN_GETIR (KULADI IN VARCHAR2)
RETURN URUN_OBJ_TAB
PIPELINED
AS
REC_OBJ URUN_OBJ;
CURSOR DATA
IS
SELECT *
FROM URUN UR
WHERE UR.KULUSERNAME = KULADI;
BEGIN
FOR REC IN DATA
LOOP
REC_OBJ :=
URUN_OBJ (REC.CREATED_BY,
REC.CREATED_DATE,
REC.UPDATED_BY,
REC.KULUSERNAME,
REC.ID);
PIPE ROW (REC_OBJ);
END LOOP;
RETURN;
END;
/
SELECT * FROM TABLE(URUN_GETIR('USER1'));
CREATED_BY CREATED_DATE UPDATED_BY KULUSERNAME ID
TEST1 1.01.1900 TTEST1 USER1 1

Procedure to Insert into table and its columns by given parameters?

i`ll start this with some code...
CREATE OR REPLACE PROCEDURE LOAD_IMAGE_INTO_TABLE (
imgDir varchar2
, imgName varchar2
, destTable varchar2
, destIndex varchar2
, destBlob varchar2)
AS
fHnd bfile;
b blob;
srcOffset integer := 1;
dstOffset integer := 1;
BEGIN
dbms_lob.CreateTemporary( b, true );
fHnd := BFilename( imgDir, imgName );
dbms_lob.FileOpen( fHnd, DBMS_LOB.FILE_READONLY );
dbms_lob.LoadFromFile( b, fHnd, DBMS_LOB.LOBMAXSIZE, dstOffset, srcOffset );
--insert into (Select * From user_tables Where table_name = destTable) values(imgName,b);
--insert into destTable (destIndex, destBlob) values( imgName, b );
commit;
dbms_lob.FileClose( fHnd );
END LOAD_IMAGE_INTO_TABLE;
As you might see, I am trying to create a procedure which puts an image into a table. Target table name and column names (for imgname and blobfile) will be given as parameters.
Both ways I tried didn't work. (see --insert(...) in code)
Maybe you have any idea how to solve this?
Thanks in advance.

How to select into varray in Oracle

I'm trying to save a set of ids in array:
create or replace type vrray_4 as varray(4) of varchar2(10);
create or replace procedure get_acl_owner_exchange (id in varchar2 ) is
path_count int;
acl_type out vrray_4;
begin
select owner_id into acl_type from kmc_acl_perm
where permission_name = 'read.'
or permission_name = 'write.'
or permission_name = 'delete.';
end get_acl_owner_exchange;
I'm getting the error:
LINE/COL ERROR
-------- --------------------------------------------------------------------------------
3/17 PLS-00103: Encountered the symbol "VRRAY_4" when expecting one of the following:
:= . ( # % ; not null range default character
The symbol ":=" was substituted for "VRRAY_4" to continue.
You have the OUT parameter in the wrong place and you need to use BULK COLLECT INTO rather than just INTO:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE KMC_ACL_PERM(
owner_id VARCHAR2(10),
permission_name VARCHAR2(10)
)
/
CREATE OR REPLACE TYPE vrray_4 AS VARRAY(4) OF VARCHAR2(10)
/
create or replace PROCEDURE GET_ACL_OWNER_EXCHANGE (
id IN VARCHAR2,
acl_type OUT VRRAY_4
) IS
BEGIN
SELECT owner_id
bulk collect into acl_type
from KMC_ACL_PERM
where permission_name IN ( 'read.', 'write.', 'delete.' );
END GET_ACL_OWNER_EXCHANGE;
/
Does this work for you:
CREATE OR REPLACE TYPE vrray_4 AS VARRAY(4) OF VARCHAR2(10);
/
CREATE TABLE kmc_acl_perm (
owner_id VARCHAR2(10),
permission_name VARCHAR2(10)
);
CREATE OR REPLACE PROCEDURE get_acl_owner_exchange (id IN VARCHAR2) IS
path_count NUMBER;
acl_type vrray_4;
BEGIN
SELECT owner_id BULK COLLECT INTO acl_type
FROM kmc_acl_perm
WHERE permission_name IN ('read.', 'write.', 'delete.');
END get_acl_owner_exchange;
/

Return an array in oracle stored procedure

I have a Stored procedure which takes 2 input parameter and 6 out. One of the out parameter returns more than one record. Is there any way to declare it as an array hence I don't have to declare a cursor. Here is the code,
CREATE OR REPLACE PROCEDURE SP_GET_USER_DETAILS
(
P_ID IN OUT VARCHAR2
, P_USER_NAME IN OUT VARCHAR2
, P_USER_TYPE OUT VARCHAR2
, P_EMPLOYEE_ID OUT VARCHAR2
, P_LICENSE_NO OUT VARCHAR2
, P_PHONE_NO OUT VARCHAR2
) IS
BEGIN
SELECT ACCT.ID, ACCT.USERNAME, ACCT.EMPLOYEE_ID, ACCT.LICENSE_NO,
ADDRESS.PHONE_NO INTO P_ID, P_USER_NAME, P_EMPLOYEE_ID, P_LICENSE_NO, P_PHONE_NO
FROM PROVIDER_ACCT ACCT
LEFT OUTER JOIN EMP_ADDRESS ADDRESS ON ACCT.ID=ACCT.ID
END SP_GET_PRISON_USER_DETAILS;
The problem is ADDRESS.PHONE_NO alone returns multiple rows. Is there any way to declare it as an array and get this working ? Thanks in advance.
If its not possible, could you please explain how to do it using a ref cursor ?
Use a collection:
CREATE OR REPLACE PROCEDURE SP_GET_USER_DETAILS
(
P_ID IN OUT VARCHAR2
, P_USER_NAME IN OUT VARCHAR2
, P_USER_TYPE OUT VARCHAR2
, P_EMPLOYEE_ID OUT VARCHAR2
, P_LICENSE_NO OUT VARCHAR2
, P_PHONE_NO OUT SYS.ODCIVARCHAR2LIST
)
IS
BEGIN
SELECT ID,
USERNAME,
EMPLOYEE_ID,
LICENSE_NO
INTO P_ID,
P_USER_NAME,
P_EMPLOYEE_ID,
P_LICENSE_NO
FROM PROVIDER_ACCT;
SELECT ADDRESS.PHONE_NO
BULK COLLECT INTO P_PHONE_NO
FROM PROVIDER_ACCT ACCT
LEFT OUTER JOIN EMP_ADDRESS ADDRESS
ON ACCT.ID = ADDRESS.ID;
END SP_GET_PRISON_USER_DETAILS;
/
Note: you haven't specified a where clause in your question - you probably want to add one in.

Workaround for ORA-00997: illegal use of LONG datatype

I want to save some data from a system table user_tab_cols, to a temp table so I can take a dump from it.
There are 100,000 rows in it , I have select from user_tab_cols about 1,000 records and d save them into a temp table with this query:
create table temp table as
select * from user_tab_cols where condition...
I had error 'illegal use of longtype' , because of the column DATA_DEFAULT that contain a type of long.
Is there an alterantive way where I can store a long type into another table?
ORA-00997: illegal use of LONG datatype
It is a restriction on usage of LONG data type. You cannot create an object type with a LONG attribute.
SQL> CREATE TABLE t AS SELECT data_default FROM user_tab_cols;
CREATE TABLE t AS SELECT data_default FROM user_tab_cols
*
ERROR at line 1:
ORA-00997: illegal use of LONG datatype
SQL>
Alternatively, you could use TO_LOB as a workaround. Which would convert it into CLOB data type.
For example,
SQL> CREATE TABLE t AS SELECT TO_LOB(data_default) data_default FROM user_tab_cols;
Table created.
SQL> desc t;
Name Null? Type
----------------------------------------- -------- ----------------------------
DATA_DEFAULT CLOB
SQL>
See more examples of workarounds here.
You'll need to create your target table explicitly, not from select *:
create table demo_copy
( table_name varchar2(30)
, column_name varchar2(30)
, data_type varchar2(106)
, data_type_mod varchar2(3)
, data_type_owner varchar2(30)
, data_length number
, data_precision number
, data_scale number
, nullable varchar2(1)
, column_id number
, default_length number
, data_default clob
, num_distinct number
, low_value raw(32)
, high_value raw(32)
, density number
, num_nulls number
, num_buckets number
, last_analyzed date
, sample_size number
, character_set_name varchar2(44)
, char_col_decl_length number
, global_stats varchar2(3)
, user_stats varchar2(3)
, avg_col_len number
, char_length number
, char_used varchar2(1)
, v80_fmt_image varchar2(3)
, data_upgraded varchar2(3)
, hidden_column varchar2(3)
, virtual_column varchar2(3)
, segment_column_id number
, internal_column_id number
, histogram varchar2(15)
, qualified_col_name varchar2(4000) );
(I've made data_default a clob for more convenient querying.)
Then you can insert rows in a PL/SQL loop:
begin
for r in (
select * from user_tab_cols c
where rownum <= 2 -- your filter condition here
)
loop
insert into demo_copy values r;
end loop;
end;
There are some limitations in principle with this approach, as a long column can hold more than the varchar2(32760) that PL/SQL will use in the loop. However, I expect 32K will be enough for most column default expressions.