Large tiff file is not inserting - oracle

I have a function, which has some parameter. One of the parameter is clob where i'm passing a tiff file from front end screen. In front end the tiff data is embedded in xaml and calling the function. I'm trying to store the tiff file into a table. i can able to insert tiff has length less than 32768. When i try to insert more than that its not inserting into the table. I can't even try to find the length of the file. It shows nothing. i have tried put it in bind variable and execute immediate the insert statement. nothing inserted.
CREATE OR REPLACE FUNCTION insert_tiff_data
(
as_fno varchar2(10),
as_a_code IN amc.amc_code%TYPE,
as_app_sign clob,
as_sataus IN VARCHAR2
) RETURN VARCHAR2 IS
--declared variables here
BEGIN
ls_file := as_a_code || '_' || as_fno || '.TIF';
BEGIN
BEGIN
SELECT COUNT(*)
INTO ll_count
FROM tiff_data
WHERE filename = ls_file AND
image_type = 'S' AND
fid = as_fno;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20780,
excep);
ll_count := 0;
END;
IF ll_count >= 1 THEN
RETURN 'Z';
ELSE
IF length(as_app_sign) > 0 THEN
BEGIN
INSERT INTO tiff_data
(filename,
image_type,
amc_code,
fid,
image_date,
image,
editor_id,
xy_cor)
VALUES
(ls_file,
'S',
as_a_code,
as_fno,
SYSDATE,
plf_base64_clob_to_blob(as_app_sign),
'',
'');
IF SQL%ROWCOUNT > 0 THEN
RETURN 'Y';
ELSE
RETURN 'C';
END IF;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20781,
excep);
RETURN 'D';
END;
END IF;
END IF;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20782,
excep);
RETURN 'E';
END;
RETURN 'F';
END insert_tiff_data;
I think function abnormally closed when trying to access that variable as_app_sign.

You need to check out the the Oracle supplied package DBMS_LOB, for processing a large object (blob, clob, ...). If your data exceeds 32767 bytes, you will need to build it up in segments. (32767 is the largest block size that can be transmitted at one time).
You also have a issue with your exception handling. Raise_Application_Error immediately terminates the current block with the error code and message specified, any code following, passing that to the exception block or the exception block of any higher block or out of the procedure, any code after RAE in the same block is not executed. Thus your function is incapable or returning D or E or setting ll_count to 0. Further a return statement executed immediately exits the procedure and no following code is executed. I have not exhaustive validated, but I do not think the current function is capable of returning F either. I have put together a fiddle for demonstration. It patterns itself after your logic (using parameters for values), but probably does not get the logic exactly.

Related

where do i use no data found exception on FOR statement inside a stored procedure

i have the next question:
Im not very good at DBs, i've been requested to add a "No data found exception" to a stored procedure.
This is the SP:
CREATE OR REPLACE PROCEDURE TABLE."SP_UPD"
(
PERROR OUT VARCHAR2
)
AS
BEGIN
FOR TMP_TABLE IN
(SELECT FIELDS FROM TABLES)
--I need to verify HERE if the for returns--
--no values, because once the loop starts it automaticaly updates tables--
LOOP
BEGIN
CODE
MORE CODE
END
END LOOP;
I added the exception here, at the bottom before the last backslash, is this right?:
EXCEPTION WHEN NO_DATA_FOUND
THEN
perror:='error message';
return;
END;
/
You don't have to do anything, because - in a cursor FOR loop (which is what you have), Oracle will skip everything between LOOP and END LOOP if cursor doesn't return any rows.
So: if select fields from tables doesn't return anything , code and more code won't ever be executed.

How to reuse temporary lob in oracle

