BFILE error on oracle - sql

I would like to make sure that every BFILE in my database really exists on the file system it is related to.
I have the following error :
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: invalid
LOB locator specified: ORA-22275 ORA-06512: at line 59
with the following PL/SQL :
1 declare
2 sSQL varchar2(32767);
3 TYPE refcursor is REF CURSOR;
4 outCursor refcursor;
5 v_1 bfile;
6 dir_alias varchar2(500);
7 name varchar2(500);
8 bfile_exists BOOLEAN := FALSE;
9 --
10 -- DECLARATION DES CURSEURS
11 --
12 cursor find_bfile is
13 SELECT owner, table_name, column_name from dba_tab_columns where data_type='BFILE' order by 1,2,3;
14 begin
15 -- curseur principal sur dba_tab_columns
16 for boucle_find_bfile in find_bfile loop
17 dbms_output.put_line('Owner : ' || boucle_find_bfile.owner || 'Table : ' || boucle_find_bfile.table_name|| boucle_find_bfile.column_name );
18 sSQL := 'select ' || boucle_find_bfile.column_name || ' from ' || boucle_find_bfile.owner || '.' || boucle_find_bfile.table_name;
19 dbms_output.put_line('sSQL : ' || sSQL);
20 OPEN outCursor FOR sSQL;
21 LOOP
22 -- lecture initiale
23 FETCH outCursor INTO v_1;
24 dbms_output.put_line('Avant bfile_exists');
25 begin
26 bfile_exists := DBMS_LOB.FILEEXISTS( v_1 ) = 1;
27 EXCEPTION
28 WHEN DBMS_LOB.NOEXIST_DIRECTORY THEN
29 dbms_output.put_line('>>>>> Directory does not exist !');
30 WHEN DBMS_LOB.NOPRIV_DIRECTORY THEN
31 dbms_output.put_line('>>>>> Directory with privs pb !');
32 WHEN DBMS_LOB.INVALID_DIRECTORY THEN
33 dbms_output.put_line('>>>>> Invalid Directory !');
34 WHEN OTHERS THEN
35 dbms_output.put_line('Milieu : Erreur inattendue : ' || SQLERRM);
36 RAISE;
37 end;
38 dbms_output.put_line('Apres bfile_exists');
39 IF bfile_exists
40 THEN
41 dbms_lob.filegetname(v_1, dir_alias, name);
42 dbms_output.put_line('Table : ' || boucle_find_bfile.table_name || ' / dir_alias : ' || dir_alias || ' / name : ' || name );
43 END IF;
44 EXIT WHEN outCursor%NOTFOUND;
45 -- lecture suivante
46 EXIT WHEN outCursor%NOTFOUND;
47 END LOOP;
48 CLOSE outCursor;
49 end loop; -- fin curseur find_bfile
50 EXCEPTION
51 WHEN DBMS_LOB.NOEXIST_DIRECTORY THEN
52 dbms_output.put_line('>>>>> Directory does not exist !');
53 WHEN DBMS_LOB.NOPRIV_DIRECTORY THEN
54 dbms_output.put_line('>>>>> Directory with privs pb !');
55 WHEN DBMS_LOB.INVALID_DIRECTORY THEN
56 dbms_output.put_line('>>>>> Invalid Directory !');
57 WHEN OTHERS THEN
58 dbms_output.put_line('Fin ; Erreur inattendue : ' || SQLERRM);
59 RAISE;
60* end;
A hint : I have many "bfilename(NULL)" in my LOB type column.
I know I do not use the DBMS_LOB.FILEEXISTS function correctly.
How can I do ?
Thanks in advance
Jean-michel A., Nemours, FRANCE
RDBMS : Oracle 11G on Linux with ASM