I am having one program in Oracle PL/SQL.The program does some batch processing ie. it sends data to another system through REST API in batches of fixed number of records. the request and response object are clob and hence i am creating temporary lob and freeing it for each iteration.
My question is ,can't i create temp lob once and resuse it for every batch i process and then free it at last only once. Basically i want to bring create and free out of the loop so that it can improve performance and reuse the memory.
When i try to bring it outside loop, i will need to initialize clob variable at the start of each iteration, so i tried it using empty_clob() but did not work.Also assigning null does not work.
I am getting error as "Invalid lob locator specified at ..."
Below is my pseudo code
for i in start_batch to end_batch
loop
dbms_lob.createtemporary(l_clob,TRUE);
...code to generate request object.
dbms_lob.freetemporary(l_clob,TRUE) ;
end loop
Huh. I swear that worked, but you are correct. I shouldn't try to remember these things. I guess assigning '' to a clob does set it to null. You can't use a null clob with dbms_lob.append, since it's expecting basically a pointer. Try using the concatenation operator, ||.
I've confirmed this works:
declare
l_clob clob;
begin
for i in 1..5 loop
l_clob := '';
for j in 1..5 loop
l_clob := l_clob || 'a';
end loop;
dbms_output.put_line(l_clob);
end loop;
end;
Edit:
I'm not sure it's true that a clob concatenated with a varchar is a varchar and therefore limited to 32 kB. But that does contradict what the documentation says. Take this for example:
declare
c clob;
begin
for i in 1..40000 loop
c := c || 'a';
end loop;
dbms_output.put_line('len=' || dbms_lob.getlength(c));
end;
Result:
len=40000

I'm trying to get a process to be kicked off when a query finds a table is empty

I want to code a way to check if there's data in a table prior to executing a stored procedure.
I've created some 'stripped down' test code that 'almost' meets the conditions that I seek, I was hoping someone might be able to help me get that to work. If so, then I can substitute the values for my procedure, instead of just the dbms_output and be up and running.
Creates a test table, with no rows.
CREATE TABLE t (c VARCHAR2(20));
Then the way I am trying to do this...
declare
no_such_table exception;
pragma exception_init( no_such_table, -942 );
EXISTS_1 integer;
BEGIN
for tst in (
select count (c) x from t
)
loop
execute immediate' select count (c) Z from ' ||tst.t into EXISTS_1;
if EXISTS_1 <= 0
then
dbms_output.put_line( 'a' );
else dbms_output.put_line( 'b' );
end if;
end loop;
exception
when no_such_table
then
dbms_output.put_line( 'c' );
WHEN NO_DATA_FOUND THEN
dbms_output.put_line( 'd' );
end;
The first part, with the count, is supposed to hold a numeric value to indicate if there are any rows in the table. Then the execute immediate into EXISTS_1 holds the value to decide what output to give.
Firstly, I can't get the execute immediate bit to actually work. But if I could get it working, I want the output to record 'a' if there's no rows in the table. (Actually, I would execute the procedure here) and to record 'b' if there was data in there, which you can insert with:
insert into t (c) values('x');
commit;
The 'c' and 'd' outputs are just attempts to handle other potential issues that may occur.
As things stand, I get an error indicating that component t must be declared. Can you understand what I 'm trying to do, and if so, hopefully suggest a means to achieve my goal please?
your first select in a loop will always return one row, so there now Need to do a loop.
using tst.t in a Loop is not possible.
is that what are you looking for?
declare
x number := 0;
begin
select count(c) into x from t;
if x <= 0
then
dbms_output.put_line( 'a' );
else
dbms_output.put_line( 'b' );
end if;
end;

function not returning a value for no rows returned