First you must fix command
EXIT WHEN outCursor%NOTFOUND;
because it should be located right below
FETCH outCursor INTO v_1;
to finish loop correctly and avoid one invalid iteration:
...
OPEN outCursor FOR sSQL;
LOOP
-- lecture initiale
FETCH outCursor INTO v_1;
EXIT WHEN outCursor%NOTFOUND; -- RIGHT HERE
dbms_output.put_line('Avant bfile_exists');
begin
bfile_exists := DBMS_LOB.FILEEXISTS(v_1) = 1;
EXCEPTION
WHEN DBMS_LOB.NOEXIST_DIRECTORY THEN
dbms_output.put_line('>>>>> Directory does not exist !');
WHEN DBMS_LOB.NOPRIV_DIRECTORY THEN
dbms_output.put_line('>>>>> Directory with privs pb !');
WHEN DBMS_LOB.INVALID_DIRECTORY THEN
dbms_output.put_line('>>>>> Invalid Directory !');
WHEN OTHERS THEN
dbms_output.put_line('Milieu : Erreur inattendue : ' || SQLERRM);
RAISE;
end;
dbms_output.put_line('Apres bfile_exists');
IF bfile_exists THEN
dbms_lob.filegetname(v_1, dir_alias, name);
dbms_output.put_line('Table : ' || boucle_find_bfile.table_name ||
' / dir_alias : ' || dir_alias || ' / name : ' || name);
END IF;
-- EXIT WHEN outCursor%NOTFOUND; not here :/
-- lecture suivante
-- EXIT WHEN outCursor%NOTFOUND; here neither :/
END LOOP;
CLOSE outCursor;
...
About invalid LOB locator: When BFILE columns value are null then DBMS_LOB.FILEEXISTS will throw exception ORA-22275: invalid LOB locator specified. A way to solve the problem is catching this into an exception/when block by ora-code. You can init/declare an exception via pragma as below and catch it later:
declare
invalid_lob_loc exception; -- naming my custom exc as 'invalid_lob_loc'
pragma exception_init(invalid_lob_loc, -22275); -- ORA: 22275
begin
...
begin
...
-- this moment exception will be thrown if BFILE column value is null
bfile_exists = DBMS_LOB.FILEEXISTS(v_1) = 1;
...
exception
when invalid_lob_loc then -- catching it
-- set that file does not exists
bfile_exists = false;
end;
...
end;
Althought, if BFILE column is not null but file does not exists anymore in filesystem then DBMS_LOB.FILEEXISTS will return false and everything will flow as planned :)

Related

HOW TO ADD HEADER AND FOOTER AT THE OF THE CODE TO GET THE REQUIRED O/P