I created a function that takes a movie id as input and returns stock information based from the ID. The function mostly works but if I want to retrieve information from a movie that is not in the database(returns no rows) nothing returns. Can't figure out why?
doesn't give me an error when i call an ID that returns no rows so exception handling wouldn't work.
create or replace function stock_info
(p_id IN NUMBER
)
return VARCHAR2
IS
cursor c1 is
select movie_id, movie_title, movie_qty
from mm_movie
where p_id = movie_id;
lv_movie_info VARCHAR2(100);
BEGIN
for i in c1 loop
if p_id = i.movie_id then
lv_movie_info := i.movie_title || ' is available: ' || i.movie_qty || ' on the shelf';
else
lv_movie_info := 'no data found';
end if;
end loop;
return lv_movie_info;
END STOCK_INFO;
/
The reason you don't get anything when there is no data is that the loop doesn't execute. Logically the For expression says "execute the following loop for every row returned in the cursor" but there are no rows in the cursor so it never executes the loop. Further the structure actually indicates you are expecting multiple for a given p_id. If that's not the case you can eliminate the cursor all together. Assuming p_id is the primary key you have either 0 or 1 row so:
create or replace function stock_info (p_id in number)
return text
is
lv_movie_info varchar2(100);
begin
select i.movie_title || ' is available: ' || i.movie_qty || ' on the shelf'
into lv_movie_info
from mm_movie i
where p_id = movie_id;
return lv_movie_info;
exceptions
when no_data_found
then return 'no data found';
end stock_info;
Of course if do expect more that 1 row the cursor is needed, but the IF is not as the were clause guarantees it's true. Still with 0 rows the loop will not be executed so the 'no data found' message needs to go after "End Loop".
Belayer
the cursor statement you used fetches data from the in parameter. i.e., in the cursor select you limiting based on the movie id passed.
on passing a movie id which is not in the data base, the cursor select statement would not fetch any records, and so the flow won't even go inside the for loop.
if you wanted to return no data found - on passing a movie id which is not in the database, two ways to resolve
1. before the loop, have select statement to set a flag to Y or N if exists according and to have your requirement.
2. in if not using for cursor, there is an option to check not found...
sample:
declare
cursor c1 is select * from table_sample; -- empty table
c_rec c1%rowtype;
begin
open c1;
fetch c1 into c_rec;
if c1%notfound then
dbms_output.put_line('not found');
end if;
close c1;
end;
-- output
not found

How can I modify my PL/SQL procedure to go to my exception handling?

I am using SQL developer to write a procedure.
The objective is to get the name of the drainage system from one table and get the count of how much the drainage system name code appears in another table.
My procedure works, but when I enter an incorrect value, it does not go to the exception section. For example, when I input ‘Mexico River’, this name does not exist in the table. So, I want my exception section to realize that this is an incorrect value being entered.
My question is how do I modify my code, so it can detect incorrect values and go to my exception section.
Below is a snippet of my code:
PROCEDURE number_of_rivers --second procedure with 1 parameter
(input_sysName IN TBLDrainage.DRAINAGE_SYS%TYPE)
is
-- Create a cursor
cursor c_river is
select code, drainage_sys
from TBLDRAINAGE
where DRAINAGE_SYS = input_sysName;
v_rivercount Number;
r_variable c_river %rowtype;
Begin
FOR r_variable in c_river
loop
select count (Drainage_sys) into v_rivercount
from TBLRIVER
where DRAINAGE_SYS = r_variable.code;
DBMS_OUTPUT.PUT_LINE (UPPER(input_sysName) || ' has ' || v_rivercount || ' river(s) in the drainage system.');
end loop;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Error: Please enter a valid drainage system name');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Error in finding system');
END ;
The CURSOR..FOR loop has the property of executing zero or more times. It doesn't throw NO_DATA_FOUND.
There are a couple of solutions. One is to include a count inside the loop, and raise an exception afterwards.
l_count := 0;
FOR r_variable in c_river
loop
....
l_count := l_count + 1;
end loop;
if l_count = 0 then
raise NO_DATA_FOUND;
end if;
The other would be to validate the input parameter at the start of your program.
begin
open c_river;
fetch c_river into r_variable;
if c_river%notfound then
raise NO_DATA_FOUND;
else
select count (Drainage_sys)
into v_rivercount
from TBLRIVER
where DRAINAGE_SYS = r_variable.code;
DBMS_OUTPUT.PUT_LINE (UPPER(input_sysName) || ' has ' || v_rivercount || ' river(s) in the drainage system.');
end if;
close c_river;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Error: Please enter a valid drainage system name');
close c_river;
END ;
In this solution I have removed the loop, because I would expect a look-up on drainage system should be unique and return one record. Please re-instate the loop if your data model isn't like that.
I have retained your names for the cursor and its row variables but you should re-name them. They are used for selecting drainage systems not rivers, and their names ought to reflect that. Discipline in naming things is a useful habit to acquire, as misleading variable names will cause confusion in larger chunks of code.
Also, swallowing exceptions like this is very bad:
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Error in finding system');
Oracle has thousands of error messages: it better to do nothing with the error message than to throw it away.

Resources