Write a procedure to genearte a report of all employee with managers name details with | (pipe delimiter) in unix development server /tmp path.
Example:**
Emp ID|Emp Name|Manager Name|Sal|Dept No|Location -------header**
7369|SMITH|FORD|800|20|DALLAS
Total Record|1 ------Trailer
f_handle2 utl_file.file_type;
begin
f_handle2 := utl_file.fopen(
'TESTING_DIR' -- File location
, 'EMP_DET_WITH_MANA_NAME2' -- File name
, 'w'); -- Open mode: w = write.
for i in (select empno,ename,manager_name,sal,deptno,loc,count(empno) from t77)
loop
utl_file.putf(f_handle2,i.empno||'|'||i.ename||'|'||i.manager_name||'|'||i.sal||'|'||i.deptno||'"'||i.loc);
UTL_FILE.NEW_LINE(f_handle2);
end loop;
utl_file.fclose(f_handle2);
exception
when others then
dbms_output.put_line('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
raise;
end;

Like operator with % in oracle plsql cursor

I cannot pass the like operator with % in the cursor sql stmt, getting code error, Can you help
SQL> l
1 CREATE OR REPLACE PROCEDURE cleanuptab (
2 isrc_tns VARCHAR2
3 )
4 IS
5 sql_stmt VARCHAR2(500);
6 errm VARCHAR2(2000);
7 refcur SYS_REFCURSOR;
8 v_tabs VARCHAR2(50);
9 BEGIN
10 OPEN refcur FOR 'SELECT table_name FROM dba_tables where table_name like '%''||isrc_tns||''%' and owner='DBASCHEMA'';
11 LOOP
12 BEGIN
13 FETCH refcur INTO v_tabs;
14 EXIT WHEN refcur%NOTFOUND;
15 EXECUTE IMMEDIATE 'drop table DBASCHEMA.'
16 ||v_tabs
17 || ' purge';
18 dbms_output.Put_line('DROPPED '
19 ||v_tabs);
20 EXCEPTION
21 WHEN OTHERS THEN
22 dbms_output.Put_line( 'TABLE NOT FOUND: '
23 ||v_tabs);
24 CONTINUE;
25 END;
26 END LOOP;
27 close refcur;
28* END;
SQL> /
Warning: Procedure created with compilation errors.
SQL> show error
Errors for PROCEDURE CLEANUPTAB:
LINE/COL ERROR
-------- -----------------------------------------------------------------
10/79 PLS-00103: Encountered the symbol "%" when expecting one of the
following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between using || multiset member submultiset
The symbol "* was inserted before "%" to continue.
10/96 PLS-00103: Encountered the symbol "%" when expecting one of the
following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
LINE/COL ERROR
-------- -----------------------------------------------------------------
like4 likec between using || member submultiset
I am trying to pass the like stmt & owner condition so that i can get those tables & drop. Pls help to review
Regards
Kannan
Why not try it without OPEN/FETCH/NOTFOUND, without all the local variables, without the danger of SQL injection, with less lines of codes:
CREATE OR REPLACE PROCEDURE cleanuptab (
isrc_tns VARCHAR2
)
IS
BEGIN
FOR v_tabs IN (SELECT table_name FROM dba_tables WHERE table_name LIKE '%' || isrc_tns || '%' AND owner = 'DBASCHEMA')
LOOP
BEGIN
EXECUTE IMMEDIATE 'drop table DBASCHEMA.' || v_tabs.table_name || ' purge';
dbms_output.put_line('DROPPED ' || v_tabs.table_name );
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('FAILED TO DROP ' || v_tabs.table_name);
END;
END LOOP;
END;

How to Write Blob from Oracle Column to the File System

my_images table consists of a blob column called images. I need to write these images to my image_dir which is 'C:\TEMP'.
When the following PL/SQL code is executed, only the first image is written to the directory as an image. The second blob is written as 0 byte (empty) and there is no other (Should be a total number of 8).
So the loop does not seem to work correctly. I am using Oracle 11g Express Edition (XE) and SQL Developer. Here is the error and the code:
Error starting at line : 53 in command -
BEGIN write_blob_to_file_v5; END;
Error report -
ORA-01403: no data found
ORA-06512: at "SYS.DBMS_LOB", line 1056
ORA-06512: at "SYS.WRITE_BLOB_TO_FILE_V5", line 40
ORA-06512: at line 1
01403. 00000 - "no data found"
*Cause: No data was found from the objects.
*Action: There was no data from the objects which may be due to end of fetch.
PL/SQL code
CREATE OR REPLACE PROCEDURE write_blob_to_file_v5
AS
v_lob_image_name VARCHAR (100);
v_lob_image_id NUMBER;
v_blob BLOB;
v_buffer RAW (32767);
v_buffer_size BINARY_INTEGER;
v_amount BINARY_INTEGER;
v_offset NUMBER (38) := 1;
v_chunksize INTEGER;
v_out_file UTL_FILE.file_type;
BEGIN
FOR i IN (SELECT DBMS_LOB.getlength (v_blob) v_len,
image_id v_lob_image_id,
"IMAGE_NAME" v_lob_image_name,
image v_blob
FROM sys.MY_IMAGES)
LOOP
v_chunksize := DBMS_LOB.getchunksize (i.v_blob);
IF (v_chunksize < 32767)
THEN
v_buffer_size := v_chunksize;
ELSE
v_buffer_size := 32767;
END IF;
v_amount := v_buffer_size;
DBMS_LOB.open (i.v_blob, DBMS_LOB.lob_readonly);
v_out_file :=
UTL_FILE.fopen (
location => 'IMAGE_DIR',
filename => ( ''
|| i.v_lob_image_id
|| '_'
|| i.v_lob_image_name
|| '.JPG'),
open_mode => 'wb',
max_linesize => 32767);
WHILE v_amount >= v_buffer_size
LOOP
DBMS_LOB.read (i.v_blob,
v_amount,
v_offset,
v_buffer);
v_offset := v_offset + v_amount;
UTL_FILE.put_raw (file => v_out_file,
buffer => v_buffer,
autoflush => TRUE);
UTL_FILE.fflush (file => v_out_file);
--utl_file.new_line(file => v_out_file);
END LOOP;
UTL_FILE.fflush (v_out_file);
UTL_FILE.fclose (v_out_file);
DBMS_LOB.close (i.v_blob);
END LOOP;
END;
The main problem is related NOT to re-initialize the parameter v_offset to 1 ( as in the declaration section ) :
v_offset := 1;
for every image id just before
v_chunksize := dbms_lob.getchunksize(i.v_blob);
assignment.
Moreover, the problem may arise about not yet closed or already opened blobs. To prevent these,
replace
dbms_lob.open(i.v_blob,dbms_lob.lob_readonly);
with
if ( dbms_lob.isopen(i.v_blob)=0 ) then
dbms_lob.open(i.v_blob,dbms_lob.lob_readonly);
end if;
and
replace
dbms_lob.close(i.v_blob);
with
if ( dbms_lob.isopen(i.v_blob)=1 ) then
dbms_lob.close(i.v_blob);
end if;

Trying to update Oracle Vendor-site flexfields. Cursor not working

I'm pretty new to PL/SQL and am having some trouble getting this to run. I am trying to pass the vendor_site_id in two places using my cursor. (Eventually the list will be longer, just trying in Dev with 2 IDs)
The code was obtained from Oracle, however we are trying to pass a mass update for these flexfields.
Here it is:
SET SERVEROUTPUT ON
DECLARE
lc_return_status VARCHAR2(2000);
ln_msg_count NUMBER;
ll_msg_data LONG;
Ln_Vendor_Id NUMBER;
Ln_Vendor_site_Id NUMBER;
ln_message_int NUMBER;
Ln_Party_Id NUMBER;
lrec_vendor_site_rec ap_vendor_pub_pkg.r_vendor_site_rec_type;
CURSOR cVendorSite
IS
SELECT VENDOR_SITE_ID
FROM ap_supplier_SITES_ALL
where vendor_site_id IN ('1631833', '1630833');
BEGIN
FOR rVendorSite IN cVendorSite
LOOP
Ln_Vendor_site_Id := rVendorSite.vendor_site_id;
Lrec_Vendor_site_Rec.vendor_site_id := rVendorSite.vendor_site_id;
Lrec_Vendor_site_Rec.ATTRIBUTE1 := 'Yes';
AP_VENDOR_PUB_PKG.Update_Vendor_Site_public ( p_api_version => 1,--
x_return_status => lc_return_status, --
x_msg_count => ln_msg_count, --
x_msg_data => ll_msg_data, --
p_vendor_site_rec => Lrec_Vendor_site_Rec, --
p_Vendor_site_Id => Ln_Vendor_site_Id);
IF (lc_return_status <> 'S') THEN
IF ln_msg_count >= 1 THEN
FOR v_index IN 1..ln_msg_count
LOOP
fnd_msg_pub.get (p_msg_index => v_index, p_encoded => 'F', p_data => ll_msg_data, p_msg_index_out => ln_message_int );
Ll_Msg_Data := 'UPDATE_VENDOR_SITE '||SUBSTR(Ll_Msg_Data,1,3900);
dbms_output.put_line('Ll_Msg_Data - '||Ll_Msg_Data );
END LOOP;
End If;
END IF;
END LOOP --Cursor Loop
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('SQLERRM - '||SQLERRM );
END;
/
COMMIT;
EXIT;
END LOOP Needs a Semicolon
You have
END LOOP --Cursor Loop
It needs a semicolon:
END LOOP; --Cursor Loop
Once I modify this plsql block, I just identify two supplier_site_id's which I can modify in lieu of (1631833, 1630833). Of course, execute this for your supplier_site_id.
With this condition, you have the datatype wrong for supplier_site_id. It is of type, NUMBER, and not VARCHAR2. I would expect the database to dynamically cast these VARCHAR2's back to NUMBER's during execution.
Before I invoke the block, here are values associated with two sites I have picked (both NULL) using SQLCl:
APPS#dev>SELECT
2 attribute1
3 FROM
4 apps.ap_supplier_sites_all
5 WHERE
6 vendor_site_id IN (
7 812119,812118
8 );
ATTRIBUTE1
Next, I invoke the plsql block which calls Oracle Applications api associated with performing updates to the vendor site records:
APPS#dev>DECLARE
2 lc_return_status VARCHAR2(2000);
3 ln_msg_count NUMBER;
4 ll_msg_data LONG;
5 ln_vendor_id NUMBER;
6 ln_vendor_site_id NUMBER;
7 ln_message_int NUMBER;
8 ln_party_id NUMBER;
9 lrec_vendor_site_rec ap_vendor_pub_pkg.r_vendor_site_rec_type;
10 CURSOR cvendorsite IS
11 SELECT
12 vendor_site_id
13 FROM
14 ap_supplier_sites_all
15 WHERE
16 vendor_site_id IN (
17 812119,812118
18 );
19
20 BEGIN
21 FOR rvendorsite IN cvendorsite LOOP
22 ln_vendor_site_id := rvendorsite.vendor_site_id;
23 lrec_vendor_site_rec.vendor_site_id := rvendorsite.vendor_site_id;
24 lrec_vendor_site_rec.attribute1 := 'Yes';
25 ap_vendor_pub_pkg.update_vendor_site_public(
26 p_api_version => 1,--
27 x_return_status => lc_return_status, --
28 x_msg_count => ln_msg_count, --
29 x_msg_data => ll_msg_data, --
30 p_vendor_site_rec => lrec_vendor_site_rec, --
31 p_vendor_site_id => ln_vendor_site_id
32 );
33
34 IF
35 ( lc_return_status <> 'S' )
36 THEN
37 IF
38 ln_msg_count >= 1
39 THEN
40 FOR v_index IN 1..ln_msg_count LOOP
41 fnd_msg_pub.get(
42 p_msg_index => v_index,
43 p_encoded => 'F',
44 p_data => ll_msg_data,
45 p_msg_index_out => ln_message_int
46 );
47
48 ll_msg_data := 'UPDATE_VENDOR_SITE '
49 || substr(
50 ll_msg_data,
51 1,
52 3900
53 );
54 dbms_output.put_line('Ll_Msg_Data - ' || ll_msg_data);
55 END LOOP;
56
57 END IF;
58 END IF;
59
60 END LOOP; --Cursor Loop
61 EXCEPTION
62 WHEN OTHERS THEN
63 dbms_output.put_line('SQLERRM - ' || sqlerrm);
64 END;
65 /
PL/SQL procedure successfully completed.
Next, I check these records to see the updates we just made through calling the vendor site update api:
APPS#dev>SELECT
2 attribute1
3 FROM
4 apps.ap_supplier_sites_all
5 WHERE
6 vendor_site_id IN (
7 812119,812118
8 );
ATTRIBUTE1
Yes
Yes
Since I did not perform a commit, I rollback my changes to leave the records unchanged:
APPS#dev>rollback;
Rollback complete.
APPS#dev>SELECT
2 attribute1
3 FROM
4 apps.ap_supplier_sites_all
5 WHERE
6 vendor_site_id IN (
7 812119,812118
8 );
ATTRIBUTE1
Thus, my environment is unchanged.

exception handling not outputting to dbms

Here is my sql code for a function that calculates the area of a circle. I am having trouble getting a dbms_output to show the user defined exception.
I begin by declaring an exception underzero. then i raise it if the user inputs a number less than or equal to 0. In the exception i have dbms_output then return the result. It shows in the query result that the value is null, however the output isn't showing.
I have already set serveroutput on and set verify off. I don't know why it wont output anything. If i run that line alone it outputs to the dbms output window but not when the exception is raised.
create or replace function circle_area
(p_radius number)
return number
is
c_Pi Constant number := acos(-1);
v_result number(10, 2);
underzero exception;
begin
if p_radius <=0 then
raise underzero;
else
v_result := c_pi * p_radius * p_radius;
return v_result;
end if;
exception
when underzero then
dbms_output.put_line('enter number greater than 0');
return v_result;
when others then
dbms_output.put_line('Exception Location: Anonymous Block');
dbms_output.put_line(sqlcode || ': ' || sqlerrm);
return v_result;
end circle_area;
to call the function:
select circle_area(-2) from dual;
I'm not sure that I understand the problem. The code you posted will generate output to dbms_output if serveroutput is enabled...
SQL> set serveroutput on;
SQL> create or replace function circle_area
2 (p_radius number)
3 return number
4 is
5 c_Pi Constant number := acos(-1);
6 v_result number(10, 2);
7 underzero exception;
8 begin
9 if p_radius <=0 then
10 raise underzero;
11 else
12 v_result := c_pi * p_radius * p_radius;
13 return v_result;
14 end if;
15
16 exception
17 when underzero then
18 dbms_output.put_line('enter number greater than 0');
19 return v_result;
20 when others then
21 dbms_output.put_line('Exception Location: Anonymous Block');
22 dbms_output.put_line(sqlcode || ': ' || sqlerrm);
23 return v_result;
24 end circle_area;
25 /
Function created.
SQL> select circle_area(-2) from dual;
CIRCLE_AREA(-2)
---------------
enter number greater than 0
I'm assuming that this is part of a homework assignment and not a real problem that you're facing. In reality, you'd never write code whose primary purpose was to write to dbms_output and you would never, ever have an exception handler that only wrote to dbms_output.